From bc51f106e9c3b36d53852aea2b73c1aa6c83aafb Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Tue, 27 Aug 2024 20:30:08 +0200 Subject: [PATCH 01/78] Feature/expose log levels as env variable (#3704) * Expose log levels as env variable * Update documentation * Update changelog --- CHANGELOG.md | 1 + README.md | 35 ++++++++++++++++++----------------- apps/api/src/main.ts | 22 ++++++++++++++++++---- 3 files changed, 37 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 30dc3b6e7..9d28fedda 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 - Reworked the portfolio calculator +- Exposed the log levels as an environment variable (`LOG_LEVELS`) - Exposed the maximum of chart data items as an environment variable (`MAX_CHART_ITEMS`) ### Fixed diff --git a/README.md b/README.md index 47316881f..d4353351f 100644 --- a/README.md +++ b/README.md @@ -85,23 +85,24 @@ We provide official container images hosted on [Docker Hub](https://hub.docker.c ### Supported Environment Variables -| Name | Type | Default Value | Description | -| ------------------------ | ------------------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------- | -| `ACCESS_TOKEN_SALT` | `string` | | A random string used as salt for access tokens | -| `API_KEY_COINGECKO_DEMO` | `string` (optional) |   | The _CoinGecko_ Demo API key | -| `API_KEY_COINGECKO_PRO` | `string` (optional) | | The _CoinGecko_ Pro API key | -| `DATABASE_URL` | `string` | | The database connection URL, e.g. `postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:5432/${POSTGRES_DB}?sslmode=prefer` | -| `HOST` | `string` (optional) | `0.0.0.0` | The host where the Ghostfolio application will run on | -| `JWT_SECRET_KEY` | `string` | | A random string used for _JSON Web Tokens_ (JWT) | -| `PORT` | `number` (optional) | `3333` | The port where the Ghostfolio application will run on | -| `POSTGRES_DB` | `string` | | The name of the _PostgreSQL_ database | -| `POSTGRES_PASSWORD` | `string` | | The password of the _PostgreSQL_ database | -| `POSTGRES_USER` | `string` | | The user of the _PostgreSQL_ database | -| `REDIS_DB` | `number` (optional) | `0` | The database index of _Redis_ | -| `REDIS_HOST` | `string` | | The host where _Redis_ is running | -| `REDIS_PASSWORD` | `string` | | The password of _Redis_ | -| `REDIS_PORT` | `number` | | The port where _Redis_ is running | -| `REQUEST_TIMEOUT` | `number` (optional) | `2000` | The timeout of network requests to data providers in milliseconds | +| Name | Type | Default Value | Description | +| ------------------------ | --------------------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| `ACCESS_TOKEN_SALT` | `string` | | A random string used as salt for access tokens | +| `API_KEY_COINGECKO_DEMO` | `string` (optional) |   | The _CoinGecko_ Demo API key | +| `API_KEY_COINGECKO_PRO` | `string` (optional) | | The _CoinGecko_ Pro API key | +| `DATABASE_URL` | `string` | | The database connection URL, e.g. `postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:5432/${POSTGRES_DB}?sslmode=prefer` | +| `HOST` | `string` (optional) | `0.0.0.0` | The host where the Ghostfolio application will run on | +| `JWT_SECRET_KEY` | `string` | | A random string used for _JSON Web Tokens_ (JWT) | +| `LOG_LEVELS` | `string[]` (optional) | | The logging levels for the Ghostfolio application, e.g. `["debug","error","log","warn"]` | +| `PORT` | `number` (optional) | `3333` | The port where the Ghostfolio application will run on | +| `POSTGRES_DB` | `string` | | The name of the _PostgreSQL_ database | +| `POSTGRES_PASSWORD` | `string` | | The password of the _PostgreSQL_ database | +| `POSTGRES_USER` | `string` | | The user of the _PostgreSQL_ database | +| `REDIS_DB` | `number` (optional) | `0` | The database index of _Redis_ | +| `REDIS_HOST` | `string` | | The host where _Redis_ is running | +| `REDIS_PASSWORD` | `string` | | The password of _Redis_ | +| `REDIS_PORT` | `number` | | The port where _Redis_ is running | +| `REQUEST_TIMEOUT` | `number` (optional) | `2000` | The timeout of network requests to data providers in milliseconds | ### Run with Docker Compose diff --git a/apps/api/src/main.ts b/apps/api/src/main.ts index abb27b7cd..9335e8d18 100644 --- a/apps/api/src/main.ts +++ b/apps/api/src/main.ts @@ -1,4 +1,9 @@ -import { Logger, ValidationPipe, VersioningType } from '@nestjs/common'; +import { + Logger, + LogLevel, + ValidationPipe, + VersioningType +} from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { NestFactory } from '@nestjs/core'; import type { NestExpressApplication } from '@nestjs/platform-express'; @@ -12,11 +17,20 @@ import { HtmlTemplateMiddleware } from './middlewares/html-template.middleware'; async function bootstrap() { const configApp = await NestFactory.create(AppModule); const configService = configApp.get(ConfigService); + let customLogLevels: LogLevel[]; + + try { + customLogLevels = JSON.parse( + configService.get('LOG_LEVELS') + ) as LogLevel[]; + } catch {} const app = await NestFactory.create(AppModule, { - logger: environment.production - ? ['error', 'log', 'warn'] - : ['debug', 'error', 'log', 'verbose', 'warn'] + logger: + customLogLevels ?? + (environment.production + ? ['error', 'log', 'warn'] + : ['debug', 'error', 'log', 'verbose', 'warn']) }); app.enableCors(); From 4505441691610621f9e432ce8142b996e2d48186 Mon Sep 17 00:00:00 2001 From: Cygguu <111180580+Cygguu@users.noreply.github.com> Date: Wed, 28 Aug 2024 20:28:11 +0200 Subject: [PATCH 02/78] Feature/improve language localization for polish (#3691) * Improve language localization for Polish * Update changelog --- CHANGELOG.md | 1 + apps/client/src/locales/messages.pl.xlf | 198 ++++++++++++------------ 2 files changed, 100 insertions(+), 99 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d28fedda..cbf940063 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Reworked the portfolio calculator - Exposed the log levels as an environment variable (`LOG_LEVELS`) - Exposed the maximum of chart data items as an environment variable (`MAX_CHART_ITEMS`) +- Improved the language localization for Polish (`pl`) ### Fixed diff --git a/apps/client/src/locales/messages.pl.xlf b/apps/client/src/locales/messages.pl.xlf index 27c9f9dc7..c7e54de73 100644 --- a/apps/client/src/locales/messages.pl.xlf +++ b/apps/client/src/locales/messages.pl.xlf @@ -299,7 +299,7 @@ privacy-policy - privacy-policy + polityka-prywatnosci apps/client/src/app/app.component.ts 65 @@ -315,7 +315,7 @@ register - register + zarejestruj apps/client/src/app/app.component.ts 71 @@ -351,7 +351,7 @@ resources - resources + zasoby apps/client/src/app/app.component.ts 72 @@ -403,7 +403,7 @@ You are using the Live Demo. - You are using the Live Demo. + Korzystasz z wersji demonstracyjnej. apps/client/src/app/app.component.html 12 @@ -455,7 +455,7 @@ Resources - Resources + Zasoby apps/client/src/app/app.component.html 61 @@ -475,7 +475,7 @@ About - About + O programie apps/client/src/app/app.component.html 67 @@ -591,7 +591,7 @@ Features - Features + Funkcje apps/client/src/app/app.component.html 76 @@ -619,7 +619,7 @@ License - License + Licencja apps/client/src/app/app.component.html 85 @@ -715,7 +715,7 @@ The risk of loss in trading can be substantial. It is not advisable to invest money you may need in the short term. - The risk of loss in trading can be substantial. It is not advisable to invest money you may need in the short term. + Ryzyko strat na rynku może być znaczne. Nie jest zalecane inwestowanie pieniędzy, które mogą być potrzebne w krótkim okresie. apps/client/src/app/app.component.html 199 @@ -723,7 +723,7 @@ Alias - Alias + Alias apps/client/src/app/components/access-table/access-table.component.html 4 @@ -743,7 +743,7 @@ Type - Type + Typ apps/client/src/app/components/admin-jobs/admin-jobs.html 31 @@ -771,7 +771,7 @@ Revoke - Revoke + Cofnij apps/client/src/app/components/access-table/access-table.component.html 62 @@ -803,7 +803,7 @@ Equity - Equity + Kapitał własny apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html 56 @@ -811,7 +811,7 @@ Activities - Activities + Aktywności apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html 61 @@ -851,7 +851,7 @@ Platform - Platform + Platforma apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html 65 @@ -867,7 +867,7 @@ Transfer Cash Balance - Transfer Cash Balance + Transfer Salda Gotówkowego apps/client/src/app/components/accounts-table/accounts-table.component.html 10 @@ -879,7 +879,7 @@ Name - Name + Nazwa apps/client/src/app/components/accounts-table/accounts-table.component.html 43 @@ -931,7 +931,7 @@ Total - Total + Suma apps/client/src/app/components/accounts-table/accounts-table.component.html 55 @@ -939,7 +939,7 @@ Currency - Currency + Waluta apps/client/src/app/components/accounts-table/accounts-table.component.html 65 @@ -967,7 +967,7 @@ Value - Value + Wartość apps/client/src/app/components/accounts-table/accounts-table.component.html 171 @@ -1099,7 +1099,7 @@ Do you really want to delete this account? - Do you really want to delete this account? + Czy na pewno chcesz usunąć to konto? apps/client/src/app/components/accounts-table/accounts-table.component.ts 110 @@ -1107,7 +1107,7 @@ Asset Profile - Asset Profile + Profil Aktywów apps/client/src/app/components/admin-jobs/admin-jobs.html 35 @@ -1115,7 +1115,7 @@ Historical Market Data - Historical Market Data + Historyczne Dane Rynkowe apps/client/src/app/components/admin-jobs/admin-jobs.html 37 @@ -1123,7 +1123,7 @@ Symbol - Symbol + Symbol apps/client/src/app/components/admin-jobs/admin-jobs.html 44 @@ -1147,7 +1147,7 @@ Data Source - Data Source + Źródło Danych apps/client/src/app/components/admin-jobs/admin-jobs.html 53 @@ -1167,7 +1167,7 @@ Attempts - Attempts + Próby apps/client/src/app/components/admin-jobs/admin-jobs.html 81 @@ -1175,7 +1175,7 @@ Created - Created + Utworzono apps/client/src/app/components/admin-jobs/admin-jobs.html 90 @@ -1183,7 +1183,7 @@ Finished - Finished + Zakończono apps/client/src/app/components/admin-jobs/admin-jobs.html 99 @@ -1191,7 +1191,7 @@ Status - Status + Status apps/client/src/app/components/admin-jobs/admin-jobs.html 108 @@ -1199,7 +1199,7 @@ Delete Jobs - Delete Jobs + Usuń Zadania apps/client/src/app/components/admin-jobs/admin-jobs.html 149 @@ -1207,7 +1207,7 @@ View Data - View Data + Zobacz Dane apps/client/src/app/components/admin-jobs/admin-jobs.html 164 @@ -1215,7 +1215,7 @@ View Stacktrace - View Stacktrace + Wyświetl Stos Wywołań apps/client/src/app/components/admin-jobs/admin-jobs.html 171 @@ -1223,7 +1223,7 @@ Delete Job - Delete Job + Usuń Zadanie apps/client/src/app/components/admin-jobs/admin-jobs.html 177 @@ -1231,7 +1231,7 @@ Details for - Details for + Szczegóły dla apps/client/src/app/components/admin-market-data-detail/market-data-detail-dialog/market-data-detail-dialog.html 2 @@ -1239,7 +1239,7 @@ Date - Date + Data apps/client/src/app/components/admin-market-data-detail/market-data-detail-dialog/market-data-detail-dialog.html 6 @@ -1271,7 +1271,7 @@ Cancel - Cancel + Anuluj apps/client/src/app/components/admin-market-data-detail/market-data-detail-dialog/market-data-detail-dialog.html 46 @@ -1315,7 +1315,7 @@ Save - Save + Zapisz apps/client/src/app/components/admin-market-data-detail/market-data-detail-dialog/market-data-detail-dialog.html 48 @@ -1351,7 +1351,7 @@ Currencies - Currencies + Waluty apps/client/src/app/components/admin-market-data/admin-market-data.component.ts 85 @@ -1359,7 +1359,7 @@ ETFs without Countries - ETFs without Countries + ETF-y bez Krajów apps/client/src/app/components/admin-market-data/admin-market-data.component.ts 90 @@ -1367,7 +1367,7 @@ ETFs without Sectors - ETFs without Sectors + ETF-y bez Sektorów apps/client/src/app/components/admin-market-data/admin-market-data.component.ts 95 @@ -1375,7 +1375,7 @@ Do you really want to delete this asset profile? - Do you really want to delete this asset profile? + Czy na pewno chcesz usunąć ten profil aktywów? apps/client/src/app/components/admin-market-data/admin-market-data.service.ts 33 @@ -1383,7 +1383,7 @@ Filter by... - Filter by... + Filtruj według... apps/client/src/app/components/admin-market-data/admin-market-data.component.ts 328 @@ -1391,7 +1391,7 @@ Asset Class - Asset Class + Klasa Aktywów apps/client/src/app/components/admin-market-data/admin-market-data.html 86 @@ -1415,7 +1415,7 @@ Asset Sub Class - Asset Sub Class + Podklasa Aktywów apps/client/src/app/components/admin-market-data/admin-market-data.html 95 @@ -1439,7 +1439,7 @@ First Activity - First Activity + Pierwsza Aktywność apps/client/src/app/components/admin-market-data/admin-market-data.html 104 @@ -1459,7 +1459,7 @@ Activities Count - Activities Count + Liczba Aktywności apps/client/src/app/components/admin-market-data/admin-market-data.html 113 @@ -1467,7 +1467,7 @@ Historical Data - Historical Data + Dane Historyczne apps/client/src/app/components/admin-market-data/admin-market-data.html 122 @@ -1479,7 +1479,7 @@ Sectors Count - Sectors Count + Liczba Sektorów apps/client/src/app/components/admin-market-data/admin-market-data.html 131 @@ -1487,7 +1487,7 @@ Countries Count - Countries Count + Liczba Krajów apps/client/src/app/components/admin-market-data/admin-market-data.html 140 @@ -1495,7 +1495,7 @@ Gather Recent Data - Gather Recent Data + Zbierz Najnowsze Dane apps/client/src/app/components/admin-market-data/admin-market-data.html 177 @@ -1503,7 +1503,7 @@ Gather All Data - Gather All Data + Zbierz Wszystkie Dane apps/client/src/app/components/admin-market-data/admin-market-data.html 180 @@ -1511,7 +1511,7 @@ Gather Profile Data - Gather Profile Data + Zbierz Dane Profilu apps/client/src/app/components/admin-market-data/admin-market-data.html 183 @@ -1531,7 +1531,7 @@ Refresh - Refresh + Odśwież apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 22 @@ -1539,7 +1539,7 @@ Gather Historical Data - Gather Historical Data + Zbierz Dane Historyczne apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 32 @@ -1547,7 +1547,7 @@ Import - Import + Importuj apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 110 @@ -1563,7 +1563,7 @@ Sector - Sector + Sektor apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 187 @@ -1575,7 +1575,7 @@ Country - Country + Kraj apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 198 @@ -1591,7 +1591,7 @@ Sectors - Sectors + Sektory apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 204 @@ -1611,7 +1611,7 @@ Countries - Countries + Kraje apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 214 @@ -1627,7 +1627,7 @@ Benchmark - Benchmark + Benchmark apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 286 @@ -1635,7 +1635,7 @@ Symbol Mapping - Symbol Mapping + Mapowanie Symboli apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 292 @@ -1643,7 +1643,7 @@ Scraper Configuration - Scraper Configuration + Konfiguracja Scrapera apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 304 @@ -1651,7 +1651,7 @@ Note - Note + Notatka apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 365 @@ -1667,7 +1667,7 @@ Add Asset Profile - Add Asset Profile + Dodaj Profil Aktywa apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html 7 @@ -1675,7 +1675,7 @@ Search - Search + Szukaj apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html 16 @@ -1683,7 +1683,7 @@ Add Manually - Add Manually + Dodaj Ręcznie apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html 19 @@ -1691,7 +1691,7 @@ Name, symbol or ISIN - Name, symbol or ISIN + Nazwa, symbol lub ISIN apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html 26 @@ -1703,7 +1703,7 @@ Please add a currency: - Please add a currency: + Proszę dodać walutę: apps/client/src/app/components/admin-overview/admin-overview.component.ts 125 @@ -1711,7 +1711,7 @@ Do you really want to delete this coupon? - Do you really want to delete this coupon? + Czy naprawdę chcesz usunąć ten kupon? apps/client/src/app/components/admin-overview/admin-overview.component.ts 152 @@ -1719,7 +1719,7 @@ Do you really want to delete this currency? - Do you really want to delete this currency? + Czy naprawdę chcesz usunąć tę walutę? apps/client/src/app/components/admin-overview/admin-overview.component.ts 165 @@ -1727,7 +1727,7 @@ Do you really want to delete this system message? - Do you really want to delete this system message? + Czy naprawdę chcesz usunąć tę wiadomość systemową? apps/client/src/app/components/admin-overview/admin-overview.component.ts 178 @@ -1735,7 +1735,7 @@ Do you really want to flush the cache? - Do you really want to flush the cache? + Czy naprawdę chcesz wyczyścić pamięć podręczną? apps/client/src/app/components/admin-overview/admin-overview.component.ts 202 @@ -1743,7 +1743,7 @@ Please set your system message: - Please set your system message: + Proszę ustawić swoją wiadomość systemową: apps/client/src/app/components/admin-overview/admin-overview.component.ts 222 @@ -1751,7 +1751,7 @@ Version - Version + Wersja apps/client/src/app/components/admin-overview/admin-overview.html 7 @@ -1759,7 +1759,7 @@ User Count - User Count + Liczba Użytkowników apps/client/src/app/components/admin-overview/admin-overview.html 13 @@ -1767,7 +1767,7 @@ Activity Count - Activity Count + Liczba Aktywności apps/client/src/app/components/admin-overview/admin-overview.html 19 @@ -1775,7 +1775,7 @@ per User - per User + na Użytkownika apps/client/src/app/components/admin-overview/admin-overview.html 28 @@ -1783,7 +1783,7 @@ Exchange Rates - Exchange Rates + Kursy Walut apps/client/src/app/components/admin-overview/admin-overview.html 34 @@ -1791,7 +1791,7 @@ Add Currency - Add Currency + Dodaj Walutę apps/client/src/app/components/admin-overview/admin-overview.html 104 @@ -1799,7 +1799,7 @@ User Signup - User Signup + Rejestracja Użytkownika apps/client/src/app/components/admin-overview/admin-overview.html 110 @@ -1807,7 +1807,7 @@ Read-only Mode - Read-only Mode + Tryb Tylko do Odczytu apps/client/src/app/components/admin-overview/admin-overview.html 124 @@ -1815,7 +1815,7 @@ System Message - System Message + Wiadomość Systemowa apps/client/src/app/components/admin-overview/admin-overview.html 148 @@ -1823,7 +1823,7 @@ Set Message - Set Message + Ustaw Wiadomość apps/client/src/app/components/admin-overview/admin-overview.html 170 @@ -1831,7 +1831,7 @@ Coupons - Coupons + Kupony apps/client/src/app/components/admin-overview/admin-overview.html 178 @@ -1839,7 +1839,7 @@ Add - Add + Dodaj apps/client/src/app/components/admin-overview/admin-overview.html 238 @@ -1851,7 +1851,7 @@ Housekeeping - Housekeeping + Konserwacja apps/client/src/app/components/admin-overview/admin-overview.html 246 @@ -1859,7 +1859,7 @@ Flush Cache - Flush Cache + Wyczyszczenie pamięci podręcznej apps/client/src/app/components/admin-overview/admin-overview.html 250 @@ -1867,7 +1867,7 @@ Add Platform - Add Platform + Dodaj Platformę apps/client/src/app/components/admin-platform/admin-platform.component.html 11 @@ -1875,7 +1875,7 @@ Url - Url + Url apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 352 @@ -1891,7 +1891,7 @@ Accounts - Accounts + Konta apps/client/src/app/components/admin-platform/admin-platform.component.html 65 @@ -1923,7 +1923,7 @@ Do you really want to delete this platform? - Do you really want to delete this platform? + Czy naprawdę chcesz usunąć tę platformę? apps/client/src/app/components/admin-platform/admin-platform.component.ts 86 @@ -1931,7 +1931,7 @@ Update platform - Update platform + Aktualizuj platformę apps/client/src/app/components/admin-platform/create-or-update-platform-dialog/create-or-update-platform-dialog.html 8 @@ -1939,7 +1939,7 @@ Add platform - Add platform + Dodaj platformę apps/client/src/app/components/admin-platform/create-or-update-platform-dialog/create-or-update-platform-dialog.html 10 @@ -1947,7 +1947,7 @@ Platforms - Platforms + Platformy apps/client/src/app/components/admin-settings/admin-settings.component.html 4 @@ -1955,7 +1955,7 @@ Tags - Tags + Tagi apps/client/src/app/components/admin-settings/admin-settings.component.html 10 @@ -1979,7 +1979,7 @@ Add Tag - Add Tag + Dodaj Tag apps/client/src/app/components/admin-tag/admin-tag.component.html 11 @@ -1987,7 +1987,7 @@ Do you really want to delete this tag? - Do you really want to delete this tag? + Czy naprawdę chcesz usunąć ten tag? apps/client/src/app/components/admin-tag/admin-tag.component.ts 86 @@ -1995,7 +1995,7 @@ Update tag - Update tag + Aktualizuj tag apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.html 8 @@ -2003,7 +2003,7 @@ Add tag - Add tag + Dodaj tag apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.html 10 From c4a28c6bff7e855603e146a4a6542245bbb67081 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Wed, 28 Aug 2024 20:28:36 +0200 Subject: [PATCH 03/78] Feature/set up a performance logging service (#3703) * Setup performance logging service * Update changelog --- CHANGELOG.md | 4 + .../account-balance.service.ts | 2 + apps/api/src/app/order/order.service.ts | 2 + .../calculator/portfolio-calculator.ts | 12 +-- .../src/app/portfolio/current-rate.service.ts | 2 + .../src/app/portfolio/portfolio.controller.ts | 2 + .../api/src/app/portfolio/portfolio.module.ts | 2 + .../performance-logging.interceptor.ts | 80 +++++++++++++++++++ .../performance-logging.module.ts | 10 +++ .../performance-logging.service.ts | 21 +++++ .../coingecko/coingecko.service.ts | 6 +- .../eod-historical-data.service.ts | 6 +- .../financial-modeling-prep.service.ts | 6 +- .../exchange-rate-data.service.ts | 2 + 14 files changed, 140 insertions(+), 17 deletions(-) create mode 100644 apps/api/src/interceptors/performance-logging/performance-logging.interceptor.ts create mode 100644 apps/api/src/interceptors/performance-logging/performance-logging.module.ts create mode 100644 apps/api/src/interceptors/performance-logging/performance-logging.service.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index cbf940063..44d7f7bf6 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 ## 2.106.0-beta.2 - 2024-08-26 +### Added + +- Set up a performance logging service + ### Changed - Reworked the portfolio calculator diff --git a/apps/api/src/app/account-balance/account-balance.service.ts b/apps/api/src/app/account-balance/account-balance.service.ts index 65393cec8..244b4c684 100644 --- a/apps/api/src/app/account-balance/account-balance.service.ts +++ b/apps/api/src/app/account-balance/account-balance.service.ts @@ -1,4 +1,5 @@ import { PortfolioChangedEvent } from '@ghostfolio/api/events/portfolio-changed.event'; +import { LogPerformance } from '@ghostfolio/api/interceptors/performance-logging/performance-logging.interceptor'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; import { resetHours } from '@ghostfolio/common/helper'; @@ -90,6 +91,7 @@ export class AccountBalanceService { return accountBalance; } + @LogPerformance public async getAccountBalances({ filters, user, diff --git a/apps/api/src/app/order/order.service.ts b/apps/api/src/app/order/order.service.ts index f66380e1f..d9ff68d61 100644 --- a/apps/api/src/app/order/order.service.ts +++ b/apps/api/src/app/order/order.service.ts @@ -1,5 +1,6 @@ import { AccountService } from '@ghostfolio/api/app/account/account.service'; import { PortfolioChangedEvent } from '@ghostfolio/api/events/portfolio-changed.event'; +import { LogPerformance } from '@ghostfolio/api/interceptors/performance-logging/performance-logging.interceptor'; import { DataGatheringService } from '@ghostfolio/api/services/data-gathering/data-gathering.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; @@ -519,6 +520,7 @@ export class OrderService { return { activities, count }; } + @LogPerformance public async getOrdersForPortfolioCalculator({ filters, userCurrency, diff --git a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts index 99f71ef0e..0fcb8b9d6 100644 --- a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts @@ -5,6 +5,7 @@ import { TransactionPointSymbol } from '@ghostfolio/api/app/portfolio/interfaces import { TransactionPoint } from '@ghostfolio/api/app/portfolio/interfaces/transaction-point.interface'; import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service'; import { getFactor } from '@ghostfolio/api/helper/portfolio.helper'; +import { LogPerformance } from '@ghostfolio/api/interceptors/performance-logging/performance-logging.interceptor'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { IDataGatheringItem } from '@ghostfolio/api/services/interfaces/interfaces'; @@ -148,6 +149,7 @@ export abstract class PortfolioCalculator { positions: TimelinePosition[] ): PortfolioSnapshot; + @LogPerformance private async computeSnapshot(): Promise { const lastTransactionPoint = last(this.transactionPoints); @@ -861,6 +863,7 @@ export abstract class PortfolioCalculator { return chartDateMap; } + @LogPerformance private computeTransactionPoints() { this.transactionPoints = []; const symbols: { [symbol: string]: TransactionPointSymbol } = {}; @@ -999,6 +1002,7 @@ export abstract class PortfolioCalculator { } } + @LogPerformance private async initialize() { const startTimeTotal = performance.now(); @@ -1033,14 +1037,6 @@ export abstract class PortfolioCalculator { JSON.stringify(this.snapshot), this.configurationService.get('CACHE_QUOTES_TTL') ); - - Logger.debug( - `Computed portfolio snapshot in ${( - (performance.now() - startTimeTotal) / - 1000 - ).toFixed(3)} seconds`, - 'PortfolioCalculator' - ); } } } diff --git a/apps/api/src/app/portfolio/current-rate.service.ts b/apps/api/src/app/portfolio/current-rate.service.ts index 24119162d..cd1994826 100644 --- a/apps/api/src/app/portfolio/current-rate.service.ts +++ b/apps/api/src/app/portfolio/current-rate.service.ts @@ -1,4 +1,5 @@ import { OrderService } from '@ghostfolio/api/app/order/order.service'; +import { LogPerformance } from '@ghostfolio/api/interceptors/performance-logging/performance-logging.interceptor'; import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service'; import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service'; import { resetHours } from '@ghostfolio/common/helper'; @@ -27,6 +28,7 @@ export class CurrentRateService { @Inject(REQUEST) private readonly request: RequestWithUser ) {} + @LogPerformance // TODO: Pass user instead of using this.request.user public async getValues({ dataGatheringItems, diff --git a/apps/api/src/app/portfolio/portfolio.controller.ts b/apps/api/src/app/portfolio/portfolio.controller.ts index 7ce0b0847..036e48901 100644 --- a/apps/api/src/app/portfolio/portfolio.controller.ts +++ b/apps/api/src/app/portfolio/portfolio.controller.ts @@ -7,6 +7,7 @@ import { hasNotDefinedValuesInObject, nullifyValuesInObject } from '@ghostfolio/api/helper/object.helper'; +import { PerformanceLoggingInterceptor } from '@ghostfolio/api/interceptors/performance-logging/performance-logging.interceptor'; import { RedactValuesInResponseInterceptor } from '@ghostfolio/api/interceptors/redact-values-in-response/redact-values-in-response.interceptor'; import { TransformDataSourceInRequestInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.interceptor'; import { TransformDataSourceInResponseInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor'; @@ -390,6 +391,7 @@ export class PortfolioController { @Get('performance') @UseGuards(AuthGuard('jwt'), HasPermissionGuard) + @UseInterceptors(PerformanceLoggingInterceptor) @UseInterceptors(TransformDataSourceInResponseInterceptor) @Version('2') public async getPerformanceV2( diff --git a/apps/api/src/app/portfolio/portfolio.module.ts b/apps/api/src/app/portfolio/portfolio.module.ts index 7f1f375b1..ad81e9e15 100644 --- a/apps/api/src/app/portfolio/portfolio.module.ts +++ b/apps/api/src/app/portfolio/portfolio.module.ts @@ -4,6 +4,7 @@ import { AccountService } from '@ghostfolio/api/app/account/account.service'; import { OrderModule } from '@ghostfolio/api/app/order/order.module'; import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.module'; import { UserModule } from '@ghostfolio/api/app/user/user.module'; +import { PerformanceLoggingModule } from '@ghostfolio/api/interceptors/performance-logging/performance-logging.module'; import { RedactValuesInResponseModule } from '@ghostfolio/api/interceptors/redact-values-in-response/redact-values-in-response.module'; import { TransformDataSourceInRequestModule } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.module'; import { TransformDataSourceInResponseModule } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.module'; @@ -38,6 +39,7 @@ import { RulesService } from './rules.service'; ImpersonationModule, MarketDataModule, OrderModule, + PerformanceLoggingModule, PrismaModule, RedactValuesInResponseModule, RedisCacheModule, diff --git a/apps/api/src/interceptors/performance-logging/performance-logging.interceptor.ts b/apps/api/src/interceptors/performance-logging/performance-logging.interceptor.ts new file mode 100644 index 000000000..d863f0ec3 --- /dev/null +++ b/apps/api/src/interceptors/performance-logging/performance-logging.interceptor.ts @@ -0,0 +1,80 @@ +import { + Injectable, + NestInterceptor, + ExecutionContext, + CallHandler +} from '@nestjs/common'; +import { Observable } from 'rxjs'; +import { tap } from 'rxjs/operators'; + +import { PerformanceLoggingService } from './performance-logging.service'; + +@Injectable() +export class PerformanceLoggingInterceptor implements NestInterceptor { + public constructor( + private readonly performanceLoggingService: PerformanceLoggingService + ) {} + + public intercept( + context: ExecutionContext, + next: CallHandler + ): Observable { + const startTime = performance.now(); + + const className = context.getClass().name; + const methodName = context.getHandler().name; + + return next.handle().pipe( + tap(() => { + return this.performanceLoggingService.logPerformance({ + className, + methodName, + startTime + }); + }) + ); + } +} + +export function LogPerformance( + target: any, + propertyKey: string, + descriptor: PropertyDescriptor +) { + const originalMethod = descriptor.value; + + descriptor.value = async function (...args: any[]) { + const startTime = performance.now(); + const performanceLoggingService = new PerformanceLoggingService(); + + const result = originalMethod.apply(this, args); + + if (result instanceof Promise) { + // Handle async method + return result + .then((res: any) => { + performanceLoggingService.logPerformance({ + startTime, + className: target.constructor.name, + methodName: propertyKey + }); + + return res; + }) + .catch((error: any) => { + throw error; + }); + } else { + // Handle sync method + performanceLoggingService.logPerformance({ + startTime, + className: target.constructor.name, + methodName: propertyKey + }); + + return result; + } + }; + + return descriptor; +} diff --git a/apps/api/src/interceptors/performance-logging/performance-logging.module.ts b/apps/api/src/interceptors/performance-logging/performance-logging.module.ts new file mode 100644 index 000000000..a26b381e5 --- /dev/null +++ b/apps/api/src/interceptors/performance-logging/performance-logging.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; + +import { PerformanceLoggingInterceptor } from './performance-logging.interceptor'; +import { PerformanceLoggingService } from './performance-logging.service'; + +@Module({ + exports: [PerformanceLoggingInterceptor, PerformanceLoggingService], + providers: [PerformanceLoggingInterceptor, PerformanceLoggingService] +}) +export class PerformanceLoggingModule {} diff --git a/apps/api/src/interceptors/performance-logging/performance-logging.service.ts b/apps/api/src/interceptors/performance-logging/performance-logging.service.ts new file mode 100644 index 000000000..1b1faf8e0 --- /dev/null +++ b/apps/api/src/interceptors/performance-logging/performance-logging.service.ts @@ -0,0 +1,21 @@ +import { Injectable, Logger } from '@nestjs/common'; + +@Injectable() +export class PerformanceLoggingService { + public logPerformance({ + className, + methodName, + startTime + }: { + className: string; + methodName: string; + startTime: number; + }) { + const endTime = performance.now(); + + Logger.debug( + `Completed execution of ${methodName}() in ${((endTime - startTime) / 1000).toFixed(3)} seconds`, + className + ); + } +} diff --git a/apps/api/src/services/data-provider/coingecko/coingecko.service.ts b/apps/api/src/services/data-provider/coingecko/coingecko.service.ts index d673dd7aa..067a6fbf9 100644 --- a/apps/api/src/services/data-provider/coingecko/coingecko.service.ts +++ b/apps/api/src/services/data-provider/coingecko/coingecko.service.ts @@ -206,9 +206,9 @@ export class CoinGeckoService implements DataProviderInterface { let message = error; if (error?.code === 'ABORT_ERR') { - message = `RequestError: The operation to get the quotes was aborted because the request to the data provider took more than ${this.configurationService.get( - 'REQUEST_TIMEOUT' - )}ms`; + message = `RequestError: The operation to get the quotes was aborted because the request to the data provider took more than ${( + this.configurationService.get('REQUEST_TIMEOUT') / 1000 + ).toFixed(3)} seconds`; } Logger.error(message, 'CoinGeckoService'); diff --git a/apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts b/apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts index 1fe9e0ad1..cf2fd42de 100644 --- a/apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts +++ b/apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts @@ -290,9 +290,9 @@ export class EodHistoricalDataService implements DataProviderInterface { let message = error; if (error?.code === 'ABORT_ERR') { - message = `RequestError: The operation to get the quotes was aborted because the request to the data provider took more than ${this.configurationService.get( - 'REQUEST_TIMEOUT' - )}ms`; + message = `RequestError: The operation to get the quotes was aborted because the request to the data provider took more than ${( + this.configurationService.get('REQUEST_TIMEOUT') / 1000 + ).toFixed(3)} seconds`; } Logger.error(message, 'EodHistoricalDataService'); 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 2faaf8db8..cf9c5ef9b 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 @@ -154,9 +154,9 @@ export class FinancialModelingPrepService implements DataProviderInterface { let message = error; if (error?.code === 'ABORT_ERR') { - message = `RequestError: The operation to get the quotes was aborted because the request to the data provider took more than ${this.configurationService.get( - 'REQUEST_TIMEOUT' - )}ms`; + message = `RequestError: The operation to get the quotes was aborted because the request to the data provider took more than ${( + this.configurationService.get('REQUEST_TIMEOUT') / 1000 + ).toFixed(3)} seconds`; } Logger.error(message, 'FinancialModelingPrepService'); diff --git a/apps/api/src/services/exchange-rate-data/exchange-rate-data.service.ts b/apps/api/src/services/exchange-rate-data/exchange-rate-data.service.ts index 1f08034cd..31b2f885c 100644 --- a/apps/api/src/services/exchange-rate-data/exchange-rate-data.service.ts +++ b/apps/api/src/services/exchange-rate-data/exchange-rate-data.service.ts @@ -1,3 +1,4 @@ +import { LogPerformance } from '@ghostfolio/api/interceptors/performance-logging/performance-logging.interceptor'; import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service'; import { IDataGatheringItem } from '@ghostfolio/api/services/interfaces/interfaces'; import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service'; @@ -46,6 +47,7 @@ export class ExchangeRateDataService { return this.currencyPairs; } + @LogPerformance public async getExchangeRatesByCurrency({ currencies, endDate = new Date(), From 208e5c8adb55b08160365a63f20387bd51da3c4d Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Wed, 28 Aug 2024 20:29:59 +0200 Subject: [PATCH 04/78] Release 2.106.0-beta.3 (#3706) --- CHANGELOG.md | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 44d7f7bf6..33705879f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## 2.106.0-beta.2 - 2024-08-26 +## 2.106.0-beta.3 - 2024-08-28 ### Added diff --git a/package.json b/package.json index dff6da5ce..ef43a39a2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "2.106.0-beta.2", + "version": "2.106.0-beta.3", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "repository": "https://github.com/ghostfolio/ghostfolio", From 7a695f34f2a263b16580e11509302074f3d4ffbe Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Thu, 29 Aug 2024 16:13:46 +0200 Subject: [PATCH 05/78] Feature/add docker pulls shield to README.md (#3705) Add Docker Pulls shield --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d4353351f..365a473ee 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,8 @@ [**Blog**](https://ghostfol.io/en/blog) | [**Slack**](https://join.slack.com/t/ghostfolio/shared_invite/zt-vsaan64h-F_I0fEo5M0P88lP9ibCxFg) | [**X**](https://x.com/ghostfolio_) [![Shield: Buy me a coffee](https://img.shields.io/badge/Buy%20me%20a%20coffee-Support-yellow?logo=buymeacoffee)](https://www.buymeacoffee.com/ghostfolio) -[![Shield: Contributions Welcome](https://img.shields.io/badge/Contributions-Welcome-orange.svg)](#contributing) -[![Shield: License: AGPL v3](https://img.shields.io/badge/License-AGPL%20v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0) +[![Shield: Contributions Welcome](https://img.shields.io/badge/Contributions-Welcome-limegreen.svg)](#contributing) [![Shield: Docker Pulls](https://img.shields.io/docker/pulls/ghostfolio/ghostfolio?label=Docker%20Pulls)](https://hub.docker.com/r/ghostfolio/ghostfolio) +[![Shield: License: AGPL v3](https://img.shields.io/badge/License-AGPL%20v3-orange.svg)](https://www.gnu.org/licenses/agpl-3.0) From b794c4dcc8b16f4c0287879f41055ff4c7f08338 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Fri, 30 Aug 2024 11:54:23 +0200 Subject: [PATCH 06/78] Feature/add todo for emergency fund positions value calculation (#3684) * Add todo --- apps/api/src/app/portfolio/portfolio.service.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index 4e5ae2bb6..01dd55112 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -1394,6 +1394,8 @@ export class PortfolioService { }: { holdings: PortfolioDetails['holdings']; }) { + // TODO: Use current value of activities instead of holdings + // tagged with EMERGENCY_FUND_TAG_ID const emergencyFundHoldings = Object.values(holdings).filter(({ tags }) => { return ( tags?.some(({ id }) => { From 267023f2c9b3c09569b65ca1a3d879f51ff2b792 Mon Sep 17 00:00:00 2001 From: Paulina <71526180+paulinek13@users.noreply.github.com> Date: Sat, 31 Aug 2024 10:46:24 +0200 Subject: [PATCH 07/78] Feature/improve language localization for polish (#3713) * Improve language localization for Polish --- apps/client/src/locales/messages.pl.xlf | 432 ++++++++++++------------ 1 file changed, 216 insertions(+), 216 deletions(-) diff --git a/apps/client/src/locales/messages.pl.xlf b/apps/client/src/locales/messages.pl.xlf index c7e54de73..52dfdfba2 100644 --- a/apps/client/src/locales/messages.pl.xlf +++ b/apps/client/src/locales/messages.pl.xlf @@ -2011,7 +2011,7 @@ Do you really want to delete this user? - Do you really want to delete this user? + Czy na pewno chcesz usunąć tego użytkownika? apps/client/src/app/components/admin-users/admin-users.component.ts 125 @@ -2019,7 +2019,7 @@ User - User + Użytkownik apps/client/src/app/components/admin-users/admin-users.html 29 @@ -2027,7 +2027,7 @@ Registration - Registration + Rejestracja apps/client/src/app/components/admin-users/admin-users.html 97 @@ -2035,7 +2035,7 @@ Engagement per Day - Engagement per Day + Zaangażowanie na Dzień apps/client/src/app/components/admin-users/admin-users.html 157 @@ -2043,7 +2043,7 @@ Last Request - Last Request + Ostatnie Żądanie apps/client/src/app/components/admin-users/admin-users.html 181 @@ -2051,7 +2051,7 @@ Impersonate User - Impersonate User + Wciel się w Użytkownika apps/client/src/app/components/admin-users/admin-users.html 218 @@ -2059,7 +2059,7 @@ Delete User - Delete User + Usuń Użytkownika apps/client/src/app/components/admin-users/admin-users.html 229 @@ -2067,7 +2067,7 @@ Performance - Performance + Wydajność apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html 6 @@ -2083,7 +2083,7 @@ Compare with... - Compare with... + Porównaj z... apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html 18 @@ -2091,7 +2091,7 @@ Manage Benchmarks - Manage Benchmarks + Zarządzanie Benchmarkami apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html 35 @@ -2115,7 +2115,7 @@ Benchmark - Benchmark + Poziom Odniesienia (Benchmark) apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts 128 @@ -2123,7 +2123,7 @@ Current Market Mood - Current Market Mood + Obecny Nastrój Rynkowy apps/client/src/app/components/fear-and-greed-index/fear-and-greed-index.component.html 12 @@ -2131,7 +2131,7 @@ Overview - Overview + Przegląd apps/client/src/app/components/header/header.component.html 28 @@ -2143,7 +2143,7 @@ Portfolio - Portfolio + Portfel apps/client/src/app/components/header/header.component.html 41 @@ -2155,7 +2155,7 @@ Admin Control - Admin Control + Nadzór Administratora apps/client/src/app/components/header/header.component.html 68 @@ -2167,7 +2167,7 @@ Me - Me + Ja apps/client/src/app/components/header/header.component.html 203 @@ -2175,7 +2175,7 @@ User - User + Użytkownik apps/client/src/app/components/header/header.component.html 221 @@ -2183,7 +2183,7 @@ My Ghostfolio - My Ghostfolio + Moje Ghostfolio apps/client/src/app/components/header/header.component.html 262 @@ -2191,7 +2191,7 @@ About Ghostfolio - About Ghostfolio + O Ghostfolio apps/client/src/app/components/header/header.component.html 303 @@ -2203,7 +2203,7 @@ Sign in - Sign in + Zaloguj się apps/client/src/app/components/header/header.component.html 394 @@ -2215,7 +2215,7 @@ Get started - Get started + Rozpocznij apps/client/src/app/components/header/header.component.html 404 @@ -2223,7 +2223,7 @@ Sign in - Sign in + Zaloguj się apps/client/src/app/app-routing.module.ts 141 @@ -2247,7 +2247,7 @@ Manage Activities - Manage Activities + Zarządzaj Aktywnościami apps/client/src/app/components/home-holdings/home-holdings.html 61 @@ -2255,7 +2255,7 @@ Fear - Fear + Zagrożenie apps/client/src/app/components/home-market/home-market.component.ts 27 @@ -2267,7 +2267,7 @@ Greed - Greed + Zachłanność apps/client/src/app/components/home-market/home-market.component.ts 28 @@ -2279,7 +2279,7 @@ Last Days - Last Days + Ostatnie Dni apps/client/src/app/components/home-market/home-market.html 7 @@ -2359,7 +2359,7 @@ Add activity - Add activity + Dodaj działalność apps/client/src/app/components/home-overview/home-overview.html 52 @@ -2371,7 +2371,7 @@ Summary - Summary + Podsumowanie apps/client/src/app/components/home-summary/home-summary.html 2 @@ -2379,7 +2379,7 @@ Total Amount - Total Amount + Całkowita Kwota apps/client/src/app/components/investment-chart/investment-chart.component.ts 141 @@ -2387,7 +2387,7 @@ Savings Rate - Savings Rate + Stopa Oszczędności apps/client/src/app/components/investment-chart/investment-chart.component.ts 213 @@ -2395,7 +2395,7 @@ Security Token - Security Token + Token Bezpieczeństwa apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html 11 @@ -2411,7 +2411,7 @@ or - or + lub apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html 31 @@ -2439,7 +2439,7 @@ Sign in with Internet Identity - Sign in with Internet Identity + Zaloguj się przy użyciu Tożsamości Internetowej (Internet Identity) apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html 42 @@ -2447,7 +2447,7 @@ Sign in with Google - Sign in with Google + Zaloguj się przez Google apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html 52 @@ -2455,7 +2455,7 @@ Stay signed in - Stay signed in + Pozostań zalogowany apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html 61 @@ -2463,7 +2463,7 @@ Time in Market - Time in Market + Czas na Rynku apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html 3 @@ -2471,7 +2471,7 @@ Buy - Buy + Kupno apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html 31 @@ -2479,7 +2479,7 @@ Sell - Sell + Sprzedaż apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html 43 @@ -2487,7 +2487,7 @@ Investment - Investment + Inwestycja apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html 168 @@ -2499,7 +2499,7 @@ Absolute Gross Performance - Absolute Gross Performance + Bezwzględne Osiągi Brutto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html 70 @@ -2507,7 +2507,7 @@ Gross Performance - Gross Performance + Osiągi Brutto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html 85 @@ -2515,7 +2515,7 @@ Fees - Fees + Opłaty apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html 203 @@ -2531,7 +2531,7 @@ Absolute Net Performance - Absolute Net Performance + Bezwzględne Osiągi Netto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html 126 @@ -2539,7 +2539,7 @@ Net Performance - Net Performance + Osiągi Netto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html 141 @@ -2547,7 +2547,7 @@ Total Assets - Total Assets + Suma Aktywów apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html 167 @@ -2555,7 +2555,7 @@ Valuables - Valuables + Kosztowności apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html 180 @@ -2563,7 +2563,7 @@ Emergency Fund - Emergency Fund + Fundusz Rezerwowy apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html 192 @@ -2579,7 +2579,7 @@ Cash - Cash + Gotówka apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html 226 @@ -2587,7 +2587,7 @@ Assets - Assets + Aktywa apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html 239 @@ -2595,7 +2595,7 @@ Buying Power - Buying Power + Siła Nabywcza apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html 252 @@ -2603,7 +2603,7 @@ Excluded from Analysis - Excluded from Analysis + Wykluczone z Analizy apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html 264 @@ -2611,7 +2611,7 @@ Liabilities - Liabilities + Pasywa (Zobowiązania Finansowe) apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html 279 @@ -2623,7 +2623,7 @@ Net Worth - Net Worth + Wartość Netto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html 297 @@ -2631,7 +2631,7 @@ Annualized Performance - Annualized Performance + Osiągi w Ujęciu Rocznym apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html 309 @@ -2639,7 +2639,7 @@ Interest - Interest + Odsetki apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html 331 @@ -2647,7 +2647,7 @@ Dividend - Dividend + Dywidenda apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html 181 @@ -2671,7 +2671,7 @@ Please enter the amount of your emergency fund: - Please enter the amount of your emergency fund: + Proszę wprowadzić wysokość funduszu rezerwowego: apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts 58 @@ -2679,7 +2679,7 @@ Change - Change + Zmień apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html 65 @@ -2691,7 +2691,7 @@ Average Unit Price - Average Unit Price + Średnia Cena Jednostkowa apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html 103 @@ -2699,7 +2699,7 @@ Minimum Price - Minimum Price + Cena Minimalna apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html 130 @@ -2707,7 +2707,7 @@ Maximum Price - Maximum Price + Cena Maksymalna apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html 146 @@ -2715,7 +2715,7 @@ Quantity - Quantity + Ilość apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html 156 @@ -2731,7 +2731,7 @@ Report Data Glitch - Report Data Glitch + Zgłoś Błąd Danych apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html 448 @@ -3147,7 +3147,7 @@ Distraction-free experience for turbulent times - Distraction-free experience for turbulent times + Doświadczenie bez zakłóceń w niespokojnych czasach apps/client/src/app/components/user-account-settings/user-account-settings.html 174 @@ -3163,7 +3163,7 @@ Sign in with fingerprint - Zaloguj się za pomocą linii papilarnych + Logowanie za pomocą linii papilarnych apps/client/src/app/components/user-account-settings/user-account-settings.html 191 @@ -3179,7 +3179,7 @@ Sneak peek at upcoming functionality - Włącz podgląd nadchodzących funkcji + Podgląd nadchodzących funkcjonalności apps/client/src/app/components/user-account-settings/user-account-settings.html 208 @@ -5047,7 +5047,7 @@ Open Source Alternative to - Open Source Alternative to + Alternatywa Open Source dla apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page-routing.module.ts 27 @@ -5055,7 +5055,7 @@ Discover Open Source Alternatives for Personal Finance Tools - Discover Open Source Alternatives for Personal Finance Tools + Odkryj alternatywy Open Source dla Narzędzi Finansów Osobistych apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.html 4 @@ -5063,7 +5063,7 @@ This overview page features a curated collection of personal finance tools compared to the open source alternative Ghostfolio. If you value transparency, data privacy, and community collaboration, Ghostfolio provides an excellent opportunity to take control of your financial management. - This overview page features a curated collection of personal finance tools compared to the open source alternative Ghostfolio. If you value transparency, data privacy, and community collaboration, Ghostfolio provides an excellent opportunity to take control of your financial management. + Ta przeglądowa strona zawiera wyselekcjonowaną kolekcję narzędzi do finansów osobistych w porównaniu z alternatywą open source Ghostfolio. Jeśli cenisz sobie przejrzystość, prywatność danych i współpracę ze społecznością, Ghostfolio stanowi doskonałą okazję do przejęcia kontroli nad swoim zarządzaniem finansami. apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.html 8 @@ -5071,7 +5071,7 @@ Explore the links below to compare a variety of personal finance tools with Ghostfolio. - Explore the links below to compare a variety of personal finance tools with Ghostfolio. + Zapoznaj się z poniższymi linkami, aby móc porównać różne narzędzia do finansów osobistych z Ghostfolio. apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.html 16 @@ -5079,7 +5079,7 @@ Open Source Alternative to - Open Source Alternative to + Alternatywa Open Source dla apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.html 42 @@ -5087,7 +5087,7 @@ The Open Source Alternative to - The Open Source Alternative to + Alternatywa Open Source dla apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 8 @@ -5095,7 +5095,7 @@ Are you looking for an open source alternative to ? Ghostfolio is a powerful portfolio management tool that provides individuals with a comprehensive platform to track, analyze, and optimize their investments. Whether you are an experienced investor or just starting out, Ghostfolio offers an intuitive user interface and a wide range of functionalities to help you make informed decisions and take control of your financial future. - Are you looking for an open source alternative to ? Ghostfolio is a powerful portfolio management tool that provides individuals with a comprehensive platform to track, analyze, and optimize their investments. Whether you are an experienced investor or just starting out, Ghostfolio offers an intuitive user interface and a wide range of functionalities to help you make informed decisions and take control of your financial future. + Szukasz alternatywy typu open source dla ? Ghostfolio to potężne narzędzie do zarządzania portfelem, które zapewnia osobom fizycznym kompleksową platformę do śledzenia, analizowania i optymalizacji ich inwestycji. Niezależnie od tego, czy jesteś doświadczonym inwestorem, czy dopiero zaczynasz, Ghostfolio oferuje intuicyjny interfejs użytkownika i szeroki zakres funkcjonalności, które pomogą Ci podejmować przemyślane decyzje i przejąć kontrolę nad swoją finansową przyszłością. apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 13 @@ -5103,7 +5103,7 @@ Ghostfolio is an open source software (OSS), providing a cost-effective alternative to making it particularly suitable for individuals on a tight budget, such as those pursuing Financial Independence, Retire Early (FIRE). By leveraging the collective efforts of a community of developers and personal finance enthusiasts, Ghostfolio continuously enhances its capabilities, security, and user experience. - Ghostfolio is an open source software (OSS), providing a cost-effective alternative to making it particularly suitable for individuals on a tight budget, such as those pursuing Financial Independence, Retire Early (FIRE). By leveraging the collective efforts of a community of developers and personal finance enthusiasts, Ghostfolio continuously enhances its capabilities, security, and user experience. + Ghostfolio to oprogramowanie o otwartym kodzie źródłowym (OSS), stanowiące opłacalną alternatywę dla , czyniąc go szczególnie odpowiednim dla osób o ograniczonym budżecie, takich jak osoby dążące do finansowej niezależności i wcześniejszej emerytury (Financial Independence, Retire Early - FIRE). Wykorzystując wspólne wysiłki społeczności programistów i entuzjastów finansów osobistych, Ghostfolio stale zwiększa swoje możliwości, bezpieczeństwo i komfort użytkowania. apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 27 @@ -5111,7 +5111,7 @@ Let’s dive deeper into the detailed Ghostfolio vs comparison table below to gain a thorough understanding of how Ghostfolio positions itself relative to . We will explore various aspects such as features, data privacy, pricing, and more, allowing you to make a well-informed choice for your personal requirements. - Let’s dive deeper into the detailed Ghostfolio vs comparison table below to gain a thorough understanding of how Ghostfolio positions itself relative to . We will explore various aspects such as features, data privacy, pricing, and more, allowing you to make a well-informed choice for your personal requirements. + Zagłębmy się w szczegółową tabelę porównawczą Ghostfolio vs poniżej, aby dokładnie zrozumieć, jak Ghostfolio pozycjonuje się w stosunku do . Przeanalizujemy różne aspekty, takie jak funkcje, prywatność danych, opłaty i inne, umożliwiając Tobie dokonanie przemyślanego wyboru pod kątem osobistych wymagań. apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 38 @@ -5119,7 +5119,7 @@ Ghostfolio vs comparison table - Ghostfolio vs comparison table + Ghostfolio vs - tabela porównawcza apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 49 @@ -5127,7 +5127,7 @@ Founded - Founded + Rok założenia apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 72 @@ -5135,7 +5135,7 @@ Origin - Origin + Pochodzenie apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 77 @@ -5143,7 +5143,7 @@ Region - Region + Region apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 82 @@ -5151,7 +5151,7 @@ Available in - Available in + Dostępny w następujących językach apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 103 @@ -5159,7 +5159,7 @@ ✅ Yes - ✅ Yes + ✅ Tak apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 131 @@ -5195,7 +5195,7 @@ ❌ No - ❌ No + ❌ Nie apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 133 @@ -5227,7 +5227,7 @@ ❌ No - ❌ No + ❌ Nie apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 140 @@ -5235,7 +5235,7 @@ Self-Hosting - Self-Hosting + Własny Hosting apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 145 @@ -5243,7 +5243,7 @@ Use anonymously - Use anonymously + Korzystaj anonimowo apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 164 @@ -5251,7 +5251,7 @@ Free Plan - Free Plan + Darmowy Plan apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 183 @@ -5267,7 +5267,7 @@ Please note that the information provided in the Ghostfolio vs comparison table is based on our independent research and analysis. This website is not affiliated with or any other product mentioned in the comparison. As the landscape of personal finance tools evolves, it is essential to verify any specific details or changes directly from the respective product page. Data needs a refresh? Help us maintain accurate data on GitHub. - Please note that the information provided in the Ghostfolio vs comparison table is based on our independent research and analysis. This website is not affiliated with or any other product mentioned in the comparison. As the landscape of personal finance tools evolves, it is essential to verify any specific details or changes directly from the respective product page. Data needs a refresh? Help us maintain accurate data on GitHub. + Należy pamiętać, że informacje zawarte w tabeli porównawczej Ghostfolio vs są oparte na naszych niezależnych badaniach i analizach. Ta strona internetowa nie jest powiązana z ani żadnym innym produktem wymienionym w porównaniu. Ponieważ krajobraz narzędzi do finansów osobistych ewoluuje, ważne jest, aby weryfikować wszelkie szczegóły lub zmiany bezpośrednio na stronie danego produktu. Informacje wymagają aktualizacji? Pomóż nam utrzymywać dokładne dane na GitHub. apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 226 @@ -5275,7 +5275,7 @@ Ready to take your investments to the next level? - Ready to take your investments to the next level? + Jesteś gotów wznieść swoje inwestycje na wyższy poziom? apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 239 @@ -5283,7 +5283,7 @@ Effortlessly track, analyze, and visualize your wealth with Ghostfolio. - Effortlessly track, analyze, and visualize your wealth with Ghostfolio. + Bezproblemowo śledź, analizuj i wizualizuj swój majątek dzięki Ghostfolio. apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 243 @@ -5291,7 +5291,7 @@ Get Started - Get Started + Rozpocznij apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 248 @@ -5299,7 +5299,7 @@ Personal Finance Tools - Personal Finance Tools + Narzędzia do Finansów Osobistych apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 266 @@ -5307,7 +5307,7 @@ Switzerland - Switzerland + Szwajcaria apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 60 @@ -5319,7 +5319,7 @@ Global - Global + Globalny apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 61 @@ -5331,7 +5331,7 @@ Resources - Resources + Zasoby apps/client/src/app/pages/resources/resources-page-routing.module.ts 13 @@ -5339,7 +5339,7 @@ Guides - Guides + Poradniki apps/client/src/app/pages/resources/resources-page.html 22 @@ -5347,7 +5347,7 @@ Glossary - Glossary + Słowniczek apps/client/src/app/pages/resources/resources-page.html 124 @@ -5355,7 +5355,7 @@ Membership - Membership + Członkostwo apps/client/src/app/pages/user-account/user-account-page-routing.module.ts 23 @@ -5367,7 +5367,7 @@ Access - Access + Dostęp apps/client/src/app/pages/user-account/user-account-page-routing.module.ts 28 @@ -5379,7 +5379,7 @@ My Ghostfolio - My Ghostfolio + Moje Ghostfolio apps/client/src/app/pages/user-account/user-account-page-routing.module.ts 33 @@ -5387,7 +5387,7 @@ Oops, authentication has failed. - Oops, authentication has failed. + Ups, uwierzytelnienie nie powiodło się. apps/client/src/app/pages/webauthn/webauthn-page.html 19 @@ -5395,7 +5395,7 @@ Try again - Try again + Spróbuj ponownie apps/client/src/app/pages/webauthn/webauthn-page.html 27 @@ -5403,7 +5403,7 @@ Go back to Home Page - Go back to Home Page + Wróć do Strony Głównej apps/client/src/app/pages/webauthn/webauthn-page.html 31 @@ -5411,7 +5411,7 @@ Import Activities - Import Activities + Importuj Działalności libs/ui/src/lib/activities-table/activities-table.component.html 9 @@ -5423,7 +5423,7 @@ Import Dividends - Import Dividends + Importuj Dywidendy libs/ui/src/lib/activities-table/activities-table.component.html 29 @@ -5435,7 +5435,7 @@ Export Activities - Export Activities + Eksportuj Działalności libs/ui/src/lib/activities-table/activities-table.component.html 41 @@ -5447,7 +5447,7 @@ Export Drafts as ICS - Export Drafts as ICS + Eksportuj Wersje Robocze jako ICS libs/ui/src/lib/activities-table/activities-table.component.html 54 @@ -5459,7 +5459,7 @@ Draft - Draft + Przygotuj Wstępną Wersję libs/ui/src/lib/activities-table/activities-table.component.html 144 @@ -5467,7 +5467,7 @@ Clone - Clone + Sklonuj libs/ui/src/lib/activities-table/activities-table.component.html 435 @@ -5475,7 +5475,7 @@ Export Draft as ICS - Export Draft as ICS + Eksportuj Wersję Roboczą jako ICS libs/ui/src/lib/activities-table/activities-table.component.html 445 @@ -5483,7 +5483,7 @@ Do you really want to delete this activity? - Do you really want to delete this activity? + Czy na pewno chcesz usunąć tę działalność? libs/ui/src/lib/activities-table/activities-table.component.ts 235 @@ -5491,7 +5491,7 @@ Find holding... - Find holding... + Znajdź portfel akcji... libs/ui/src/lib/assistant/assistant.component.ts 138 @@ -5499,7 +5499,7 @@ No entries... - No entries... + Brak wpisów... libs/ui/src/lib/assistant/assistant.html 63 @@ -5519,7 +5519,7 @@ Index - Index + Indeks libs/ui/src/lib/benchmark/benchmark.component.html 3 @@ -5527,7 +5527,7 @@ Last All Time High - Last All Time High + Ostatni Najwyższy Punkt w Historii libs/ui/src/lib/benchmark/benchmark.component.html 65 @@ -5535,7 +5535,7 @@ Change from All Time High - Change from All Time High + Zmiana od Najwyższego Punktu w Historii libs/ui/src/lib/benchmark/benchmark.component.html 81 @@ -5551,7 +5551,7 @@ Market data provided by - Market data provided by + Dane rynkowe dostarczone przez libs/ui/src/lib/data-provider-credits/data-provider-credits.component.html 2 @@ -5567,7 +5567,7 @@ Annual Interest Rate - Annual Interest Rate + Roczna Stopa Procentowa libs/ui/src/lib/fire-calculator/fire-calculator.component.html 21 @@ -5583,7 +5583,7 @@ Projected Total Amount - Projected Total Amount + Przewidywana Łączna Kwota libs/ui/src/lib/fire-calculator/fire-calculator.component.html 57 @@ -5591,7 +5591,7 @@ Interest - Interest + Udział libs/ui/src/lib/fire-calculator/fire-calculator.component.ts 371 @@ -5603,7 +5603,7 @@ Savings - Savings + Oszczędności libs/ui/src/lib/fire-calculator/fire-calculator.component.ts 381 @@ -5623,7 +5623,7 @@ Show all - Show all + Pokaż wszystko libs/ui/src/lib/holdings-table/holdings-table.component.html 197 @@ -5631,7 +5631,7 @@ Account - Account + Konto libs/ui/src/lib/i18n.ts 4 @@ -5639,7 +5639,7 @@ Asia-Pacific - Asia-Pacific + Azja-Pacyfik libs/ui/src/lib/i18n.ts 5 @@ -5647,7 +5647,7 @@ Asset Class - Asset Class + Rodzaj Aktywów libs/ui/src/lib/i18n.ts 6 @@ -5655,7 +5655,7 @@ Asset Sub Class - Asset Sub Class + Podklasa Aktywów libs/ui/src/lib/i18n.ts 7 @@ -5671,7 +5671,7 @@ Switch to Ghostfolio Premium or Ghostfolio Open Source easily - Switch to Ghostfolio Premium or Ghostfolio Open Source easily + Przełącz się z łatwością na Ghostfolio Premium lub Ghostfolio Open Source libs/ui/src/lib/i18n.ts 12 @@ -5679,7 +5679,7 @@ Switch to Ghostfolio Premium easily - Switch to Ghostfolio Premium easily + Przełącz się z łatwością na Ghostfolio Premium libs/ui/src/lib/i18n.ts 13 @@ -5687,7 +5687,7 @@ Switch to Ghostfolio Open Source or Ghostfolio Basic easily - Switch to Ghostfolio Open Source or Ghostfolio Basic easily + Przełącz się z łatwością na Ghostfolio Open Source lub Ghostfolio Basic libs/ui/src/lib/i18n.ts 14 @@ -5695,7 +5695,7 @@ Emergency Fund - Emergency Fund + Fundusz Rezerwowy libs/ui/src/lib/i18n.ts 15 @@ -5711,7 +5711,7 @@ Higher Risk - Higher Risk + Wyższe Ryzyko libs/ui/src/lib/i18n.ts 18 @@ -5719,7 +5719,7 @@ This activity already exists. - This activity already exists. + Ta działalność już istnieje. libs/ui/src/lib/i18n.ts 19 @@ -5727,7 +5727,7 @@ Japan - Japan + Japonia libs/ui/src/lib/i18n.ts 83 @@ -5735,7 +5735,7 @@ Lower Risk - Lower Risk + Niższe Ryzyko libs/ui/src/lib/i18n.ts 20 @@ -5779,7 +5779,7 @@ Retirement Provision - Retirement Provision + Świadczenia Emerytalne libs/ui/src/lib/i18n.ts 25 @@ -5787,7 +5787,7 @@ Satellite - Satellite + Satelita libs/ui/src/lib/i18n.ts 26 @@ -5827,7 +5827,7 @@ Buy - Buy + Zakup libs/ui/src/lib/i18n.ts 34 @@ -5835,7 +5835,7 @@ Fee - Fee + Opłata libs/ui/src/lib/i18n.ts 36 @@ -5867,7 +5867,7 @@ Cash - Cash + Gotówka libs/ui/src/lib/i18n.ts 43 @@ -5875,7 +5875,7 @@ Commodity - Commodity + Towar libs/ui/src/lib/i18n.ts 44 @@ -5883,7 +5883,7 @@ Equity - Equity + Kapitał libs/ui/src/lib/i18n.ts 45 @@ -5891,7 +5891,7 @@ Fixed Income - Fixed Income + Stały Dochód libs/ui/src/lib/i18n.ts 46 @@ -5899,7 +5899,7 @@ Real Estate - Real Estate + Nieruchomość libs/ui/src/lib/i18n.ts 48 @@ -5907,7 +5907,7 @@ Bond - Bond + Obligacja libs/ui/src/lib/i18n.ts 51 @@ -5915,7 +5915,7 @@ Cryptocurrency - Cryptocurrency + Kryptowaluta libs/ui/src/lib/i18n.ts 52 @@ -5923,7 +5923,7 @@ ETF - ETF + ETF libs/ui/src/lib/i18n.ts 53 @@ -5931,7 +5931,7 @@ Mutual Fund - Mutual Fund + Fundusz Wzajemny libs/ui/src/lib/i18n.ts 54 @@ -5939,7 +5939,7 @@ Precious Metal - Precious Metal + Metal Szlachetny libs/ui/src/lib/i18n.ts 55 @@ -5947,7 +5947,7 @@ Private Equity - Private Equity + Prywatny Kapitał libs/ui/src/lib/i18n.ts 56 @@ -6035,7 +6035,7 @@ Membership - Membership + Członkostwo libs/ui/src/lib/membership-card/membership-card.component.html 18 @@ -6043,7 +6043,7 @@ Valid until - Valid until + Ważność do libs/ui/src/lib/membership-card/membership-card.component.html 23 @@ -6051,7 +6051,7 @@ Time to add your first activity. - Time to add your first activity. + Czas dodać Twoją pierwszą działalność. libs/ui/src/lib/no-transactions-info/no-transactions-info.component.html 12 @@ -6071,7 +6071,7 @@ 50-Day Trend - 50-Day Trend + 50-Dniowy Trend libs/ui/src/lib/benchmark/benchmark.component.html 15 @@ -6079,7 +6079,7 @@ 200-Day Trend - 200-Day Trend + 200-Dniowy Trend libs/ui/src/lib/benchmark/benchmark.component.html 40 @@ -6087,7 +6087,7 @@ Cash Balances - Cash Balances + Salda Gotówkowe apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html 122 @@ -6127,7 +6127,7 @@ is an invalid currency! - is an invalid currency! + to nieprawidłowa waluta! apps/client/src/app/components/admin-overview/admin-overview.component.ts 133 @@ -6143,7 +6143,7 @@ The current market price is - The current market price is + Obecna cena rynkowa wynosi apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 345 @@ -6151,7 +6151,7 @@ Test - Test + Test apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 322 @@ -6159,7 +6159,7 @@ Date Range - Date Range + Zakres Dat libs/ui/src/lib/assistant/assistant.html 93 @@ -6167,7 +6167,7 @@ Permission - Permission + Pozwolenie apps/client/src/app/components/access-table/access-table.component.html 18 @@ -6179,7 +6179,7 @@ Restricted view - Restricted view + Ograniczony widok apps/client/src/app/components/access-table/access-table.component.html 26 @@ -6207,7 +6207,7 @@ Job Queue - Job Queue + Kolejka Zadań apps/client/src/app/pages/admin/admin-page-routing.module.ts 25 @@ -6219,7 +6219,7 @@ Market data is delayed for - Market data is delayed for + Dane rynkowe są opóźnione o apps/client/src/app/components/portfolio-performance/portfolio-performance.component.ts 86 @@ -6331,7 +6331,7 @@ View - View + Widok apps/client/src/app/components/access-table/access-table.component.html 23 @@ -6351,7 +6351,7 @@ If you retire today, you would be able to withdraw per year or per month, based on your total assets of and a withdrawal rate of 4%. - If you retire today, you would be able to withdraw per year or per month, based on your total assets of and a withdrawal rate of 4%. + Jeśli przejdziesz na emeryturę dzisiaj, będziesz mógł wypłacić rocznie lub miesięcznie, w oparciu o Twój łączny majątek w wysokości i stopę wypłaty w wysokości 4%. apps/client/src/app/pages/portfolio/fire/fire-page.html 67 @@ -6383,7 +6383,7 @@ Asset Classes - Asset Classes + Klasy Aktywów libs/ui/src/lib/assistant/assistant.html 138 @@ -6407,7 +6407,7 @@ General - General + Informacje Ogólne apps/client/src/app/pages/faq/faq-page.component.ts 36 @@ -6415,7 +6415,7 @@ Cloud - Cloud + Rozwiązanie w Chmurze apps/client/src/app/pages/faq/faq-page.component.ts 41 @@ -6427,7 +6427,7 @@ Self-Hosting - Self-Hosting + Własny Hosting apps/client/src/app/pages/faq/faq-page.component.ts 47 @@ -6467,7 +6467,7 @@ My Account - My Account + Moje Konto apps/client/src/app/pages/i18n/i18n-page.html 13 @@ -6507,7 +6507,7 @@ Execute Job - Execute Job + Wykonaj Zadanie apps/client/src/app/components/admin-jobs/admin-jobs.html 174 @@ -6563,7 +6563,7 @@ Buy and sell - Buy and sell + Kupno i Sprzedaż libs/ui/src/lib/i18n.ts 8 @@ -6595,7 +6595,7 @@ Danger Zone - Danger Zone + Strefa Zagrożenia apps/client/src/app/components/user-account-settings/user-account-settings.html 244 @@ -6603,7 +6603,7 @@ Close Account - Close Account + Zamknij Konto apps/client/src/app/components/user-account-settings/user-account-settings.html 279 @@ -6619,7 +6619,7 @@ Approximation based on the top holdings of each ETF - Approximation based on the top holdings of each ETF + Przybliżenie oparte na najwyższych aktywach każdego funduszu ETF apps/client/src/app/pages/portfolio/allocations/allocations-page.html 340 @@ -6651,7 +6651,7 @@ Benchmarks - Benchmarks + Punkty Odniesienia apps/client/src/app/components/admin-market-data/admin-market-data.component.ts 80 @@ -6683,7 +6683,7 @@ Table - Table + Tabela apps/client/src/app/components/home-holdings/home-holdings.html 17 @@ -6691,7 +6691,7 @@ Chart - Chart + Wykres apps/client/src/app/components/home-holdings/home-holdings.html 20 @@ -6707,7 +6707,7 @@ Alternative - Alternative + Alternatywa apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 83 @@ -6715,7 +6715,7 @@ App - App + Aplikacja apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 84 @@ -6723,7 +6723,7 @@ Budgeting - Budgeting + Budżetowanie apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 85 @@ -6731,7 +6731,7 @@ Community - Community + Społeczność apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 86 @@ -6739,7 +6739,7 @@ Family Office - Family Office + Biuro Rodzinne apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 87 @@ -6747,7 +6747,7 @@ Investor - Investor + Inwestor apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 90 @@ -6755,7 +6755,7 @@ Open Source - Open Source + Otwarty Kod Źródłowy apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 91 @@ -6763,7 +6763,7 @@ Personal Finance - Personal Finance + Finanse Osobiste apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 93 @@ -6771,7 +6771,7 @@ Privacy - Privacy + Prywatność apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 94 @@ -6779,7 +6779,7 @@ Software - Software + Oprogramowanie apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 96 @@ -6787,7 +6787,7 @@ Tool - Tool + Narzędzie apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 97 @@ -6795,7 +6795,7 @@ User Experience - User Experience + Doświadczenie Użytkownika apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 98 @@ -6803,7 +6803,7 @@ Wealth - Wealth + Majątek apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 99 @@ -6811,7 +6811,7 @@ Wealth Management - Wealth Management + Zarządzanie Majątkiem apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 100 @@ -6819,7 +6819,7 @@ Australia - Australia + Australia libs/ui/src/lib/i18n.ts 72 @@ -6827,7 +6827,7 @@ Austria - Austria + Austria libs/ui/src/lib/i18n.ts 73 @@ -6835,7 +6835,7 @@ Belgium - Belgium + Belgia libs/ui/src/lib/i18n.ts 74 @@ -6843,7 +6843,7 @@ Bulgaria - Bulgaria + Bułgaria libs/ui/src/lib/i18n.ts 75 @@ -6851,7 +6851,7 @@ Canada - Canada + Kanada libs/ui/src/lib/i18n.ts 76 @@ -6859,7 +6859,7 @@ Czech Republic - Czech Republic + Czechy libs/ui/src/lib/i18n.ts 77 @@ -6867,7 +6867,7 @@ Finland - Finland + Finlandia libs/ui/src/lib/i18n.ts 78 @@ -6875,7 +6875,7 @@ France - France + Francja libs/ui/src/lib/i18n.ts 79 @@ -6883,7 +6883,7 @@ Germany - Germany + Niemcy libs/ui/src/lib/i18n.ts 80 @@ -6891,7 +6891,7 @@ India - India + Indie libs/ui/src/lib/i18n.ts 81 @@ -6899,7 +6899,7 @@ Italy - Italy + Włochy libs/ui/src/lib/i18n.ts 82 @@ -6907,7 +6907,7 @@ Netherlands - Netherlands + Holandia libs/ui/src/lib/i18n.ts 84 @@ -6915,7 +6915,7 @@ New Zealand - New Zealand + Nowa Zelandia libs/ui/src/lib/i18n.ts 85 @@ -6923,7 +6923,7 @@ Poland - Poland + Polska libs/ui/src/lib/i18n.ts 86 @@ -6931,7 +6931,7 @@ Romania - Romania + Rumunia libs/ui/src/lib/i18n.ts 87 @@ -6939,7 +6939,7 @@ South Africa - South Africa + Południowa Afryka libs/ui/src/lib/i18n.ts 88 @@ -6947,7 +6947,7 @@ Thailand - Thailand + Tajlandia libs/ui/src/lib/i18n.ts 90 @@ -6955,7 +6955,7 @@ United States - United States + Stany Zjednoczone libs/ui/src/lib/i18n.ts 91 @@ -6963,7 +6963,7 @@ Error - Error + Błąd apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 336 @@ -6971,7 +6971,7 @@ Deactivate - Deactivate + Dezaktywuj apps/client/src/app/components/rule/rule.component.html 67 @@ -6979,7 +6979,7 @@ Activate - Activate + Aktywuj apps/client/src/app/components/rule/rule.component.html 69 @@ -6987,7 +6987,7 @@ Inactive - Inactive + Nieaktywny apps/client/src/app/pages/portfolio/fire/fire-page.html 194 @@ -6995,7 +6995,7 @@ Cancel - Cancel + Anuluj libs/ui/src/lib/i18n.ts 9 @@ -7003,7 +7003,7 @@ Close - Close + Zamknij libs/ui/src/lib/i18n.ts 11 @@ -7011,7 +7011,7 @@ Yes - Yes + Tak libs/ui/src/lib/i18n.ts 31 From 0fc83486dc17c69304ea474db59c95d634f9f1ed Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 31 Aug 2024 10:57:26 +0200 Subject: [PATCH 08/78] Feature/improve redis cache (#3714) * Improve redis cache * Update changelog --- CHANGELOG.md | 5 + .../interfaces/redis-cache.interface.ts | 7 - .../interfaces/redis-store.interface.ts | 8 - .../src/app/redis-cache/redis-cache.module.ts | 16 +- .../redis-cache/redis-cache.service.mock.ts | 4 +- .../app/redis-cache/redis-cache.service.ts | 10 +- .../configuration/configuration.service.ts | 3 +- .../interfaces/environment.interface.ts | 1 - package-lock.json | 220 ++++++++++++------ package.json | 8 +- 10 files changed, 176 insertions(+), 106 deletions(-) delete mode 100644 apps/api/src/app/redis-cache/interfaces/redis-cache.interface.ts delete mode 100644 apps/api/src/app/redis-cache/interfaces/redis-store.interface.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 33705879f..fb764589e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Reworked the portfolio calculator - Exposed the log levels as an environment variable (`LOG_LEVELS`) - Exposed the maximum of chart data items as an environment variable (`MAX_CHART_ITEMS`) +- Changed the data format of the environment variable `CACHE_QUOTES_TTL` from seconds to milliseconds +- Changed the data format of the environment variable `CACHE_TTL` from seconds to milliseconds +- Removed the environment variable `MAX_ITEM_IN_CACHE` - Improved the language localization for Polish (`pl`) +- Migrated from `cache-manager-redis-store` to `cache-manager-redis-yet` +- Upgraded `cache-manager` from version `3.4.3` to `5.7.6` ### Fixed diff --git a/apps/api/src/app/redis-cache/interfaces/redis-cache.interface.ts b/apps/api/src/app/redis-cache/interfaces/redis-cache.interface.ts deleted file mode 100644 index 194da0bc8..000000000 --- a/apps/api/src/app/redis-cache/interfaces/redis-cache.interface.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Cache } from 'cache-manager'; - -import type { RedisStore } from './redis-store.interface'; - -export interface RedisCache extends Cache { - store: RedisStore; -} diff --git a/apps/api/src/app/redis-cache/interfaces/redis-store.interface.ts b/apps/api/src/app/redis-cache/interfaces/redis-store.interface.ts deleted file mode 100644 index 2ad5df485..000000000 --- a/apps/api/src/app/redis-cache/interfaces/redis-store.interface.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Store } from 'cache-manager'; -import { createClient } from 'redis'; - -export interface RedisStore extends Store { - getClient: () => ReturnType; - isCacheableValue: (value: any) => boolean; - name: 'redis'; -} diff --git a/apps/api/src/app/redis-cache/redis-cache.module.ts b/apps/api/src/app/redis-cache/redis-cache.module.ts index 4b4168168..f960ad047 100644 --- a/apps/api/src/app/redis-cache/redis-cache.module.ts +++ b/apps/api/src/app/redis-cache/redis-cache.module.ts @@ -3,31 +3,27 @@ import { ConfigurationService } from '@ghostfolio/api/services/configuration/con import { CacheModule } from '@nestjs/cache-manager'; import { Module } from '@nestjs/common'; -import * as redisStore from 'cache-manager-redis-store'; +import { redisStore } from 'cache-manager-redis-yet'; import type { RedisClientOptions } from 'redis'; import { RedisCacheService } from './redis-cache.service'; @Module({ + exports: [RedisCacheService], imports: [ - CacheModule.registerAsync({ + CacheModule.registerAsync({ imports: [ConfigurationModule], inject: [ConfigurationService], useFactory: async (configurationService: ConfigurationService) => { return { - db: configurationService.get('REDIS_DB'), - host: configurationService.get('REDIS_HOST'), - max: configurationService.get('MAX_ITEM_IN_CACHE'), - password: configurationService.get('REDIS_PASSWORD'), - port: configurationService.get('REDIS_PORT'), store: redisStore, - ttl: configurationService.get('CACHE_TTL') + ttl: configurationService.get('CACHE_TTL'), + url: `redis://:${configurationService.get('REDIS_PASSWORD')}@${configurationService.get('REDIS_HOST')}:${configurationService.get('REDIS_PORT')}/${configurationService.get('REDIS_DB')}` }; } }), ConfigurationModule ], - providers: [RedisCacheService], - exports: [RedisCacheService] + providers: [RedisCacheService] }) export class RedisCacheModule {} diff --git a/apps/api/src/app/redis-cache/redis-cache.service.mock.ts b/apps/api/src/app/redis-cache/redis-cache.service.mock.ts index 2422e88ab..094c7e6a0 100644 --- a/apps/api/src/app/redis-cache/redis-cache.service.mock.ts +++ b/apps/api/src/app/redis-cache/redis-cache.service.mock.ts @@ -1,4 +1,4 @@ -import { RedisCacheService } from './redis-cache.service'; +import { Milliseconds } from 'cache-manager'; export const RedisCacheServiceMock = { get: (key: string): Promise => { @@ -7,7 +7,7 @@ export const RedisCacheServiceMock = { getPortfolioSnapshotKey: (userId: string): string => { return `portfolio-snapshot-${userId}`; }, - set: (key: string, value: string, ttlInSeconds?: number): Promise => { + set: (key: string, value: string, ttl?: Milliseconds): Promise => { return Promise.resolve(value); } }; diff --git a/apps/api/src/app/redis-cache/redis-cache.service.ts b/apps/api/src/app/redis-cache/redis-cache.service.ts index 341dc4acf..c972c30a1 100644 --- a/apps/api/src/app/redis-cache/redis-cache.service.ts +++ b/apps/api/src/app/redis-cache/redis-cache.service.ts @@ -4,17 +4,17 @@ import { AssetProfileIdentifier, Filter } from '@ghostfolio/common/interfaces'; import { CACHE_MANAGER } from '@nestjs/cache-manager'; import { Inject, Injectable, Logger } from '@nestjs/common'; +import { Milliseconds } from 'cache-manager'; +import { RedisCache } from 'cache-manager-redis-yet'; import { createHash } from 'crypto'; -import type { RedisCache } from './interfaces/redis-cache.interface'; - @Injectable() export class RedisCacheService { public constructor( @Inject(CACHE_MANAGER) private readonly cache: RedisCache, private readonly configurationService: ConfigurationService ) { - const client = cache.store.getClient(); + const client = cache.store.client; client.on('error', (error) => { Logger.error(error, 'RedisCacheService'); @@ -81,11 +81,11 @@ export class RedisCacheService { return this.cache.reset(); } - public async set(key: string, value: string, ttlInSeconds?: number) { + public async set(key: string, value: string, ttl?: Milliseconds) { return this.cache.set( key, value, - ttlInSeconds ?? this.configurationService.get('CACHE_TTL') + ttl ?? this.configurationService.get('CACHE_TTL') ); } } diff --git a/apps/api/src/services/configuration/configuration.service.ts b/apps/api/src/services/configuration/configuration.service.ts index 6a50766d2..4c5a60cce 100644 --- a/apps/api/src/services/configuration/configuration.service.ts +++ b/apps/api/src/services/configuration/configuration.service.ts @@ -21,7 +21,7 @@ export class ConfigurationService { API_KEY_FINANCIAL_MODELING_PREP: str({ default: '' }), API_KEY_OPEN_FIGI: str({ default: '' }), API_KEY_RAPID_API: str({ default: '' }), - CACHE_QUOTES_TTL: num({ default: ms('1 minute') / 1000 }), + CACHE_QUOTES_TTL: num({ default: ms('1 minute') }), CACHE_TTL: num({ default: 1 }), DATA_SOURCE_EXCHANGE_RATES: str({ default: DataSource.YAHOO }), DATA_SOURCE_IMPORT: str({ default: DataSource.YAHOO }), @@ -43,7 +43,6 @@ export class ConfigurationService { JWT_SECRET_KEY: str({}), MAX_ACTIVITIES_TO_IMPORT: num({ default: Number.MAX_SAFE_INTEGER }), MAX_CHART_ITEMS: num({ default: 365 }), - MAX_ITEM_IN_CACHE: num({ default: 9999 }), PORT: port({ default: 3333 }), REDIS_DB: num({ default: 0 }), REDIS_HOST: str({ default: 'localhost' }), diff --git a/apps/api/src/services/interfaces/environment.interface.ts b/apps/api/src/services/interfaces/environment.interface.ts index c0dfb1806..d07937787 100644 --- a/apps/api/src/services/interfaces/environment.interface.ts +++ b/apps/api/src/services/interfaces/environment.interface.ts @@ -29,7 +29,6 @@ export interface Environment extends CleanedEnvAccessors { JWT_SECRET_KEY: string; MAX_ACTIVITIES_TO_IMPORT: number; MAX_CHART_ITEMS: number; - MAX_ITEM_IN_CACHE: number; PORT: number; REDIS_DB: number; REDIS_HOST: string; diff --git a/package-lock.json b/package-lock.json index aa7ff4681..2938d915b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ghostfolio", - "version": "2.103.0", + "version": "2.106.0-beta.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ghostfolio", - "version": "2.103.0", + "version": "2.106.0-beta.3", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { @@ -30,7 +30,7 @@ "@dinero.js/currencies": "2.0.0-alpha.8", "@internationalized/number": "3.5.2", "@nestjs/bull": "10.0.1", - "@nestjs/cache-manager": "2.1.0", + "@nestjs/cache-manager": "2.2.2", "@nestjs/common": "10.1.3", "@nestjs/config": "3.0.0", "@nestjs/core": "10.1.3", @@ -49,8 +49,8 @@ "body-parser": "1.20.2", "bootstrap": "4.6.0", "bull": "4.10.4", - "cache-manager": "3.4.3", - "cache-manager-redis-store": "2.0.0", + "cache-manager": "5.7.6", + "cache-manager-redis-yet": "5.1.4", "chart.js": "4.2.0", "chartjs-adapter-date-fns": "3.0.0", "chartjs-chart-treemap": "2.3.1", @@ -126,7 +126,7 @@ "@trivago/prettier-plugin-sort-imports": "4.3.0", "@types/big.js": "6.2.2", "@types/body-parser": "1.19.5", - "@types/cache-manager": "3.4.2", + "@types/cache-manager": "4.0.6", "@types/color": "3.0.6", "@types/google-spreadsheet": "3.1.5", "@types/jest": "29.4.4", @@ -6800,14 +6800,14 @@ "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, "node_modules/@nestjs/cache-manager": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@nestjs/cache-manager/-/cache-manager-2.1.0.tgz", - "integrity": "sha512-9kep3a8Mq5cMuXN/anGhSYc0P48CRBXk5wyJJRBFxhNkCH8AIzZF4CASGVDIEMmm3OjVcEUHojjyJwCODS17Qw==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@nestjs/cache-manager/-/cache-manager-2.2.2.tgz", + "integrity": "sha512-+n7rpU1QABeW2WV17Dl1vZCG3vWjJU1MaamWgZvbGxYE9EeCM0lVLfw3z7acgDTNwOy+K68xuQPoIMxD0bhjlA==", + "license": "MIT", "peerDependencies": { "@nestjs/common": "^9.0.0 || ^10.0.0", "@nestjs/core": "^9.0.0 || ^10.0.0", "cache-manager": "<=5", - "reflect-metadata": "^0.1.12", "rxjs": "^7.0.0" } }, @@ -9708,6 +9708,71 @@ "@prisma/debug": "5.18.0" } }, + "node_modules/@redis/bloom": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz", + "integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==", + "license": "MIT", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/client": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.6.0.tgz", + "integrity": "sha512-aR0uffYI700OEEH4gYnitAnv3vzVGXCFvYfdpu/CJKvk4pHfLPEy/JSZyrpQ+15WhXe1yJRXLtfQ84s4mEXnPg==", + "license": "MIT", + "dependencies": { + "cluster-key-slot": "1.1.2", + "generic-pool": "3.9.0", + "yallist": "4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@redis/client/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, + "node_modules/@redis/graph": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.1.tgz", + "integrity": "sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw==", + "license": "MIT", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/json": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.7.tgz", + "integrity": "sha512-6UyXfjVaTBTJtKNG4/9Z8PSpKE6XgSyEb8iwaqDcy+uKrd/DGYHTWkUdnQDyzm727V7p21WUMhsqz5oy65kPcQ==", + "license": "MIT", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/search": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.2.0.tgz", + "integrity": "sha512-tYoDBbtqOVigEDMAcTGsRlMycIIjwMCgD8eR2t0NANeQmgK/lvxNAvYyb6bZDD4frHRhIHkJu2TBRvB0ERkOmw==", + "license": "MIT", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/time-series": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.1.0.tgz", + "integrity": "sha512-c1Q99M5ljsIuc4YdaCwfUEXsofakb9c8+Zse2qxTadu8TalLXuAESzLvFAvNVbkmSlvlzIQOLpBCmWI9wTOt+g==", + "license": "MIT", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.19.1", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.19.1.tgz", @@ -11468,10 +11533,11 @@ } }, "node_modules/@types/cache-manager": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/@types/cache-manager/-/cache-manager-3.4.2.tgz", - "integrity": "sha512-1IwA74t5ID4KWo0Kndal16MhiPSZgMe1fGc+MLT6j5r+Ab7jku36PFTl4PP6MiWw0BJscM9QpZEo00qixNQoRg==", - "dev": true + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@types/cache-manager/-/cache-manager-4.0.6.tgz", + "integrity": "sha512-8qL93MF05/xrzFm/LSPtzNEOE1eQF3VwGHAcQEylgp5hDSTe41jtFwbSYAPfyYcVa28y1vYSjIt0c1fLLUiC/Q==", + "dev": true, + "license": "MIT" }, "node_modules/@types/cacheable-request": { "version": "6.0.3", @@ -13255,7 +13321,8 @@ "node_modules/async": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", - "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==" + "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==", + "dev": true }, "node_modules/asynckit": { "version": "0.4.0", @@ -14243,41 +14310,50 @@ } }, "node_modules/cache-manager": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/cache-manager/-/cache-manager-3.4.3.tgz", - "integrity": "sha512-6+Hfzy1SNs/thUwo+07pV0ozgxc4sadrAN0eFVGvXl/X9nz3J0BqEnnEoyxEn8jnF+UkEo0MKpyk9BO80hMeiQ==", - "dependencies": { - "async": "3.2.0", - "lodash": "^4.17.21", - "lru-cache": "6.0.0" - } - }, - "node_modules/cache-manager-redis-store": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/cache-manager-redis-store/-/cache-manager-redis-store-2.0.0.tgz", - "integrity": "sha512-bWLWlUg6nCYHiJLCCYxY2MgvwvKnvlWwrbuynrzpjEIhfArD2GC9LtutIHFEPeyGVQN6C+WEw+P3r+BFBwhswg==", + "version": "5.7.6", + "resolved": "https://registry.npmjs.org/cache-manager/-/cache-manager-5.7.6.tgz", + "integrity": "sha512-wBxnBHjDxF1RXpHCBD6HGvKER003Ts7IIm0CHpggliHzN1RZditb7rXoduE1rplc2DEFYKxhLKgFuchXMJje9w==", + "license": "MIT", "dependencies": { - "redis": "^3.0.2" + "eventemitter3": "^5.0.1", + "lodash.clonedeep": "^4.5.0", + "lru-cache": "^10.2.2", + "promise-coalesce": "^1.1.2" }, "engines": { - "node": ">= 8.3" + "node": ">= 18" } }, - "node_modules/cache-manager/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/cache-manager-redis-yet": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/cache-manager-redis-yet/-/cache-manager-redis-yet-5.1.4.tgz", + "integrity": "sha512-2mXZjo+txfH2m+mSTHTITNq8c5SssU2nP7NutzrocO3Mw/SbjHcDo+mriI3ZuR63ov/oUUIaF9iF+MzDqVzMoQ==", + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" + "@redis/bloom": "^1.2.0", + "@redis/client": "^1.6.0", + "@redis/graph": "^1.1.1", + "@redis/json": "^1.0.7", + "@redis/search": "^1.2.0", + "@redis/time-series": "^1.1.0", + "cache-manager": "^5.7.6", + "redis": "^4.7.0" }, "engines": { - "node": ">=10" + "node": ">= 18" } }, - "node_modules/cache-manager/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "node_modules/cache-manager/node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT" + }, + "node_modules/cache-manager/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" }, "node_modules/cacheable-lookup": { "version": "5.0.4", @@ -19466,6 +19542,15 @@ "node": ">=10" } }, + "node_modules/generic-pool": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", + "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -24555,6 +24640,12 @@ "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", "optional": true }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", + "license": "MIT" + }, "node_modules/lodash.clonedeepwith": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clonedeepwith/-/lodash.clonedeepwith-4.5.0.tgz", @@ -28785,6 +28876,15 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, + "node_modules/promise-coalesce": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/promise-coalesce/-/promise-coalesce-1.1.2.tgz", + "integrity": "sha512-zLaJ9b8hnC564fnJH6NFSOGZYYdzrAJn2JUUIwzoQb32fG2QAakpDNM+CZo1km6keXkRXRM+hml1BFAPVnPkxg==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=16" + } + }, "node_modules/promise-inflight": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", @@ -29125,28 +29225,22 @@ } }, "node_modules/redis": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/redis/-/redis-3.1.2.tgz", - "integrity": "sha512-grn5KoZLr/qrRQVwoSkmzdbw6pwF+/rwODtrOr6vuBRiR/f3rjSTGupbF90Zpqm2oenix8Do6RV7pYEkGwlKkw==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/redis/-/redis-4.7.0.tgz", + "integrity": "sha512-zvmkHEAdGMn+hMRXuMBtu4Vo5P6rHQjLoHftu+lBqq8ZTA3RCVC/WzD790bkKKiNFp7d5/9PcSD19fJyyRvOdQ==", + "license": "MIT", + "workspaces": [ + "./packages/*" + ], "dependencies": { - "denque": "^1.5.0", - "redis-commands": "^1.7.0", - "redis-errors": "^1.2.0", - "redis-parser": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-redis" + "@redis/bloom": "1.2.0", + "@redis/client": "1.6.0", + "@redis/graph": "1.1.1", + "@redis/json": "1.0.7", + "@redis/search": "1.2.0", + "@redis/time-series": "1.1.0" } }, - "node_modules/redis-commands": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.7.0.tgz", - "integrity": "sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ==" - }, "node_modules/redis-errors": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", @@ -29166,14 +29260,6 @@ "node": ">=4" } }, - "node_modules/redis/node_modules/denque": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", - "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==", - "engines": { - "node": ">=0.10" - } - }, "node_modules/reflect-metadata": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", diff --git a/package.json b/package.json index ef43a39a2..f44dae34e 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,7 @@ "@dinero.js/currencies": "2.0.0-alpha.8", "@internationalized/number": "3.5.2", "@nestjs/bull": "10.0.1", - "@nestjs/cache-manager": "2.1.0", + "@nestjs/cache-manager": "2.2.2", "@nestjs/common": "10.1.3", "@nestjs/config": "3.0.0", "@nestjs/core": "10.1.3", @@ -93,8 +93,8 @@ "body-parser": "1.20.2", "bootstrap": "4.6.0", "bull": "4.10.4", - "cache-manager": "3.4.3", - "cache-manager-redis-store": "2.0.0", + "cache-manager": "5.7.6", + "cache-manager-redis-yet": "5.1.4", "chart.js": "4.2.0", "chartjs-adapter-date-fns": "3.0.0", "chartjs-chart-treemap": "2.3.1", @@ -170,7 +170,7 @@ "@trivago/prettier-plugin-sort-imports": "4.3.0", "@types/big.js": "6.2.2", "@types/body-parser": "1.19.5", - "@types/cache-manager": "3.4.2", + "@types/cache-manager": "4.0.6", "@types/color": "3.0.6", "@types/google-spreadsheet": "3.1.5", "@types/jest": "29.4.4", From e4ba27850d625a4e5442363b7c557ff579c5aed2 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 31 Aug 2024 14:29:45 +0200 Subject: [PATCH 09/78] Feature/upgrade prisma to version 5.19.0 (#3715) * Upgrade prisma to version 5.19.0 * Update changelog --- CHANGELOG.md | 1 + package-lock.json | 67 +++++++++++++++++++++++++---------------------- package.json | 4 +-- 3 files changed, 38 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fb764589e..f68d1aad8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Improved the language localization for Polish (`pl`) - Migrated from `cache-manager-redis-store` to `cache-manager-redis-yet` - Upgraded `cache-manager` from version `3.4.3` to `5.7.6` +- Upgraded `prisma` from version `5.18.0` to `5.19.0` ### Fixed diff --git a/package-lock.json b/package-lock.json index 2938d915b..fbb54d4e2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -40,7 +40,7 @@ "@nestjs/platform-express": "10.1.3", "@nestjs/schedule": "3.0.2", "@nestjs/serve-static": "4.0.0", - "@prisma/client": "5.18.0", + "@prisma/client": "5.19.0", "@simplewebauthn/browser": "9.0.1", "@simplewebauthn/server": "9.0.3", "@stripe/stripe-js": "3.5.0", @@ -84,7 +84,7 @@ "passport": "0.7.0", "passport-google-oauth20": "2.0.0", "passport-jwt": "4.0.1", - "prisma": "5.18.0", + "prisma": "5.19.0", "reflect-metadata": "0.1.13", "rxjs": "7.5.6", "stripe": "15.11.0", @@ -9646,9 +9646,9 @@ "dev": true }, "node_modules/@prisma/client": { - "version": "5.18.0", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.18.0.tgz", - "integrity": "sha512-BWivkLh+af1kqC89zCJYkHsRcyWsM8/JHpsDMM76DjP3ZdEquJhXa4IeX+HkWPnwJ5FanxEJFZZDTWiDs/Kvyw==", + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.19.0.tgz", + "integrity": "sha512-CzOpau+q1kEWQyoQMvlnXIHqPvwmWbh48xZ4n8KWbAql0p8PC0BIgSTYW5ncxXa4JSEff0tcoxSZB874wDstdg==", "hasInstallScript": true, "license": "Apache-2.0", "engines": { @@ -9664,48 +9664,48 @@ } }, "node_modules/@prisma/debug": { - "version": "5.18.0", - "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.18.0.tgz", - "integrity": "sha512-f+ZvpTLidSo3LMJxQPVgAxdAjzv5OpzAo/eF8qZqbwvgi2F5cTOI9XCpdRzJYA0iGfajjwjOKKrVq64vkxEfUw==", + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.19.0.tgz", + "integrity": "sha512-+b/G0ubAZlrS+JSiDhXnYV5DF/aTJ3pinktkiV/L4TtLRLZO6SVGyFELgxBsicCTWJ2ZMu5vEV/jTtYCdjFTRA==", "license": "Apache-2.0" }, "node_modules/@prisma/engines": { - "version": "5.18.0", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.18.0.tgz", - "integrity": "sha512-ofmpGLeJ2q2P0wa/XaEgTnX/IsLnvSp/gZts0zjgLNdBhfuj2lowOOPmDcfKljLQUXMvAek3lw5T01kHmCG8rg==", + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.19.0.tgz", + "integrity": "sha512-UtW+0m4HYoRSSR3LoDGKF3Ud4BSMWYlLEt4slTnuP1mI+vrV3zaDoiAPmejdAT76vCN5UqnWURbkXxf66nSylQ==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "5.18.0", - "@prisma/engines-version": "5.18.0-25.4c784e32044a8a016d99474bd02a3b6123742169", - "@prisma/fetch-engine": "5.18.0", - "@prisma/get-platform": "5.18.0" + "@prisma/debug": "5.19.0", + "@prisma/engines-version": "5.19.0-31.5fe21811a6ba0b952a3bc71400666511fe3b902f", + "@prisma/fetch-engine": "5.19.0", + "@prisma/get-platform": "5.19.0" } }, "node_modules/@prisma/engines-version": { - "version": "5.18.0-25.4c784e32044a8a016d99474bd02a3b6123742169", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.18.0-25.4c784e32044a8a016d99474bd02a3b6123742169.tgz", - "integrity": "sha512-a/+LpJj8vYU3nmtkg+N3X51ddbt35yYrRe8wqHTJtYQt7l1f8kjIBcCs6sHJvodW/EK5XGvboOiwm47fmNrbgg==", + "version": "5.19.0-31.5fe21811a6ba0b952a3bc71400666511fe3b902f", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.19.0-31.5fe21811a6ba0b952a3bc71400666511fe3b902f.tgz", + "integrity": "sha512-GimI9aZIFy/yvvR11KfXRn3pliFn1QAkdebVlsXlnoh5uk0YhLblVmeYiHfsu+wDA7BeKqYT4sFfzg8mutzuWw==", "license": "Apache-2.0" }, "node_modules/@prisma/fetch-engine": { - "version": "5.18.0", - "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.18.0.tgz", - "integrity": "sha512-I/3u0x2n31rGaAuBRx2YK4eB7R/1zCuayo2DGwSpGyrJWsZesrV7QVw7ND0/Suxeo/vLkJ5OwuBqHoCxvTHpOg==", + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.19.0.tgz", + "integrity": "sha512-oOiPNtmJX0cP/ebu7BBEouJvCw8T84/MFD/Hf2zlqjxkK4ojl38bB9i9J5LAxotL6WlYVThKdxc7HqoWnPOhqQ==", "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "5.18.0", - "@prisma/engines-version": "5.18.0-25.4c784e32044a8a016d99474bd02a3b6123742169", - "@prisma/get-platform": "5.18.0" + "@prisma/debug": "5.19.0", + "@prisma/engines-version": "5.19.0-31.5fe21811a6ba0b952a3bc71400666511fe3b902f", + "@prisma/get-platform": "5.19.0" } }, "node_modules/@prisma/get-platform": { - "version": "5.18.0", - "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.18.0.tgz", - "integrity": "sha512-Tk+m7+uhqcKDgnMnFN0lRiH7Ewea0OEsZZs9pqXa7i3+7svS3FSCqDBCaM9x5fmhhkufiG0BtunJVDka+46DlA==", + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.19.0.tgz", + "integrity": "sha512-s9DWkZKnuP4Y8uy6yZfvqQ/9X3/+2KYf3IZUVZz5OstJdGBJrBlbmIuMl81917wp5TuK/1k2TpHNCEdpYLPKmg==", "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "5.18.0" + "@prisma/debug": "5.19.0" } }, "node_modules/@redis/bloom": { @@ -28829,19 +28829,22 @@ } }, "node_modules/prisma": { - "version": "5.18.0", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.18.0.tgz", - "integrity": "sha512-+TrSIxZsh64OPOmaSgVPH7ALL9dfU0jceYaMJXsNrTkFHO7/3RANi5K2ZiPB1De9+KDxCWn7jvRq8y8pvk+o9g==", + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.19.0.tgz", + "integrity": "sha512-Pu7lUKpVyTx8cVwM26dYh8NdvMOkMnJXzE8L6cikFuR4JwyMU5NKofQkWyxJKlTT4fNjmcnibTvklV8oVMrn+g==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@prisma/engines": "5.18.0" + "@prisma/engines": "5.19.0" }, "bin": { "prisma": "build/index.js" }, "engines": { "node": ">=16.13" + }, + "optionalDependencies": { + "fsevents": "2.3.3" } }, "node_modules/prismjs": { diff --git a/package.json b/package.json index f44dae34e..9eb00e3c4 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,7 @@ "@nestjs/platform-express": "10.1.3", "@nestjs/schedule": "3.0.2", "@nestjs/serve-static": "4.0.0", - "@prisma/client": "5.18.0", + "@prisma/client": "5.19.0", "@simplewebauthn/browser": "9.0.1", "@simplewebauthn/server": "9.0.3", "@stripe/stripe-js": "3.5.0", @@ -128,7 +128,7 @@ "passport": "0.7.0", "passport-google-oauth20": "2.0.0", "passport-jwt": "4.0.1", - "prisma": "5.18.0", + "prisma": "5.19.0", "reflect-metadata": "0.1.13", "rxjs": "7.5.6", "stripe": "15.11.0", From c6f804f68c419571abee3d1d02787aa54864f0bc Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 31 Aug 2024 16:11:18 +0200 Subject: [PATCH 10/78] Feature/Improve redis cache part 2 (#3716) * Set ttl to 0 --- apps/api/src/app/benchmark/benchmark.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/api/src/app/benchmark/benchmark.service.ts b/apps/api/src/app/benchmark/benchmark.service.ts index 169ea8cad..6cb375e0f 100644 --- a/apps/api/src/app/benchmark/benchmark.service.ts +++ b/apps/api/src/app/benchmark/benchmark.service.ts @@ -443,7 +443,7 @@ export class BenchmarkService { benchmarks, expiration: expiration.getTime() }), - ms('12 hours') / 1000 + 0 ); } From 71a568264d8933ca9befe1d4563b1b0b046faea9 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 31 Aug 2024 16:11:52 +0200 Subject: [PATCH 11/78] Feature/improve portfolio snapshot caching (#3717) * Improve portfolio snapshot caching * Update changelog --- CHANGELOG.md | 1 + .../calculator/portfolio-calculator.ts | 74 ++++++++++++++----- .../interfaces/snapshot-value.interface.ts | 4 + 3 files changed, 60 insertions(+), 19 deletions(-) create mode 100644 apps/api/src/app/portfolio/interfaces/snapshot-value.interface.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index f68d1aad8..cbfcfa2f2 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 - Reworked the portfolio calculator +- Improved the caching of the portfolio snapshot in the portfolio calculator by returning cached data and recalculating in the background when it expires - Exposed the log levels as an environment variable (`LOG_LEVELS`) - Exposed the maximum of chart data items as an environment variable (`MAX_CHART_ITEMS`) - Changed the data format of the environment variable `CACHE_QUOTES_TTL` from seconds to milliseconds diff --git a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts index 0fcb8b9d6..5384fd6d8 100644 --- a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts @@ -1,6 +1,7 @@ import { Activity } from '@ghostfolio/api/app/order/interfaces/activities.interface'; import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service'; import { PortfolioOrder } from '@ghostfolio/api/app/portfolio/interfaces/portfolio-order.interface'; +import { PortfolioSnapshotValue } from '@ghostfolio/api/app/portfolio/interfaces/snapshot-value.interface'; import { TransactionPointSymbol } from '@ghostfolio/api/app/portfolio/interfaces/transaction-point-symbol.interface'; import { TransactionPoint } from '@ghostfolio/api/app/portfolio/interfaces/transaction-point.interface'; import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service'; @@ -32,6 +33,7 @@ import { Logger } from '@nestjs/common'; import { Big } from 'big.js'; import { plainToClass } from 'class-transformer'; import { + addMilliseconds, differenceInDays, eachDayOfInterval, endOfDay, @@ -863,6 +865,29 @@ export abstract class PortfolioCalculator { return chartDateMap; } + private async computeAndCacheSnapshot() { + const snapshot = await this.computeSnapshot(); + + const expiration = addMilliseconds( + new Date(), + this.configurationService.get('CACHE_QUOTES_TTL') + ); + + this.redisCacheService.set( + this.redisCacheService.getPortfolioSnapshotKey({ + filters: this.filters, + userId: this.userId + }), + JSON.stringify(({ + expiration: expiration.getTime(), + portfolioSnapshot: snapshot + })), + 0 + ); + + return snapshot; + } + @LogPerformance private computeTransactionPoints() { this.transactionPoints = []; @@ -1006,19 +1031,33 @@ export abstract class PortfolioCalculator { private async initialize() { const startTimeTotal = performance.now(); - const cachedSnapshot = await this.redisCacheService.get( - this.redisCacheService.getPortfolioSnapshotKey({ - filters: this.filters, - userId: this.userId - }) - ); + let cachedPortfolioSnapshot: PortfolioSnapshot; + let isCachedPortfolioSnapshotExpired = false; + + try { + const cachedPortfolioSnapshotValue = await this.redisCacheService.get( + this.redisCacheService.getPortfolioSnapshotKey({ + filters: this.filters, + userId: this.userId + }) + ); + + const { expiration, portfolioSnapshot }: PortfolioSnapshotValue = + JSON.parse(cachedPortfolioSnapshotValue); - if (cachedSnapshot) { - this.snapshot = plainToClass( + cachedPortfolioSnapshot = plainToClass( PortfolioSnapshot, - JSON.parse(cachedSnapshot) + portfolioSnapshot ); + if (isAfter(new Date(), new Date(expiration))) { + isCachedPortfolioSnapshotExpired = true; + } + } catch {} + + if (cachedPortfolioSnapshot) { + this.snapshot = cachedPortfolioSnapshot; + Logger.debug( `Fetched portfolio snapshot from cache in ${( (performance.now() - startTimeTotal) / @@ -1026,17 +1065,14 @@ export abstract class PortfolioCalculator { ).toFixed(3)} seconds`, 'PortfolioCalculator' ); - } else { - this.snapshot = await this.computeSnapshot(); - this.redisCacheService.set( - this.redisCacheService.getPortfolioSnapshotKey({ - filters: this.filters, - userId: this.userId - }), - JSON.stringify(this.snapshot), - this.configurationService.get('CACHE_QUOTES_TTL') - ); + if (isCachedPortfolioSnapshotExpired) { + // Compute in the background + this.computeAndCacheSnapshot(); + } + } else { + // Wait for computation + this.snapshot = await this.computeAndCacheSnapshot(); } } } diff --git a/apps/api/src/app/portfolio/interfaces/snapshot-value.interface.ts b/apps/api/src/app/portfolio/interfaces/snapshot-value.interface.ts new file mode 100644 index 000000000..3d205416c --- /dev/null +++ b/apps/api/src/app/portfolio/interfaces/snapshot-value.interface.ts @@ -0,0 +1,4 @@ +export interface PortfolioSnapshotValue { + expiration: number; + portfolioSnapshot: string; +} From 5358f13e934a3d20f7b24a7a949d9de8c421e96f Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 31 Aug 2024 16:13:56 +0200 Subject: [PATCH 12/78] Release 2.106.0-beta.4 (#3719) --- CHANGELOG.md | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cbfcfa2f2..d7dfcb740 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## 2.106.0-beta.3 - 2024-08-28 +## 2.106.0-beta.4 - 2024-08-31 ### Added diff --git a/package.json b/package.json index 9eb00e3c4..eb7c3532f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "2.106.0-beta.3", + "version": "2.106.0-beta.4", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "repository": "https://github.com/ghostfolio/ghostfolio", From adcddae44eeff2a6e413b6f4f86a1cf5bc31cf7c Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 31 Aug 2024 16:49:05 +0200 Subject: [PATCH 13/78] Encode redis password (#3720) --- apps/api/src/app/redis-cache/redis-cache.module.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/api/src/app/redis-cache/redis-cache.module.ts b/apps/api/src/app/redis-cache/redis-cache.module.ts index f960ad047..a507479b9 100644 --- a/apps/api/src/app/redis-cache/redis-cache.module.ts +++ b/apps/api/src/app/redis-cache/redis-cache.module.ts @@ -15,10 +15,14 @@ import { RedisCacheService } from './redis-cache.service'; imports: [ConfigurationModule], inject: [ConfigurationService], useFactory: async (configurationService: ConfigurationService) => { + const redisPassword = encodeURIComponent( + configurationService.get('REDIS_PASSWORD') + ); + return { store: redisStore, ttl: configurationService.get('CACHE_TTL'), - url: `redis://:${configurationService.get('REDIS_PASSWORD')}@${configurationService.get('REDIS_HOST')}:${configurationService.get('REDIS_PORT')}/${configurationService.get('REDIS_DB')}` + url: `redis://${redisPassword ? `:${redisPassword}` : ''}@${configurationService.get('REDIS_HOST')}:${configurationService.get('REDIS_PORT')}/${configurationService.get('REDIS_DB')}` }; } }), From 676be076c3b98321f6b3617e9b3f5d13f5d6844a Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 31 Aug 2024 16:50:25 +0200 Subject: [PATCH 14/78] Release 2.106.0-beta.5 (#3721) --- CHANGELOG.md | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d7dfcb740..25cae43aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## 2.106.0-beta.4 - 2024-08-31 +## 2.106.0-beta.5 - 2024-08-31 ### Added diff --git a/package.json b/package.json index eb7c3532f..e66dc3a3f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "2.106.0-beta.4", + "version": "2.106.0-beta.5", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "repository": "https://github.com/ghostfolio/ghostfolio", From 8fab73f122af289a0266db1fb900efbdd453da14 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Tue, 3 Sep 2024 14:12:16 +0200 Subject: [PATCH 15/78] Feature/update OSS friends (#3718) --- apps/client/src/assets/oss-friends.json | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/apps/client/src/assets/oss-friends.json b/apps/client/src/assets/oss-friends.json index 88037573f..0fe726510 100644 --- a/apps/client/src/assets/oss-friends.json +++ b/apps/client/src/assets/oss-friends.json @@ -1,5 +1,5 @@ { - "createdAt": "2024-04-09T00:00:00.000Z", + "createdAt": "2024-08-31T00:00:00.000Z", "data": [ { "name": "Aptabase", @@ -46,11 +46,6 @@ "description": "dyrector.io is an open-source continuous delivery & deployment platform with version management.", "href": "https://dyrector.io" }, - { - "name": "Erxes", - "description": "The Open-Source HubSpot Alternative. A single XOS enables to create unique and life-changing experiences that work for all types of business.", - "href": "https://erxes.io" - }, { "name": "Firecamp", "description": "vscode for apis, open-source postman/insomnia alternative", @@ -86,11 +81,6 @@ "description": "Open source, end-to-end encrypted platform that lets you securely manage secrets and configs across your team, devices, and infrastructure.", "href": "https://infisical.com" }, - { - "name": "Keep", - "description": "Open source alert management and AIOps platform.", - "href": "https://keephq.dev" - }, { "name": "Langfuse", "description": "Open source LLM engineering platform. Debug, analyze and iterate together.", @@ -116,6 +106,11 @@ "description": "Open-source monitoring platform with beautiful status pages", "href": "https://www.openstatus.dev" }, + { + "name": "Portkey AI", + "description": "AI Gateway with integrated Guardrails. Route to 250+ LLMs and 50+ Guardrails with 1-fast API. Supports caching, retries, and edge deployment for low latency.", + "href": "https://www.portkey.ai" + }, { "name": "Prisma", "description": "Simplify working with databases. Build, optimize, and grow your app easily with an intuitive data model, type-safety, automated migrations, connection pooling, caching, and real-time db subscriptions.", @@ -126,11 +121,6 @@ "description": "Makes frontend development cycle 10x faster with API Client, Mock Server, Intercept & Modify HTTP Requests and Session Replays.", "href": "https://requestly.com" }, - { - "name": "Revert", - "description": "The open-source unified API to build B2B integrations remarkably fast", - "href": "https://revert.dev" - }, { "name": "Rivet", "description": "Open-source solution to deploy, scale, and operate your multiplayer game.", From a6d9f5dd69f7935904ceb402c3072a9613cbbbbd Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Tue, 3 Sep 2024 19:24:14 +0200 Subject: [PATCH 16/78] Bugfix/load data once on portfolio activities page (#3726) * Fetch activities only once * Update changelog --- CHANGELOG.md | 3 ++- .../pages/portfolio/activities/activities-page.component.ts | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 25cae43aa..d5945c854 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## 2.106.0-beta.5 - 2024-08-31 +## Unreleased ### Added @@ -28,6 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Fixed an issue in the view mode toggle of the holdings tab on the home page (experimental) +- Fixed an issue on the portfolio activities page by loading the data only once ## 2.105.0 - 2024-08-21 diff --git a/apps/client/src/app/pages/portfolio/activities/activities-page.component.ts b/apps/client/src/app/pages/portfolio/activities/activities-page.component.ts index 7cd89d62f..a7638c561 100644 --- a/apps/client/src/app/pages/portfolio/activities/activities-page.component.ts +++ b/apps/client/src/app/pages/portfolio/activities/activities-page.component.ts @@ -108,8 +108,6 @@ export class ActivitiesPageComponent implements OnDestroy, OnInit { this.changeDetectorRef.markForCheck(); } }); - - this.fetchActivities(); } public fetchActivities() { From c48e4ec4c632b0e2f5188b83463742a3703e26da Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Tue, 3 Sep 2024 20:42:49 +0200 Subject: [PATCH 17/78] Feature/improve usage of portfolio calculator in holding endpoint (#3727) * Improve usage of portfolio calculator --- .../src/app/portfolio/portfolio.service.ts | 65 +++++++++---------- 1 file changed, 30 insertions(+), 35 deletions(-) diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index 01dd55112..0cd602046 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -602,14 +602,7 @@ export class PortfolioService { userId }); - const orders = activities.filter(({ SymbolProfile }) => { - return ( - SymbolProfile.dataSource === aDataSource && - SymbolProfile.symbol === aSymbol - ); - }); - - if (orders.length <= 0) { + if (activities.length === 0) { return { accounts: [], averagePrice: undefined, @@ -646,10 +639,8 @@ export class PortfolioService { ]); const portfolioCalculator = this.calculatorFactory.createCalculator({ + activities, userId, - activities: orders.filter((order) => { - return ['BUY', 'DIVIDEND', 'ITEM', 'SELL'].includes(order.type); - }), calculationType: PerformanceCalculationType.TWR, currency: userCurrency }); @@ -659,8 +650,8 @@ export class PortfolioService { const { positions } = await portfolioCalculator.getSnapshot(); - const position = positions.find(({ symbol }) => { - return symbol === aSymbol; + const position = positions.find(({ dataSource, symbol }) => { + return dataSource === aDataSource && symbol === aSymbol; }); if (position) { @@ -673,14 +664,22 @@ export class PortfolioService { firstBuyDate, marketPrice, quantity, + symbol, tags, timeWeightedInvestment, timeWeightedInvestmentWithCurrencyEffect, transactionCount } = position; + const activitiesOfPosition = activities.filter(({ SymbolProfile }) => { + return ( + SymbolProfile.dataSource === dataSource && + SymbolProfile.symbol === symbol + ); + }); + const accounts: PortfolioHoldingDetail['accounts'] = uniqBy( - orders.filter(({ Account }) => { + activitiesOfPosition.filter(({ Account }) => { return Account; }), 'Account.id' @@ -715,8 +714,8 @@ export class PortfolioService { ); const historicalDataArray: HistoricalDataItem[] = []; - let maxPrice = Math.max(orders[0].unitPrice, marketPrice); - let minPrice = Math.min(orders[0].unitPrice, marketPrice); + let maxPrice = Math.max(activitiesOfPosition[0].unitPrice, marketPrice); + let minPrice = Math.min(activitiesOfPosition[0].unitPrice, marketPrice); if (historicalData[aSymbol]) { let j = -1; @@ -760,10 +759,10 @@ export class PortfolioService { } else { // Add historical entry for buy date, if no historical data available historicalDataArray.push({ - averagePrice: orders[0].unitPrice, + averagePrice: activitiesOfPosition[0].unitPrice, date: firstBuyDate, - marketPrice: orders[0].unitPrice, - quantity: orders[0].quantity + marketPrice: activitiesOfPosition[0].unitPrice, + quantity: activitiesOfPosition[0].quantity }); } @@ -773,7 +772,6 @@ export class PortfolioService { marketPrice, maxPrice, minPrice, - orders, SymbolProfile, tags, transactionCount, @@ -805,6 +803,7 @@ export class PortfolioService { ]?.toNumber(), netPerformanceWithCurrencyEffect: position.netPerformanceWithCurrencyEffectMap?.['max']?.toNumber(), + orders: activitiesOfPosition, quantity: quantity.toNumber(), value: this.exchangeRateDataService.toCurrency( quantity.mul(marketPrice ?? 0).toNumber(), @@ -862,7 +861,6 @@ export class PortfolioService { marketPrice, maxPrice, minPrice, - orders, SymbolProfile, accounts: [], averagePrice: 0, @@ -882,6 +880,7 @@ export class PortfolioService { netPerformancePercent: undefined, netPerformancePercentWithCurrencyEffect: undefined, netPerformanceWithCurrencyEffect: undefined, + orders: [], quantity: 0, tags: [], transactionCount: undefined, @@ -912,7 +911,7 @@ export class PortfolioService { userCurrency: this.getUserCurrency() }); - if (activities?.length <= 0) { + if (activities.length === 0) { return { hasErrors: false, positions: [] @@ -1037,14 +1036,12 @@ export class PortfolioService { dateRange = 'max', filters, impersonationId, - portfolioCalculator, userId, withExcludedAccounts = false }: { dateRange?: DateRange; filters?: Filter[]; impersonationId: string; - portfolioCalculator?: PortfolioCalculator; userId: string; withExcludedAccounts?: boolean; }): Promise { @@ -1089,7 +1086,7 @@ export class PortfolioService { userId }); - if (accountBalanceItems?.length <= 0 && activities?.length <= 0) { + if (accountBalanceItems.length === 0 && activities.length === 0) { return { chart: [], firstOrderDate: undefined, @@ -1106,16 +1103,14 @@ export class PortfolioService { }; } - portfolioCalculator = - portfolioCalculator ?? - this.calculatorFactory.createCalculator({ - accountBalanceItems, - activities, - filters, - userId, - calculationType: PerformanceCalculationType.TWR, - currency: userCurrency - }); + const portfolioCalculator = this.calculatorFactory.createCalculator({ + accountBalanceItems, + activities, + filters, + userId, + calculationType: PerformanceCalculationType.TWR, + currency: userCurrency + }); const { errors, hasErrors, historicalData } = await portfolioCalculator.getSnapshot(); From d6dbc0d9e3a166c31d1253b9f7bf2c52bc6c4122 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Tue, 3 Sep 2024 20:44:42 +0200 Subject: [PATCH 18/78] Release 2.106.0-beta.6 (#3728) --- CHANGELOG.md | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d5945c854..5427d6a3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased +## 2.106.0-beta.6 ### Added diff --git a/package.json b/package.json index e66dc3a3f..79ed8f8c1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "2.106.0-beta.5", + "version": "2.106.0-beta.6", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "repository": "https://github.com/ghostfolio/ghostfolio", From 80182369424e92ecc5c4b5b4c4cb4bd0346bfb77 Mon Sep 17 00:00:00 2001 From: Daniel Idem <36500470+dinirichard@users.noreply.github.com> Date: Wed, 4 Sep 2024 19:19:59 +0100 Subject: [PATCH 19/78] Bugfix/fix carousel component (#3709) * Fix carousel component * Update changelog --- CHANGELOG.md | 1 + .../src/app/pages/landing/landing-page.html | 2 +- .../lib/carousel/carousel-item.directive.ts | 12 +--- .../src/lib/carousel/carousel.component.html | 7 +- .../ui/src/lib/carousel/carousel.component.ts | 64 +++---------------- 5 files changed, 13 insertions(+), 73 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5427d6a3b..d598db05c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed an issue in the view mode toggle of the holdings tab on the home page (experimental) - Fixed an issue on the portfolio activities page by loading the data only once +- Fixed an issue in the carousel component for the testimonial section on the landing page ## 2.105.0 - 2024-08-21 diff --git a/apps/client/src/app/pages/landing/landing-page.html b/apps/client/src/app/pages/landing/landing-page.html index 72de38c20..f726a6020 100644 --- a/apps/client/src/app/pages/landing/landing-page.html +++ b/apps/client/src/app/pages/landing/landing-page.html @@ -331,7 +331,7 @@
@for (testimonial of testimonials; track testimonial) { -
+
) {} - - public focus() { - this.element.nativeElement.focus({ preventScroll: true }); - } } diff --git a/libs/ui/src/lib/carousel/carousel.component.html b/libs/ui/src/lib/carousel/carousel.component.html index 27d94dfd5..9cf34fe02 100644 --- a/libs/ui/src/lib/carousel/carousel.component.html +++ b/libs/ui/src/lib/carousel/carousel.component.html @@ -11,12 +11,7 @@ } -
+
diff --git a/libs/ui/src/lib/carousel/carousel.component.ts b/libs/ui/src/lib/carousel/carousel.component.ts index 7f93297dd..8b766aa6d 100644 --- a/libs/ui/src/lib/carousel/carousel.component.ts +++ b/libs/ui/src/lib/carousel/carousel.component.ts @@ -1,24 +1,18 @@ -import { FocusKeyManager } from '@angular/cdk/a11y'; -import { LEFT_ARROW, RIGHT_ARROW, TAB } from '@angular/cdk/keycodes'; import { - AfterContentInit, CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, Component, - ContentChildren, + contentChildren, ElementRef, HostBinding, Inject, Input, Optional, - QueryList, ViewChild } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { ANIMATION_MODULE_TYPE } from '@angular/platform-browser/animations'; -import { CarouselItem } from './carousel-item.directive'; - @Component({ changeDetection: ChangeDetectionStrategy.OnPush, imports: [MatButtonModule], @@ -28,9 +22,7 @@ import { CarouselItem } from './carousel-item.directive'; styleUrls: ['./carousel.component.scss'], templateUrl: './carousel.component.html' }) -export class GfCarouselComponent implements AfterContentInit { - @ContentChildren(CarouselItem) public items!: QueryList; - +export class GfCarouselComponent { @HostBinding('class.animations-disabled') public readonly animationsDisabled: boolean; @@ -38,11 +30,11 @@ export class GfCarouselComponent implements AfterContentInit { @ViewChild('list') public list!: ElementRef; + public items = contentChildren('carouselItem', { read: ElementRef }); public showPrevArrow = false; public showNextArrow = true; private index = 0; - private keyManager!: FocusKeyManager; private position = 0; public constructor( @@ -51,12 +43,8 @@ export class GfCarouselComponent implements AfterContentInit { this.animationsDisabled = animationsModule === 'NoopAnimations'; } - public ngAfterContentInit() { - this.keyManager = new FocusKeyManager(this.items); - } - public next() { - for (let i = this.index; i < this.items.length; i++) { + for (let i = this.index; i < this.items().length; i++) { if (this.isOutOfView(i)) { this.index = i; this.scrollToActiveItem(); @@ -65,31 +53,6 @@ export class GfCarouselComponent implements AfterContentInit { } } - public onKeydown({ keyCode }: KeyboardEvent) { - const manager = this.keyManager; - const previousActiveIndex = manager.activeItemIndex; - - if (keyCode === LEFT_ARROW) { - manager.setPreviousItemActive(); - } else if (keyCode === RIGHT_ARROW) { - manager.setNextItemActive(); - } else if (keyCode === TAB && !manager.activeItem) { - manager.setFirstItemActive(); - } - - if ( - manager.activeItemIndex != null && - manager.activeItemIndex !== previousActiveIndex - ) { - this.index = manager.activeItemIndex; - this.updateItemTabIndices(); - - if (this.isOutOfView(this.index)) { - this.scrollToActiveItem(); - } - } - } - public previous() { for (let i = this.index; i > -1; i--) { if (this.isOutOfView(i)) { @@ -101,8 +64,7 @@ export class GfCarouselComponent implements AfterContentInit { } private isOutOfView(index: number, side?: 'start' | 'end') { - const { offsetWidth, offsetLeft } = - this.items.toArray()[index].element.nativeElement; + const { offsetWidth, offsetLeft } = this.items()[index].nativeElement; if ((!side || side === 'start') && offsetLeft - this.position < 0) { return true; @@ -120,33 +82,23 @@ export class GfCarouselComponent implements AfterContentInit { return; } - const itemsArray = this.items.toArray(); let targetItemIndex = this.index; if (this.index > 0 && !this.isOutOfView(this.index - 1)) { targetItemIndex = - itemsArray.findIndex((_, i) => !this.isOutOfView(i)) + 1; + this.items().findIndex((_, i) => !this.isOutOfView(i)) + 1; } - this.position = - itemsArray[targetItemIndex].element.nativeElement.offsetLeft; + this.position = this.items()[targetItemIndex].nativeElement.offsetLeft; this.list.nativeElement.style.transform = `translateX(-${this.position}px)`; this.showPrevArrow = this.index > 0; this.showNextArrow = false; - for (let i = itemsArray.length - 1; i > -1; i--) { + for (let i = this.items().length - 1; i > -1; i--) { if (this.isOutOfView(i, 'end')) { this.showNextArrow = true; break; } } } - - private updateItemTabIndices() { - this.items.forEach((item: CarouselItem) => { - if (this.keyManager != null) { - item.tabindex = item === this.keyManager.activeItem ? '0' : '-1'; - } - }); - } } From 7ea906185219f608473a1737894fbb0278a75c39 Mon Sep 17 00:00:00 2001 From: Shaunak Das <51281688+shaun-ak@users.noreply.github.com> Date: Thu, 5 Sep 2024 00:47:38 +0530 Subject: [PATCH 20/78] Feature/execute scraper configuration instantly (#3723) * Execute scraper configuration instantly * Update changelog --------- Co-authored-by: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> --- CHANGELOG.md | 1 + .../data-provider/manual/manual.service.ts | 35 +++++++++++++++++-- .../symbol-profile/symbol-profile.service.ts | 2 ++ .../scraper-configuration.interface.ts | 1 + 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d598db05c..4639d2485 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 - Set up a performance logging service +- Added the attribute `mode` to the scraper configuration to get quotes instantly ### Changed diff --git a/apps/api/src/services/data-provider/manual/manual.service.ts b/apps/api/src/services/data-provider/manual/manual.service.ts index 0655d2318..02e50a145 100644 --- a/apps/api/src/services/data-provider/manual/manual.service.ts +++ b/apps/api/src/services/data-provider/manual/manual.service.ts @@ -166,11 +166,42 @@ export class ManualService implements DataProviderInterface { } }); + const symbolProfilesWithScraperConfigurationAndInstantMode = + symbolProfiles.filter(({ scraperConfiguration }) => { + return scraperConfiguration?.mode === 'instant'; + }); + + const scraperResultPromises = + symbolProfilesWithScraperConfigurationAndInstantMode.map( + async ({ scraperConfiguration, symbol }) => { + try { + const marketPrice = await this.scrape(scraperConfiguration); + return { marketPrice, symbol }; + } catch (error) { + Logger.error( + `Could not get quote for ${symbol} (${this.getName()}): [${error.name}] ${error.message}`, + 'ManualService' + ); + return { symbol, marketPrice: undefined }; + } + } + ); + + // Wait for all scraping requests to complete concurrently + const scraperResults = await Promise.all(scraperResultPromises); + for (const { currency, symbol } of symbolProfiles) { - let marketPrice = + let { marketPrice } = + scraperResults.find((result) => { + return result.symbol === symbol; + }) ?? {}; + + marketPrice = + marketPrice ?? marketData.find((marketDataItem) => { return marketDataItem.symbol === symbol; - })?.marketPrice ?? 0; + })?.marketPrice ?? + 0; response[symbol] = { currency, diff --git a/apps/api/src/services/symbol-profile/symbol-profile.service.ts b/apps/api/src/services/symbol-profile/symbol-profile.service.ts index 50cb25000..283da7b52 100644 --- a/apps/api/src/services/symbol-profile/symbol-profile.service.ts +++ b/apps/api/src/services/symbol-profile/symbol-profile.service.ts @@ -275,6 +275,8 @@ export class SymbolProfileService { headers: scraperConfiguration.headers as ScraperConfiguration['headers'], locale: scraperConfiguration.locale as string, + mode: + (scraperConfiguration.mode as ScraperConfiguration['mode']) ?? 'lazy', selector: scraperConfiguration.selector as string, url: scraperConfiguration.url as string }; diff --git a/libs/common/src/lib/interfaces/scraper-configuration.interface.ts b/libs/common/src/lib/interfaces/scraper-configuration.interface.ts index ef5506328..70fcd939d 100644 --- a/libs/common/src/lib/interfaces/scraper-configuration.interface.ts +++ b/libs/common/src/lib/interfaces/scraper-configuration.interface.ts @@ -2,6 +2,7 @@ export interface ScraperConfiguration { defaultMarketPrice?: number; headers?: { [key: string]: string }; locale?: string; + mode?: 'instant' | 'lazy'; selector: string; url: string; } From fb44933c9cd168b34e90a83eceeaf44cf6f9a61b Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Thu, 5 Sep 2024 18:21:32 +0200 Subject: [PATCH 21/78] Feature/improve error logs in scraper configuration test (#3730) * Improve error logs * Update changelog --- CHANGELOG.md | 1 + apps/api/src/app/admin/admin.controller.ts | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4639d2485..448e1c5a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Changed the data format of the environment variable `CACHE_QUOTES_TTL` from seconds to milliseconds - Changed the data format of the environment variable `CACHE_TTL` from seconds to milliseconds - Removed the environment variable `MAX_ITEM_IN_CACHE` +- Improved the error logs of the scraper configuration test in the asset profile details dialog of the admin control - Improved the language localization for Polish (`pl`) - Migrated from `cache-manager-redis-store` to `cache-manager-redis-yet` - Upgraded `cache-manager` from version `3.4.3` to `5.7.6` diff --git a/apps/api/src/app/admin/admin.controller.ts b/apps/api/src/app/admin/admin.controller.ts index 69e6955c1..6d201be23 100644 --- a/apps/api/src/app/admin/admin.controller.ts +++ b/apps/api/src/app/admin/admin.controller.ts @@ -239,9 +239,11 @@ export class AdminController { return { price }; } - throw new Error('Could not parse the current market price'); + throw new Error( + `Could not parse the current market price for ${symbol} (${dataSource})` + ); } catch (error) { - Logger.error(error); + Logger.error(error, 'AdminController'); throw new HttpException(error.message, StatusCodes.BAD_REQUEST); } From df5e2f5f0e7041ad73f27f77c983edff61aa6d18 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Thu, 5 Sep 2024 18:23:38 +0200 Subject: [PATCH 22/78] Feature/extract common CACHE_TTL as constants (#3722) Extract CACHE_TTL * CACHE_TTL_NO_CACHE * CACHE_TTL_INFINITE --- apps/api/src/app/benchmark/benchmark.service.ts | 7 +++++-- .../src/app/portfolio/calculator/portfolio-calculator.ts | 3 ++- .../src/services/configuration/configuration.service.ts | 7 +++++-- libs/common/src/lib/config.ts | 3 +++ 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/apps/api/src/app/benchmark/benchmark.service.ts b/apps/api/src/app/benchmark/benchmark.service.ts index 6cb375e0f..f57f5fa30 100644 --- a/apps/api/src/app/benchmark/benchmark.service.ts +++ b/apps/api/src/app/benchmark/benchmark.service.ts @@ -7,7 +7,10 @@ import { MarketDataService } from '@ghostfolio/api/services/market-data/market-d 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 { PROPERTY_BENCHMARKS } from '@ghostfolio/common/config'; +import { + CACHE_TTL_INFINITE, + PROPERTY_BENCHMARKS +} from '@ghostfolio/common/config'; import { DATE_FORMAT, calculateBenchmarkTrend, @@ -443,7 +446,7 @@ export class BenchmarkService { benchmarks, expiration: expiration.getTime() }), - 0 + CACHE_TTL_INFINITE ); } diff --git a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts index 5384fd6d8..2938bd734 100644 --- a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts @@ -11,6 +11,7 @@ import { ConfigurationService } from '@ghostfolio/api/services/configuration/con import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { IDataGatheringItem } from '@ghostfolio/api/services/interfaces/interfaces'; import { getIntervalFromDateRange } from '@ghostfolio/common/calculation-helper'; +import { CACHE_TTL_INFINITE } from '@ghostfolio/common/config'; import { DATE_FORMAT, getSum, @@ -882,7 +883,7 @@ export abstract class PortfolioCalculator { expiration: expiration.getTime(), portfolioSnapshot: snapshot })), - 0 + CACHE_TTL_INFINITE ); return snapshot; diff --git a/apps/api/src/services/configuration/configuration.service.ts b/apps/api/src/services/configuration/configuration.service.ts index 4c5a60cce..26ef38c0a 100644 --- a/apps/api/src/services/configuration/configuration.service.ts +++ b/apps/api/src/services/configuration/configuration.service.ts @@ -1,5 +1,8 @@ import { Environment } from '@ghostfolio/api/services/interfaces/environment.interface'; -import { DEFAULT_ROOT_URL } from '@ghostfolio/common/config'; +import { + CACHE_TTL_NO_CACHE, + DEFAULT_ROOT_URL +} from '@ghostfolio/common/config'; import { Injectable } from '@nestjs/common'; import { DataSource } from '@prisma/client'; @@ -22,7 +25,7 @@ export class ConfigurationService { API_KEY_OPEN_FIGI: str({ default: '' }), API_KEY_RAPID_API: str({ default: '' }), CACHE_QUOTES_TTL: num({ default: ms('1 minute') }), - CACHE_TTL: num({ default: 1 }), + CACHE_TTL: num({ default: CACHE_TTL_NO_CACHE }), DATA_SOURCE_EXCHANGE_RATES: str({ default: DataSource.YAHOO }), DATA_SOURCE_IMPORT: str({ default: DataSource.YAHOO }), DATA_SOURCES: json({ diff --git a/libs/common/src/lib/config.ts b/libs/common/src/lib/config.ts index 50c02ae20..00e756810 100644 --- a/libs/common/src/lib/config.ts +++ b/libs/common/src/lib/config.ts @@ -30,6 +30,9 @@ export const warnColorRgb = { b: 69 }; +export const CACHE_TTL_NO_CACHE = 1; +export const CACHE_TTL_INFINITE = 0; + export const DATA_GATHERING_QUEUE = 'DATA_GATHERING_QUEUE'; export const DATA_GATHERING_QUEUE_PRIORITY_HIGH = 1; export const DATA_GATHERING_QUEUE_PRIORITY_LOW = Number.MAX_SAFE_INTEGER; From 1204240ed09e4283ecef3becd40adb01fa7df577 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Fri, 6 Sep 2024 10:29:53 +0200 Subject: [PATCH 23/78] Bugfix/fix exception in admin market data detail component (#3731) * Add check for dateOfFirstActivity * Update changelog --- CHANGELOG.md | 1 + .../admin-market-data-detail.component.ts | 76 +++++++++---------- 2 files changed, 39 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 448e1c5a6..a1bb6525f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed an issue in the view mode toggle of the holdings tab on the home page (experimental) - Fixed an issue on the portfolio activities page by loading the data only once - Fixed an issue in the carousel component for the testimonial section on the landing page +- Handled an exception in the historical market data component of the asset profile details dialog in the admin control panel ## 2.105.0 - 2024-08-21 diff --git a/apps/client/src/app/components/admin-market-data-detail/admin-market-data-detail.component.ts b/apps/client/src/app/components/admin-market-data-detail/admin-market-data-detail.component.ts index 7e7168a6e..a1261c37f 100644 --- a/apps/client/src/app/components/admin-market-data-detail/admin-market-data-detail.component.ts +++ b/apps/client/src/app/components/admin-market-data-detail/admin-market-data-detail.component.ts @@ -93,52 +93,52 @@ export class AdminMarketDataDetailComponent implements OnChanges, OnInit { }; }); - let date = parseISO(this.dateOfFirstActivity); - - const missingMarketData: Partial[] = []; - - if (this.historicalDataItems?.[0]?.date) { - while ( - isBefore( - date, - parse(this.historicalDataItems[0].date, DATE_FORMAT, new Date()) - ) - ) { - missingMarketData.push({ - date, - marketPrice: undefined - }); - - date = addDays(date, 1); + if (this.dateOfFirstActivity) { + let date = parseISO(this.dateOfFirstActivity); + + const missingMarketData: Partial[] = []; + + if (this.historicalDataItems?.[0]?.date) { + while ( + isBefore( + date, + parse(this.historicalDataItems[0].date, DATE_FORMAT, new Date()) + ) + ) { + missingMarketData.push({ + date, + marketPrice: undefined + }); + + date = addDays(date, 1); + } } - } - const marketDataItems = [...missingMarketData, ...this.marketData]; + const marketDataItems = [...missingMarketData, ...this.marketData]; - if (!isToday(last(marketDataItems)?.date)) { - marketDataItems.push({ date: new Date() }); - } + if (!isToday(last(marketDataItems)?.date)) { + marketDataItems.push({ date: new Date() }); + } - this.marketDataByMonth = {}; + this.marketDataByMonth = {}; - for (const marketDataItem of marketDataItems) { - const currentDay = parseInt(format(marketDataItem.date, 'd'), 10); - const key = format(marketDataItem.date, 'yyyy-MM'); + for (const marketDataItem of marketDataItems) { + const currentDay = parseInt(format(marketDataItem.date, 'd'), 10); + const key = format(marketDataItem.date, 'yyyy-MM'); - if (!this.marketDataByMonth[key]) { - this.marketDataByMonth[key] = {}; - } + if (!this.marketDataByMonth[key]) { + this.marketDataByMonth[key] = {}; + } - this.marketDataByMonth[key][ - currentDay < 10 ? `0${currentDay}` : currentDay - ] = { - date: marketDataItem.date, - day: currentDay, - marketPrice: marketDataItem.marketPrice - }; - } + this.marketDataByMonth[key][ + currentDay < 10 ? `0${currentDay}` : currentDay + ] = { + date: marketDataItem.date, + day: currentDay, + marketPrice: marketDataItem.marketPrice + }; + } - if (this.dateOfFirstActivity) { // Fill up missing months const dates = Object.keys(this.marketDataByMonth).sort(); const startDate = min([ From 8c322b4e817075ff2510324aaa07ad8b53b8cd55 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 7 Sep 2024 21:21:02 +0200 Subject: [PATCH 24/78] Bugfix/fix historical market data gathering in yahoo finance service (#3737) * Switch from historical() to chart() * Update changelog --- CHANGELOG.md | 1 + .../yahoo-finance/yahoo-finance.service.ts | 62 +++++++++++++------ 2 files changed, 43 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a1bb6525f..5f1102d92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed an issue in the view mode toggle of the holdings tab on the home page (experimental) - Fixed an issue on the portfolio activities page by loading the data only once - Fixed an issue in the carousel component for the testimonial section on the landing page +- Fixed the historical market data gathering in the _Yahoo Finance_ service by switching from `historical()` to `chart()` - Handled an exception in the historical market data component of the asset profile details dialog in the admin control panel ## 2.105.0 - 2024-08-21 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 e0d88f0c6..a8f7d261e 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 @@ -20,6 +20,11 @@ import { Injectable, Logger } from '@nestjs/common'; import { DataSource, SymbolProfile } from '@prisma/client'; import { addDays, format, isSameDay } from 'date-fns'; import yahooFinance from 'yahoo-finance2'; +import { ChartResultArray } from 'yahoo-finance2/dist/esm/src/modules/chart'; +import { + HistoricalDividendsResult, + HistoricalHistoryResult +} from 'yahoo-finance2/dist/esm/src/modules/historical'; import { Quote } from 'yahoo-finance2/dist/esm/src/modules/quote'; @Injectable() @@ -60,18 +65,19 @@ export class YahooFinanceService implements DataProviderInterface { } try { - const historicalResult = await yahooFinance.historical( - this.yahooFinanceDataEnhancerService.convertToYahooFinanceSymbol( - symbol - ), - { - events: 'dividends', - interval: granularity === 'month' ? '1mo' : '1d', - period1: format(from, DATE_FORMAT), - period2: format(to, DATE_FORMAT) - } + const historicalResult = this.convertToDividendResult( + await yahooFinance.chart( + this.yahooFinanceDataEnhancerService.convertToYahooFinanceSymbol( + symbol + ), + { + events: 'dividends', + interval: granularity === 'month' ? '1mo' : '1d', + period1: format(from, DATE_FORMAT), + period2: format(to, DATE_FORMAT) + } + ) ); - const response: { [date: string]: IDataProviderHistoricalResponse; } = {}; @@ -108,15 +114,17 @@ export class YahooFinanceService implements DataProviderInterface { } try { - const historicalResult = await yahooFinance.historical( - this.yahooFinanceDataEnhancerService.convertToYahooFinanceSymbol( - symbol - ), - { - interval: '1d', - period1: format(from, DATE_FORMAT), - period2: format(to, DATE_FORMAT) - } + const historicalResult = this.convertToHistoricalResult( + await yahooFinance.chart( + this.yahooFinanceDataEnhancerService.convertToYahooFinanceSymbol( + symbol + ), + { + interval: '1d', + period1: format(from, DATE_FORMAT), + period2: format(to, DATE_FORMAT) + } + ) ); const response: { @@ -302,6 +310,20 @@ export class YahooFinanceService implements DataProviderInterface { return { items }; } + private convertToDividendResult( + result: ChartResultArray + ): HistoricalDividendsResult { + return result.events.dividends.map(({ amount: dividends, date }) => { + return { date, dividends }; + }); + } + + private convertToHistoricalResult( + result: ChartResultArray + ): HistoricalHistoryResult { + return result.quotes; + } + private async getQuotesWithQuoteSummary(aYahooFinanceSymbols: string[]) { const quoteSummaryPromises = aYahooFinanceSymbols.map((symbol) => { return yahooFinance.quoteSummary(symbol).catch(() => { From 1bc2b474527ff625db443f2ddb5f56af4b25aeb2 Mon Sep 17 00:00:00 2001 From: Shaunak Das <51281688+shaun-ak@users.noreply.github.com> Date: Sun, 8 Sep 2024 00:52:56 +0530 Subject: [PATCH 25/78] Feature/setup skeleton loader for data tables (#3735) * Setup skeleton loader for data tables * Update changelog --- CHANGELOG.md | 2 ++ .../app/components/admin-jobs/admin-jobs.component.ts | 5 +++++ .../src/app/components/admin-jobs/admin-jobs.html | 10 ++++++++++ .../src/app/components/admin-jobs/admin-jobs.module.ts | 2 ++ .../components/admin-users/admin-users.component.ts | 5 +++++ .../src/app/components/admin-users/admin-users.html | 10 ++++++++++ .../app/components/admin-users/admin-users.module.ts | 4 +++- 7 files changed, 37 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f1102d92..56ac6210d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Set up a performance logging service +- Added a loading indicator to the queue jobs table in the admin control panel +- Added a loading indicator to the users table in the admin control panel - Added the attribute `mode` to the scraper configuration to get quotes instantly ### Changed diff --git a/apps/client/src/app/components/admin-jobs/admin-jobs.component.ts b/apps/client/src/app/components/admin-jobs/admin-jobs.component.ts index 820b3651d..e828049bc 100644 --- a/apps/client/src/app/components/admin-jobs/admin-jobs.component.ts +++ b/apps/client/src/app/components/admin-jobs/admin-jobs.component.ts @@ -51,6 +51,7 @@ export class AdminJobsComponent implements OnDestroy, OnInit { 'status', 'actions' ]; + public isLoading = false; public statusFilterOptions = QUEUE_JOB_STATUS_LIST; public user: User; @@ -138,12 +139,16 @@ export class AdminJobsComponent implements OnDestroy, OnInit { } private fetchJobs(aStatus?: JobStatus[]) { + this.isLoading = true; + this.adminService .fetchJobs({ status: aStatus }) .pipe(takeUntil(this.unsubscribeSubject)) .subscribe(({ jobs }) => { this.dataSource = new MatTableDataSource(jobs); + this.isLoading = false; + this.changeDetectorRef.markForCheck(); }); } diff --git a/apps/client/src/app/components/admin-jobs/admin-jobs.html b/apps/client/src/app/components/admin-jobs/admin-jobs.html index 9ea2097e2..e194b2b37 100644 --- a/apps/client/src/app/components/admin-jobs/admin-jobs.html +++ b/apps/client/src/app/components/admin-jobs/admin-jobs.html @@ -183,6 +183,16 @@ + @if (isLoading) { + + }
diff --git a/apps/client/src/app/components/admin-jobs/admin-jobs.module.ts b/apps/client/src/app/components/admin-jobs/admin-jobs.module.ts index fe717b904..cca66a04a 100644 --- a/apps/client/src/app/components/admin-jobs/admin-jobs.module.ts +++ b/apps/client/src/app/components/admin-jobs/admin-jobs.module.ts @@ -5,6 +5,7 @@ import { MatButtonModule } from '@angular/material/button'; import { MatMenuModule } from '@angular/material/menu'; import { MatSelectModule } from '@angular/material/select'; import { MatTableModule } from '@angular/material/table'; +import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; import { AdminJobsComponent } from './admin-jobs.component'; @@ -17,6 +18,7 @@ import { AdminJobsComponent } from './admin-jobs.component'; MatMenuModule, MatSelectModule, MatTableModule, + NgxSkeletonLoaderModule, ReactiveFormsModule ], schemas: [CUSTOM_ELEMENTS_SCHEMA] diff --git a/apps/client/src/app/components/admin-users/admin-users.component.ts b/apps/client/src/app/components/admin-users/admin-users.component.ts index 0a66977bf..4a419dd6c 100644 --- a/apps/client/src/app/components/admin-users/admin-users.component.ts +++ b/apps/client/src/app/components/admin-users/admin-users.component.ts @@ -32,6 +32,7 @@ export class AdminUsersComponent implements OnDestroy, OnInit { public hasPermissionForSubscription: boolean; public hasPermissionToImpersonateAllUsers: boolean; public info: InfoItem; + public isLoading = false; public user: User; private unsubscribeSubject = new Subject(); @@ -142,12 +143,16 @@ export class AdminUsersComponent implements OnDestroy, OnInit { } private fetchAdminData() { + this.isLoading = true; + this.adminService .fetchAdminData() .pipe(takeUntil(this.unsubscribeSubject)) .subscribe(({ users }) => { this.dataSource = new MatTableDataSource(users); + this.isLoading = false; + this.changeDetectorRef.markForCheck(); }); } diff --git a/apps/client/src/app/components/admin-users/admin-users.html b/apps/client/src/app/components/admin-users/admin-users.html index 25ab9053d..b65b7c821 100644 --- a/apps/client/src/app/components/admin-users/admin-users.html +++ b/apps/client/src/app/components/admin-users/admin-users.html @@ -245,6 +245,16 @@ >
+ @if (isLoading) { + + }
diff --git a/apps/client/src/app/components/admin-users/admin-users.module.ts b/apps/client/src/app/components/admin-users/admin-users.module.ts index 3f4e9f2f7..fcf25c8b5 100644 --- a/apps/client/src/app/components/admin-users/admin-users.module.ts +++ b/apps/client/src/app/components/admin-users/admin-users.module.ts @@ -6,6 +6,7 @@ import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MatMenuModule } from '@angular/material/menu'; import { MatTableModule } from '@angular/material/table'; +import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; import { AdminUsersComponent } from './admin-users.component'; @@ -18,7 +19,8 @@ import { AdminUsersComponent } from './admin-users.component'; GfValueComponent, MatButtonModule, MatMenuModule, - MatTableModule + MatTableModule, + NgxSkeletonLoaderModule ], schemas: [CUSTOM_ELEMENTS_SCHEMA] }) From 728f84e7eb960a81417940ed4bfd6f4034f4a699 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 7 Sep 2024 21:24:33 +0200 Subject: [PATCH 26/78] Release 2.106.0 (#3738) --- CHANGELOG.md | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56ac6210d..f91b3b62e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## 2.106.0-beta.6 +## 2.106.0 - 2024-09-07 ### Added diff --git a/package.json b/package.json index 79ed8f8c1..81eb3859f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "2.106.0-beta.6", + "version": "2.106.0", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "repository": "https://github.com/ghostfolio/ghostfolio", From 9cd4321bd02c2f3cb6eaf7010c020882937a0d84 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 8 Sep 2024 09:56:08 +0200 Subject: [PATCH 27/78] Feature/extract users from admin control panel endpoint to dedicated endpoint (#3740) * Introduce GET api/v1/admin/user endpoint * Update changelog --- CHANGELOG.md | 6 ++++++ apps/api/src/app/admin/admin.controller.ts | 8 ++++++++ apps/api/src/app/admin/admin.service.ts | 10 +++++++--- .../admin-users/admin-users.component.ts | 12 ++++++------ apps/client/src/app/services/admin.service.ts | 5 +++++ .../src/lib/interfaces/admin-data.interface.ts | 12 ------------ .../src/lib/interfaces/admin-users.interface.ts | 14 ++++++++++++++ libs/common/src/lib/interfaces/index.ts | 2 ++ 8 files changed, 48 insertions(+), 21 deletions(-) create mode 100644 libs/common/src/lib/interfaces/admin-users.interface.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index f91b3b62e..eae074550 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 + +- Extracted the users from the admin control panel endpoint to a dedicated endpoint + ## 2.106.0 - 2024-09-07 ### Added diff --git a/apps/api/src/app/admin/admin.controller.ts b/apps/api/src/app/admin/admin.controller.ts index 6d201be23..da4b5dd7e 100644 --- a/apps/api/src/app/admin/admin.controller.ts +++ b/apps/api/src/app/admin/admin.controller.ts @@ -17,6 +17,7 @@ import { AdminData, AdminMarketData, AdminMarketDataDetails, + AdminUsers, EnhancedSymbolProfile } from '@ghostfolio/common/interfaces'; import { permissions } from '@ghostfolio/common/permissions'; @@ -347,4 +348,11 @@ export class AdminController { ) { return this.adminService.putSetting(key, data.value); } + + @Get('user') + @HasPermission(permissions.accessAdminControl) + @UseGuards(AuthGuard('jwt'), HasPermissionGuard) + public async getUsers(): Promise { + return this.adminService.getUsers(); + } } diff --git a/apps/api/src/app/admin/admin.service.ts b/apps/api/src/app/admin/admin.service.ts index 50b781f54..3f5274285 100644 --- a/apps/api/src/app/admin/admin.service.ts +++ b/apps/api/src/app/admin/admin.service.ts @@ -21,6 +21,7 @@ import { AdminMarketData, AdminMarketDataDetails, AdminMarketDataItem, + AdminUsers, AssetProfileIdentifier, EnhancedSymbolProfile, Filter @@ -135,7 +136,6 @@ export class AdminService { settings: await this.propertyService.get(), transactionCount: await this.prismaService.order.count(), userCount: await this.prismaService.user.count(), - users: await this.getUsersWithAnalytics(), version: environment.version }; } @@ -377,6 +377,10 @@ export class AdminService { }; } + public async getUsers(): Promise { + return { users: await this.getUsersWithAnalytics() }; + } + public async patchAssetProfileData({ assetClass, assetSubClass, @@ -546,11 +550,11 @@ export class AdminService { return { marketData, count: marketData.length }; } - private async getUsersWithAnalytics(): Promise { + private async getUsersWithAnalytics(): Promise { let orderBy: any = { createdAt: 'desc' }; - let where; + let where: Prisma.UserWhereInput; if (this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION')) { orderBy = { diff --git a/apps/client/src/app/components/admin-users/admin-users.component.ts b/apps/client/src/app/components/admin-users/admin-users.component.ts index 4a419dd6c..c5264c3b3 100644 --- a/apps/client/src/app/components/admin-users/admin-users.component.ts +++ b/apps/client/src/app/components/admin-users/admin-users.component.ts @@ -5,7 +5,7 @@ import { DataService } from '@ghostfolio/client/services/data.service'; import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { getDateFormatString, getEmojiFlag } from '@ghostfolio/common/helper'; -import { AdminData, InfoItem, User } from '@ghostfolio/common/interfaces'; +import { AdminUsers, InfoItem, User } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; @@ -24,7 +24,7 @@ import { takeUntil } from 'rxjs/operators'; templateUrl: './admin-users.html' }) export class AdminUsersComponent implements OnDestroy, OnInit { - public dataSource: MatTableDataSource = + public dataSource: MatTableDataSource = new MatTableDataSource(); public defaultDateFormat: string; public displayedColumns: string[] = []; @@ -94,7 +94,7 @@ export class AdminUsersComponent implements OnDestroy, OnInit { } public ngOnInit() { - this.fetchAdminData(); + this.fetchUsers(); } public formatDistanceToNow(aDateString: string) { @@ -119,7 +119,7 @@ export class AdminUsersComponent implements OnDestroy, OnInit { .deleteUser(aId) .pipe(takeUntil(this.unsubscribeSubject)) .subscribe(() => { - this.fetchAdminData(); + this.fetchUsers(); }); }, confirmType: ConfirmationDialogType.Warn, @@ -142,11 +142,11 @@ export class AdminUsersComponent implements OnDestroy, OnInit { this.unsubscribeSubject.complete(); } - private fetchAdminData() { + private fetchUsers() { this.isLoading = true; this.adminService - .fetchAdminData() + .fetchUsers() .pipe(takeUntil(this.unsubscribeSubject)) .subscribe(({ users }) => { this.dataSource = new MatTableDataSource(users); diff --git a/apps/client/src/app/services/admin.service.ts b/apps/client/src/app/services/admin.service.ts index e5ea176d1..4c011e8c1 100644 --- a/apps/client/src/app/services/admin.service.ts +++ b/apps/client/src/app/services/admin.service.ts @@ -12,6 +12,7 @@ import { AdminJobs, AdminMarketData, AdminMarketDataDetails, + AdminUsers, EnhancedSymbolProfile, Filter } from '@ghostfolio/common/interfaces'; @@ -155,6 +156,10 @@ export class AdminService { return this.http.get('/api/v1/tag'); } + public fetchUsers() { + return this.http.get('/api/v1/admin/user'); + } + public gather7Days() { return this.http.post('/api/v1/admin/gather', {}); } diff --git a/libs/common/src/lib/interfaces/admin-data.interface.ts b/libs/common/src/lib/interfaces/admin-data.interface.ts index 6b139026b..3dc476df8 100644 --- a/libs/common/src/lib/interfaces/admin-data.interface.ts +++ b/libs/common/src/lib/interfaces/admin-data.interface.ts @@ -1,7 +1,5 @@ import { AssetProfileIdentifier } from '@ghostfolio/common/interfaces'; -import { Role } from '@prisma/client'; - export interface AdminData { exchangeRates: ({ label1: string; @@ -11,15 +9,5 @@ export interface AdminData { settings: { [key: string]: boolean | object | string | string[] }; transactionCount: number; userCount: number; - users: { - accountCount: number; - country: string; - createdAt: Date; - engagement: number; - id: string; - lastActivity: Date; - role: Role; - transactionCount: number; - }[]; version: string; } diff --git a/libs/common/src/lib/interfaces/admin-users.interface.ts b/libs/common/src/lib/interfaces/admin-users.interface.ts new file mode 100644 index 000000000..24eb45c85 --- /dev/null +++ b/libs/common/src/lib/interfaces/admin-users.interface.ts @@ -0,0 +1,14 @@ +import { Role } from '@prisma/client'; + +export interface AdminUsers { + users: { + accountCount: number; + country: string; + createdAt: Date; + engagement: number; + id: string; + lastActivity: Date; + role: Role; + transactionCount: number; + }[]; +} diff --git a/libs/common/src/lib/interfaces/index.ts b/libs/common/src/lib/interfaces/index.ts index f7224407b..efab780fd 100644 --- a/libs/common/src/lib/interfaces/index.ts +++ b/libs/common/src/lib/interfaces/index.ts @@ -7,6 +7,7 @@ import type { AdminMarketData, AdminMarketDataItem } from './admin-market-data.interface'; +import type { AdminUsers } from './admin-users.interface'; import type { AssetProfileIdentifier } from './asset-profile-identifier.interface'; import type { BenchmarkMarketDataDetails } from './benchmark-market-data-details.interface'; import type { BenchmarkProperty } from './benchmark-property.interface'; @@ -61,6 +62,7 @@ export { AdminMarketData, AdminMarketDataDetails, AdminMarketDataItem, + AdminUsers, AssetProfileIdentifier, Benchmark, BenchmarkMarketDataDetails, From bdb3a8f1dc5f89ebda2f081320a2033c774a0ded Mon Sep 17 00:00:00 2001 From: Andrea Date: Sun, 8 Sep 2024 21:41:41 +0200 Subject: [PATCH 28/78] Feature/improve language localization for Italian (#3744) * Update translations * Update changelog --- CHANGELOG.md | 1 + apps/client/src/locales/messages.it.xlf | 326 ++++++++++++------------ 2 files changed, 164 insertions(+), 163 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eae074550..510ccddf6 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 - Extracted the users from the admin control panel endpoint to a dedicated endpoint +- Improved the language localization for Italian (`it`) ## 2.106.0 - 2024-09-07 diff --git a/apps/client/src/locales/messages.it.xlf b/apps/client/src/locales/messages.it.xlf index e8fb9e562..592df3152 100644 --- a/apps/client/src/locales/messages.it.xlf +++ b/apps/client/src/locales/messages.it.xlf @@ -404,7 +404,7 @@
Asset Profiles - Profilo dell’asset + Profilo dell’asset libs/ui/src/lib/assistant/assistant.html 67 @@ -412,7 +412,7 @@ Historical Market Data - Dati storici del mercato + Dati storici del mercato apps/client/src/app/components/admin-jobs/admin-jobs.html 37 @@ -796,7 +796,7 @@ Last Request - Ultima richiesta + Ultima richiesta apps/client/src/app/components/admin-users/admin-users.html 181 @@ -1768,7 +1768,7 @@ Sign in with fingerprint - Accesso con impronta digitale + Accesso con impronta digitale apps/client/src/app/components/user-account-settings/user-account-settings.html 191 @@ -3460,7 +3460,7 @@ Protection for sensitive information like absolute performances and quantity values - Protezione delle informazioni sensibili come le prestazioni assolute e i valori quantitativi + Protezione delle informazioni sensibili come le prestazioni assolute e i valori quantitativi apps/client/src/app/components/user-account-settings/user-account-settings.html 8 @@ -3468,7 +3468,7 @@ Distraction-free experience for turbulent times - Esperienza priva di distrazioni per i periodi più turbolenti + Esperienza priva di distrazioni per i periodi più turbolenti apps/client/src/app/components/user-account-settings/user-account-settings.html 174 @@ -3476,7 +3476,7 @@ Sneak peek at upcoming functionality - Un’anteprima delle funzionalità in arrivo + Un’anteprima delle funzionalità in arrivo apps/client/src/app/components/user-account-settings/user-account-settings.html 208 @@ -3660,7 +3660,7 @@ For new investors who are just getting started with trading. - Per i nuovi investitori che hanno appena iniziato a fare trading. + Per i nuovi investitori che hanno appena iniziato a fare trading. apps/client/src/app/pages/pricing/pricing-page.html 123 @@ -3688,7 +3688,7 @@ One-time payment, no auto-renewal. - Pagamento una tantum, senza rinnovo automatico. + Pagamento una tantum, senza rinnovo automatico. apps/client/src/app/pages/pricing/pricing-page.html 280 @@ -3864,7 +3864,7 @@ Renew Plan - Rinnova il piano + Rinnova il piano apps/client/src/app/components/header/header.component.html 183 @@ -3880,7 +3880,7 @@ Our official Ghostfolio Premium cloud offering is the easiest way to get started. Due to the time it saves, this will be the best option for most people. Revenue is used to cover the costs of the hosting infrastructure and to fund ongoing development. - La nostra offerta cloud ufficiale Ghostfolio Premium è il modo più semplice per iniziare. Grazie al risparmio di tempo, questa è l’opzione migliore per la maggior parte delle persone. I ricavi vengono utilizzati per coprire l’infrastruttura di hosting e per finanziare lo sviluppo continuo di Ghostfolio. + La nostra offerta cloud ufficiale Ghostfolio Premium è il modo più semplice per iniziare. Grazie al risparmio di tempo, questa è l’opzione migliore per la maggior parte delle persone. I ricavi vengono utilizzati per coprire l’infrastruttura di hosting e per finanziare lo sviluppo continuo di Ghostfolio. apps/client/src/app/pages/pricing/pricing-page.html 6 @@ -3904,7 +3904,7 @@ Do you really want to delete these activities? - Vuoi davvero eliminare tutte le tue attività? + Vuoi davvero eliminare tutte le tue attività? libs/ui/src/lib/activities-table/activities-table.component.ts 225 @@ -4744,7 +4744,7 @@ New Users - Nuovi utenti + Nuovi utenti apps/client/src/app/pages/open/open-page.html 51 @@ -5132,7 +5132,7 @@ Are you ready? - Seipronto? + Sei pronto? apps/client/src/app/pages/landing/landing-page.html 431 @@ -5584,7 +5584,7 @@ Open Source Alternative to - L’alternativa open source a + L’alternativa open source a apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.html 42 @@ -5624,7 +5624,7 @@ Let’s dive deeper into the detailed Ghostfolio vs comparison table below to gain a thorough understanding of how Ghostfolio positions itself relative to . We will explore various aspects such as features, data privacy, pricing, and more, allowing you to make a well-informed choice for your personal requirements. - Analizziamo nel dettaglio la tabella di confronto qui sotto per comprendere a fondo come Ghostfolio si posiziona rispetto a . Esploreremo vari aspetti come le caratteristiche, la privacy dei dati, il prezzo e altro ancora, permettendoti di fare una scelta ben informata per le tue esigenze personali. + Analizziamo nel dettaglio la tabella di confronto qui sotto per comprendere a fondo come Ghostfolio si posiziona rispetto a . Esploreremo vari aspetti come le caratteristiche, la privacy dei dati, il prezzo e altro ancora, permettendoti di fare una scelta ben informata per le tue esigenze personali. apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 38 @@ -5644,7 +5644,7 @@ Please note that the information provided in the Ghostfolio vs comparison table is based on our independent research and analysis. This website is not affiliated with or any other product mentioned in the comparison. As the landscape of personal finance tools evolves, it is essential to verify any specific details or changes directly from the respective product page. Data needs a refresh? Help us maintain accurate data on GitHub. - Nota bene: le informazioni fornite si basano sulle nostre ricerche e analisi indipendenti. Questo sito web non è affiliato con o a qualsiasi altro prodotto citato nel confronto. Poiché il panorama degli strumenti di finanza personale si evolve, è essenziale verificare qualsiasi dettaglio o modifica specifica direttamente nella pagina del prodotto in questione. I dati hanno bisogno di essere aggiornati? Aiutaci a mantenere i dati accurati su GitHub. + Nota bene: le informazioni fornite si basano sulle nostre ricerche e analisi indipendenti. Questo sito web non è affiliato con o a qualsiasi altro prodotto citato nel confronto. Poiché il panorama degli strumenti di finanza personale si evolve, è essenziale verificare qualsiasi dettaglio o modifica specifica direttamente nella pagina del prodotto in questione. I dati hanno bisogno di essere aggiornati? Aiutaci a mantenere i dati accurati su GitHub. apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 226 @@ -5720,7 +5720,7 @@ Choose or drop a file here - Choose or drop a file here + Seleziona o trascina qui un file apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.html 84 @@ -5728,7 +5728,7 @@ You are using the Live Demo. - You are using the Live Demo. + Stai usando la Live Demo. apps/client/src/app/app.component.html 12 @@ -5736,7 +5736,7 @@ One-time fee, annual account fees - One-time fee, annual account fees + Commissione una tantum, commissioni annuali per l'account apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html 33 @@ -5744,7 +5744,7 @@ Distribution of corporate earnings - Distribution of corporate earnings + A distribuzione dei dividendi apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html 41 @@ -5752,7 +5752,7 @@ Oops! Could not get the historical exchange rate from - Oops! Could not get the historical exchange rate from + Ops! Impossibile ottenere il tasso di cambio storico da apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html 318 @@ -5760,7 +5760,7 @@ Fee - Fee + Commissione libs/ui/src/lib/i18n.ts 36 @@ -5768,7 +5768,7 @@ Interest - Interest + Interesse apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html 331 @@ -5776,7 +5776,7 @@ Revenue for lending out money - Revenue for lending out money + Ricavi dal prestito di soldi apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html 49 @@ -5784,7 +5784,7 @@ Add Tag - Add Tag + Aggiungi un Tag apps/client/src/app/components/admin-tag/admin-tag.component.html 11 @@ -5792,7 +5792,7 @@ Do you really want to delete this tag? - Do you really want to delete this tag? + Sei sicuro di voler eliminare questo tag? apps/client/src/app/components/admin-tag/admin-tag.component.ts 86 @@ -5800,7 +5800,7 @@ Update tag - Update tag + Aggiorna il tag apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.html 8 @@ -5808,7 +5808,7 @@ Add tag - Add tag + Aggiungi un tag apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.html 10 @@ -5816,7 +5816,7 @@ Ghostfolio X-ray uses static analysis to identify potential issues and risks in your portfolio. - Ghostfolio X-ray uses static analysis to identify potential issues and risks in your portfolio. + Ghostfolio X-ray usa l'analisi statica per identificare potenziali problemi e rischi del tuo portafoglio. apps/client/src/app/pages/portfolio/fire/fire-page.html 111 @@ -5840,7 +5840,7 @@ Transfer Cash Balance - Transfer Cash Balance + Trasferisci il saldo di cassa apps/client/src/app/components/accounts-table/accounts-table.component.html 10 @@ -5852,7 +5852,7 @@ Benchmark - Benchmark + Benchmark apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 286 @@ -5860,7 +5860,7 @@ Version - Version + Versione apps/client/src/app/components/admin-overview/admin-overview.html 7 @@ -5868,7 +5868,7 @@ Settings - Settings + Impostazioni apps/client/src/app/components/user-account-settings/user-account-settings.html 2 @@ -5876,7 +5876,7 @@ From - From + Da apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.html 11 @@ -5884,7 +5884,7 @@ To - To + A apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.html 32 @@ -5892,7 +5892,7 @@ Transfer - Transfer + Trasferisci apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.html 72 @@ -5900,7 +5900,7 @@ Membership - Membership + Iscrizione apps/client/src/app/pages/user-account/user-account-page-routing.module.ts 23 @@ -5912,7 +5912,7 @@ Access - Access + Accesso apps/client/src/app/pages/user-account/user-account-page-routing.module.ts 28 @@ -5924,7 +5924,7 @@ Find holding... - Find holding... + Trova possedimenti... libs/ui/src/lib/assistant/assistant.component.ts 138 @@ -5932,7 +5932,7 @@ No entries... - No entries... + Nessun risultato... libs/ui/src/lib/assistant/assistant.html 63 @@ -5944,7 +5944,7 @@ Asset Profile - Asset Profile + Profilo dell'asset apps/client/src/app/components/admin-jobs/admin-jobs.html 35 @@ -5952,7 +5952,7 @@ Do you really want to delete this asset profile? - Do you really want to delete this asset profile? + Vuoi veramente eliminare il profilo di questo asset? apps/client/src/app/components/admin-market-data/admin-market-data.service.ts 33 @@ -5960,7 +5960,7 @@ Search - Search + Cerca apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html 16 @@ -5968,7 +5968,7 @@ Add Manually - Add Manually + Aggiungi manualmente apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html 19 @@ -5976,7 +5976,7 @@ Ghostfolio is a personal finance dashboard to keep track of your net worth including cash, stocks, ETFs and cryptocurrencies across multiple platforms. - Ghostfolio è un dashboard di finanza personale per tenere traccia delle vostre attività come azioni, ETF o criptovalute su più piattaforme. + Ghostfolio è un dashboard di finanza personale per tenere traccia delle vostre attività come azioni, ETF o criptovalute su più piattaforme. apps/client/src/app/pages/i18n/i18n-page.html 4 @@ -5984,7 +5984,7 @@ Last All Time High - Last All Time High + Ultimo massimo storico libs/ui/src/lib/benchmark/benchmark.component.html 65 @@ -5992,7 +5992,7 @@ User - User + Utente apps/client/src/app/components/admin-users/admin-users.html 29 @@ -6008,7 +6008,7 @@ Open Source Wealth Management Software - Open Source Wealth Management Software + Software Open Source per la gestione della tua ricchezza apps/client/src/app/pages/i18n/i18n-page.html 14 @@ -6016,7 +6016,7 @@ app, asset, cryptocurrency, dashboard, etf, finance, management, performance, portfolio, software, stock, trading, wealth, web3 - app, asset, cryptocurrency, dashboard, etf, finance, management, performance, portfolio, software, stock, trading, wealth, web3 + app, asset, crypto, dashboard, etf, finanza, gestione patrimoniale, rendimenti, portafoglio, software, stock, azioni, titoli, obbligazioni, trading, ricchezza, web3 apps/client/src/app/pages/i18n/i18n-page.html 9 @@ -6024,7 +6024,7 @@ Oops, cash balance transfer has failed. - Oops, cash balance transfer has failed. + Ops, il trasferimento del saldo di cassa è fallito. apps/client/src/app/pages/accounts/accounts-page.component.ts 311 @@ -6032,7 +6032,7 @@ Extreme Fear - Extreme Fear + Paura estrema libs/ui/src/lib/i18n.ts 94 @@ -6040,7 +6040,7 @@ Extreme Greed - Extreme Greed + Avidità estrema libs/ui/src/lib/i18n.ts 95 @@ -6048,7 +6048,7 @@ Neutral - Neutral + Neutrale libs/ui/src/lib/i18n.ts 98 @@ -6056,7 +6056,7 @@ Oops! Could not parse historical data. - Oops! Could not parse historical data. + Ops! Impossibile elaborare i dati storici. apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 237 @@ -6064,7 +6064,7 @@ Do you really want to delete this system message? - Do you really want to delete this system message? + Confermi di voler cancellare questo messaggio di sistema? apps/client/src/app/components/admin-overview/admin-overview.component.ts 178 @@ -6072,7 +6072,7 @@ 50-Day Trend - 50-Day Trend + Trend a 50 giorni libs/ui/src/lib/benchmark/benchmark.component.html 15 @@ -6080,7 +6080,7 @@ 200-Day Trend - 200-Day Trend + Trend a 200 giorni libs/ui/src/lib/benchmark/benchmark.component.html 40 @@ -6088,7 +6088,7 @@ Cash Balances - Cash Balances + Saldi di cassa apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html 122 @@ -6096,7 +6096,7 @@ Starting from - Starting from + Inizia da apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 204 @@ -6108,7 +6108,7 @@ year - year + anno apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 205 @@ -6120,7 +6120,7 @@ Do you really want to delete this account balance? - Do you really want to delete this account balance? + Vuoi veramente elimnare il saldo di questo conto? libs/ui/src/lib/account-balances/account-balances.component.ts 110 @@ -6128,7 +6128,7 @@ is an invalid currency! - is an invalid currency! + non è una valuta valida! apps/client/src/app/components/admin-overview/admin-overview.component.ts 133 @@ -6136,7 +6136,7 @@ If a translation is missing, kindly support us in extending it here. - If a translation is missing, kindly support us in extending it here. + Se manca una traduzione, puoi aiutarci modificando questo file: here. apps/client/src/app/components/user-account-settings/user-account-settings.html 50 @@ -6144,7 +6144,7 @@ The current market price is - The current market price is + L'attuale prezzo di mercato è apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 345 @@ -6152,7 +6152,7 @@ Test - Test + Prova apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 322 @@ -6160,7 +6160,7 @@ Date Range - Date Range + Intervallo di date libs/ui/src/lib/assistant/assistant.html 93 @@ -6168,7 +6168,7 @@ Permission - Permission + Permessi apps/client/src/app/components/access-table/access-table.component.html 18 @@ -6192,7 +6192,7 @@ Oops! Could not grant access. - Oops! Could not grant access. + Ops! Impossibile abilitare l'accesso. apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts 91 @@ -6200,7 +6200,7 @@ Private - Private + Privato apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 24 @@ -6208,7 +6208,7 @@ Job Queue - Job Queue + Coda Lavori apps/client/src/app/pages/admin/admin-page-routing.module.ts 25 @@ -6220,7 +6220,7 @@ Market data is delayed for - Market data is delayed for + I dati di mercato sono ritardati di apps/client/src/app/components/portfolio-performance/portfolio-performance.component.ts 86 @@ -6228,7 +6228,7 @@ Investment - Investment + Investimento apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts 42 @@ -6244,7 +6244,7 @@ Absolute Asset Performance - Absolute Asset Performance + Rendimento assoluto dell'Asset apps/client/src/app/pages/portfolio/analysis/analysis-page.html 29 @@ -6252,7 +6252,7 @@ Asset Performance - Asset Performance + Rendimento dell'Asset apps/client/src/app/pages/portfolio/analysis/analysis-page.html 50 @@ -6260,7 +6260,7 @@ Absolute Currency Performance - Absolute Currency Performance + Rendimento assoluto della Valuta apps/client/src/app/pages/portfolio/analysis/analysis-page.html 72 @@ -6268,7 +6268,7 @@ Currency Performance - Currency Performance + Rendimento della Valuta apps/client/src/app/pages/portfolio/analysis/analysis-page.html 96 @@ -6276,7 +6276,7 @@ Absolute Net Performance - Absolute Net Performance + Rendimento assoluto della Valuta apps/client/src/app/pages/portfolio/analysis/analysis-page.html 119 @@ -6284,7 +6284,7 @@ Net Performance - Net Performance + Rendimento Netto apps/client/src/app/pages/portfolio/analysis/analysis-page.html 138 @@ -6292,7 +6292,7 @@ Week to date - Week to date + Da inizio settimana libs/ui/src/lib/assistant/assistant.component.ts 217 @@ -6308,7 +6308,7 @@ Month to date - Month to date + Da inizio mese libs/ui/src/lib/assistant/assistant.component.ts 221 @@ -6324,7 +6324,7 @@ Year to date - Year to date + Da inizio anno libs/ui/src/lib/assistant/assistant.component.ts 225 @@ -6332,7 +6332,7 @@ View - View + Visualizza apps/client/src/app/components/access-table/access-table.component.html 23 @@ -6344,7 +6344,7 @@ Oops! A data provider is experiencing the hiccups. - Oops! A data provider is experiencing the hiccups. + Ops! Un data provider sta riscontrando dei problemi. apps/client/src/app/components/portfolio-performance/portfolio-performance.component.html 8 @@ -6352,7 +6352,7 @@ If you retire today, you would be able to withdraw per year or per month, based on your total assets of and a withdrawal rate of 4%. - If you retire today, you would be able to withdraw per year or per month, based on your total assets of and a withdrawal rate of 4%. + Se andassi in pensione oggi, saresti in grado di prelevare all'anno o al mese, calcolato sul valore totale dei tuoi asset di e un prelievo costante del 4%. apps/client/src/app/pages/portfolio/fire/fire-page.html 67 @@ -6360,7 +6360,7 @@ Reset Filters - Reset Filters + Reset Filtri libs/ui/src/lib/assistant/assistant.html 155 @@ -6368,7 +6368,7 @@ year - year + anno libs/ui/src/lib/assistant/assistant.component.ts 229 @@ -6376,7 +6376,7 @@ years - years + anni libs/ui/src/lib/assistant/assistant.component.ts 250 @@ -6384,7 +6384,7 @@ Asset Classes - Asset Classes + classi degli Asset libs/ui/src/lib/assistant/assistant.html 138 @@ -6392,7 +6392,7 @@ Apply Filters - Apply Filters + Applica i Filtri libs/ui/src/lib/assistant/assistant.html 165 @@ -6400,7 +6400,7 @@ Data Gathering - Data Gathering + Raccolta Dati apps/client/src/app/components/admin-overview/admin-overview.html 136 @@ -6408,7 +6408,7 @@ General - General + Generale apps/client/src/app/pages/faq/faq-page.component.ts 36 @@ -6416,7 +6416,7 @@ Cloud - Cloud + Cloud apps/client/src/app/pages/faq/faq-page.component.ts 41 @@ -6428,7 +6428,7 @@ Self-Hosting - Self-Hosting + Self-Hosting apps/client/src/app/pages/faq/faq-page.component.ts 47 @@ -6440,7 +6440,7 @@ self-hosting - self-hosting + self-hosting apps/client/src/app/pages/faq/faq-page.component.ts 48 @@ -6448,7 +6448,7 @@ FAQ - FAQ + FAQ apps/client/src/app/pages/faq/saas/saas-page-routing.module.ts 13 @@ -6460,7 +6460,7 @@ Oops! It looks like you’re making too many requests. Please slow down a bit. - Oops! It looks like you’re making too many requests. Please slow down a bit. + Ops! Sembra tu stia facendo troppe richieste. Rallenta un po' per favore. apps/client/src/app/core/http-response.interceptor.ts 96 @@ -6468,7 +6468,7 @@ My Account - My Account + Il mio Account apps/client/src/app/pages/i18n/i18n-page.html 13 @@ -6476,7 +6476,7 @@ Active - Active + Attivo apps/client/src/app/components/home-holdings/home-holdings.component.ts 38 @@ -6484,7 +6484,7 @@ Closed - Closed + Chiuso apps/client/src/app/components/home-holdings/home-holdings.component.ts 39 @@ -6492,7 +6492,7 @@ Activity - Activity + Attività apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html 223 @@ -6500,7 +6500,7 @@ Dividend Yield - Dividend Yield + Rendimento da Dividendi apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html 191 @@ -6508,7 +6508,7 @@ Execute Job - Execute Job + Esegui il lavoro apps/client/src/app/components/admin-jobs/admin-jobs.html 174 @@ -6516,7 +6516,7 @@ Priority - Priority + Priorità apps/client/src/app/components/admin-jobs/admin-jobs.html 62 @@ -6524,7 +6524,7 @@ This action is not allowed. - This action is not allowed. + Questa azione non è permessa. apps/client/src/app/core/http-response.interceptor.ts 61 @@ -6532,7 +6532,7 @@ Liquidity - Liquidity + Liquidità libs/ui/src/lib/i18n.ts 47 @@ -6540,7 +6540,7 @@ Change with currency effect - Change with currency effect + Variazione con Effetto Valutario apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html 53 @@ -6548,7 +6548,7 @@ Performance with currency effect - Performance with currency effect + Rendimento con effetto valutario apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html 81 @@ -6564,7 +6564,7 @@ Buy and sell - Buy and sell + Compra e vendi libs/ui/src/lib/i18n.ts 8 @@ -6572,7 +6572,7 @@ Delete Activities - Delete Activities + Elimina le attività libs/ui/src/lib/activities-table/activities-table.component.html 66 @@ -6580,7 +6580,7 @@ Internationalization - Internationalization + Internazionalizzazione apps/client/src/app/app-routing.module.ts 79 @@ -6588,7 +6588,7 @@ Do you really want to close your Ghostfolio account? - Do you really want to close your Ghostfolio account? + Confermi di voler chiudere il tuo account Ghostfolio? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts 174 @@ -6596,7 +6596,7 @@ Danger Zone - Danger Zone + Zona di Pericolo apps/client/src/app/components/user-account-settings/user-account-settings.html 244 @@ -6604,7 +6604,7 @@ Close Account - Close Account + Chiudi l'account apps/client/src/app/components/user-account-settings/user-account-settings.html 279 @@ -6612,7 +6612,7 @@ By ETF Holding - By ETF Holding + Per ETF posseduti apps/client/src/app/pages/portfolio/allocations/allocations-page.html 333 @@ -6620,7 +6620,7 @@ Approximation based on the top holdings of each ETF - Approximation based on the top holdings of each ETF + Approssimato in base ai principali ETF posseduti apps/client/src/app/pages/portfolio/allocations/allocations-page.html 340 @@ -6628,7 +6628,7 @@ Join now or check out the example account - Join now or check out the example account + Registrati adesso o prova l'account demo apps/client/src/app/pages/landing/landing-page.html 434 @@ -6636,7 +6636,7 @@ Oops! There was an error setting up biometric authentication. - Oops! There was an error setting up biometric authentication. + Ops! C'è stato un errore impostando l'autenticazione biometrica. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts 308 @@ -6644,7 +6644,7 @@ Show more - Show more + Visualizza di più libs/ui/src/lib/top-holdings/top-holdings.component.html 81 @@ -6652,7 +6652,7 @@ Benchmarks - Benchmarks + Benchmarks apps/client/src/app/components/admin-market-data/admin-market-data.component.ts 80 @@ -6660,7 +6660,7 @@ Delete Profiles - Delete Profiles + Elimina i profili apps/client/src/app/components/admin-market-data/admin-market-data.html 190 @@ -6668,7 +6668,7 @@ Do you really want to delete these profiles? - Do you really want to delete these profiles? + Confermi di voler eliminare questi profili? apps/client/src/app/components/admin-market-data/admin-market-data.service.ts 65 @@ -6676,7 +6676,7 @@ Oops! Could not delete profiles. - Oops! Could not delete profiles. + Ops! Impossibile eliminare i profili. apps/client/src/app/components/admin-market-data/admin-market-data.service.ts 52 @@ -6684,7 +6684,7 @@ Table - Table + Tabella apps/client/src/app/components/home-holdings/home-holdings.html 17 @@ -6692,7 +6692,7 @@ Chart - Chart + Grafico apps/client/src/app/components/home-holdings/home-holdings.html 20 @@ -6700,7 +6700,7 @@ Would you like to refine your personal investment strategy? - Would you like to refine your personal investment strategy? + Vorresti perfezionare la tua strategia personale di investimento? apps/client/src/app/pages/public/public-page.html 155 @@ -6708,7 +6708,7 @@ Alternative - Alternative + Alternativa apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 83 @@ -6716,7 +6716,7 @@ App - App + App apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 84 @@ -6724,7 +6724,7 @@ Budgeting - Budgeting + Budgeting apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 85 @@ -6732,7 +6732,7 @@ Community - Community + Comunità apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 86 @@ -6748,7 +6748,7 @@ Investor - Investor + Investitore apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 90 @@ -6756,7 +6756,7 @@ Open Source - Open Source + Open Source apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 91 @@ -6764,7 +6764,7 @@ Personal Finance - Personal Finance + Finanza Personale apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 93 @@ -6772,7 +6772,7 @@ Privacy - Privacy + Privacy apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 94 @@ -6780,7 +6780,7 @@ Software - Software + Software apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 96 @@ -6788,7 +6788,7 @@ Tool - Tool + Strumento apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 97 @@ -6804,7 +6804,7 @@ Wealth - Wealth + Ricchezza apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 99 @@ -6812,7 +6812,7 @@ Wealth Management - Wealth Management + Gestione Patrimoniale apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 100 @@ -6820,7 +6820,7 @@ Australia - Australia + Australia libs/ui/src/lib/i18n.ts 72 @@ -6828,7 +6828,7 @@ Austria - Austria + Austria libs/ui/src/lib/i18n.ts 73 @@ -6836,7 +6836,7 @@ Belgium - Belgium + Belgio libs/ui/src/lib/i18n.ts 74 @@ -6844,7 +6844,7 @@ Bulgaria - Bulgaria + Bulgaria libs/ui/src/lib/i18n.ts 75 @@ -6852,7 +6852,7 @@ Canada - Canada + Canada libs/ui/src/lib/i18n.ts 76 @@ -6860,7 +6860,7 @@ Czech Republic - Czech Republic + Repubblica Ceca libs/ui/src/lib/i18n.ts 77 @@ -6868,7 +6868,7 @@ Finland - Finland + Finlandia libs/ui/src/lib/i18n.ts 78 @@ -6876,7 +6876,7 @@ France - France + Francia libs/ui/src/lib/i18n.ts 79 @@ -6884,7 +6884,7 @@ Germany - Germany + Germania libs/ui/src/lib/i18n.ts 80 @@ -6892,7 +6892,7 @@ India - India + India libs/ui/src/lib/i18n.ts 81 @@ -6900,7 +6900,7 @@ Italy - Italy + Italia libs/ui/src/lib/i18n.ts 82 @@ -6908,7 +6908,7 @@ Netherlands - Netherlands + Olanda libs/ui/src/lib/i18n.ts 84 @@ -6916,7 +6916,7 @@ New Zealand - New Zealand + Nuova Zelanda libs/ui/src/lib/i18n.ts 85 @@ -6924,7 +6924,7 @@ Poland - Poland + Polonia libs/ui/src/lib/i18n.ts 86 @@ -6932,7 +6932,7 @@ Romania - Romania + Romania libs/ui/src/lib/i18n.ts 87 @@ -6940,7 +6940,7 @@ South Africa - South Africa + Sud Africa libs/ui/src/lib/i18n.ts 88 @@ -6948,7 +6948,7 @@ Thailand - Thailand + Tailandia libs/ui/src/lib/i18n.ts 90 @@ -6956,7 +6956,7 @@ United States - United States + Stati Uniti libs/ui/src/lib/i18n.ts 91 @@ -6964,7 +6964,7 @@ Error - Error + Errore apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 336 @@ -6972,7 +6972,7 @@ Deactivate - Deactivate + Disattiva apps/client/src/app/components/rule/rule.component.html 67 @@ -6980,7 +6980,7 @@ Activate - Activate + Attiva apps/client/src/app/components/rule/rule.component.html 69 @@ -6988,7 +6988,7 @@ Inactive - Inactive + Inattivo apps/client/src/app/pages/portfolio/fire/fire-page.html 194 @@ -6996,7 +6996,7 @@ Cancel - Cancel + Annulla libs/ui/src/lib/i18n.ts 9 @@ -7004,7 +7004,7 @@ Close - Close + Chiudi libs/ui/src/lib/i18n.ts 11 @@ -7012,7 +7012,7 @@ Yes - Yes + Si libs/ui/src/lib/i18n.ts 31 From 557a0bf8080870943f70dfda37f6ae5cb0666a4e Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Mon, 9 Sep 2024 13:20:55 +0200 Subject: [PATCH 29/78] Feature/optimize info endpoint using promise.all (#3742) * Optimize by using Promise.all() * Update changelog --- CHANGELOG.md | 1 + apps/api/src/app/info/info.service.ts | 33 +++++++++++++++------------ 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 510ccddf6..afc0dcc58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Optimized the asynchronous operations using `Promise.all()` in the info service - Extracted the users from the admin control panel endpoint to a dedicated endpoint - Improved the language localization for Italian (`it`) diff --git a/apps/api/src/app/info/info.service.ts b/apps/api/src/app/info/info.service.ts index de4a870d2..acd7b315b 100644 --- a/apps/api/src/app/info/info.service.ts +++ b/apps/api/src/app/info/info.service.ts @@ -54,9 +54,6 @@ export class InfoService { public async get(): Promise { const info: Partial = {}; let isReadOnlyMode: boolean; - const platforms = await this.platformService.getPlatforms({ - orderBy: { name: 'asc' } - }); const globalPermissions: string[] = []; @@ -100,22 +97,30 @@ export class InfoService { globalPermissions.push(permissions.enableSystemMessage); } - const isUserSignupEnabled = - await this.propertyService.isUserSignupEnabled(); + const [ + benchmarks, + demoAuthToken, + isUserSignupEnabled, + platforms, + statistics, + subscriptions, + tags + ] = await Promise.all([ + this.benchmarkService.getBenchmarkAssetProfiles(), + this.getDemoAuthToken(), + this.propertyService.isUserSignupEnabled(), + this.platformService.getPlatforms({ + orderBy: { name: 'asc' } + }), + this.getStatistics(), + this.getSubscriptions(), + this.tagService.get() + ]); if (isUserSignupEnabled) { globalPermissions.push(permissions.createUserAccount); } - const [benchmarks, demoAuthToken, statistics, subscriptions, tags] = - await Promise.all([ - this.benchmarkService.getBenchmarkAssetProfiles(), - this.getDemoAuthToken(), - this.getStatistics(), - this.getSubscriptions(), - this.tagService.get() - ]); - return { ...info, benchmarks, From 6db881b08f49aa323b5940c1dde082b7aef974c6 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Tue, 10 Sep 2024 14:39:52 +0200 Subject: [PATCH 30/78] Feature/optimize admin control panel endpoint using promise.all (#3741) * Optimize by using Promise.all() * Update changelog --- CHANGELOG.md | 1 + apps/api/src/app/admin/admin.service.ts | 62 ++++++++++++++----------- 2 files changed, 36 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index afc0dcc58..e4d92ad12 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 - Optimized the asynchronous operations using `Promise.all()` in the info service +- Optimized the asynchronous operations using `Promise.all()` in the admin control panel endpoint - Extracted the users from the admin control panel endpoint to a dedicated endpoint - Improved the language localization for Italian (`it`) diff --git a/apps/api/src/app/admin/admin.service.ts b/apps/api/src/app/admin/admin.service.ts index 3f5274285..143d5c1ca 100644 --- a/apps/api/src/app/admin/admin.service.ts +++ b/apps/api/src/app/admin/admin.service.ts @@ -108,34 +108,42 @@ export class AdminService { } public async get(): Promise { - return { - exchangeRates: this.exchangeRateDataService - .getCurrencies() - .filter((currency) => { - return currency !== DEFAULT_CURRENCY; - }) - .map((currency) => { - const label1 = DEFAULT_CURRENCY; - const label2 = currency; + const exchangeRates = this.exchangeRateDataService + .getCurrencies() + .filter((currency) => { + return currency !== DEFAULT_CURRENCY; + }) + .map((currency) => { + const label1 = DEFAULT_CURRENCY; + const label2 = currency; - return { - label1, - label2, - dataSource: - DataSource[ - this.configurationService.get('DATA_SOURCE_EXCHANGE_RATES') - ], - symbol: `${label1}${label2}`, - value: this.exchangeRateDataService.toCurrency( - 1, - DEFAULT_CURRENCY, - currency - ) - }; - }), - settings: await this.propertyService.get(), - transactionCount: await this.prismaService.order.count(), - userCount: await this.prismaService.user.count(), + return { + label1, + label2, + dataSource: + DataSource[ + this.configurationService.get('DATA_SOURCE_EXCHANGE_RATES') + ], + symbol: `${label1}${label2}`, + value: this.exchangeRateDataService.toCurrency( + 1, + DEFAULT_CURRENCY, + currency + ) + }; + }); + + const [settings, transactionCount, userCount] = await Promise.all([ + this.propertyService.get(), + this.prismaService.order.count(), + this.prismaService.user.count() + ]); + + return { + exchangeRates, + settings, + transactionCount, + userCount, version: environment.version }; } From 9edffd100e7286969f5e6c4380287868e6332589 Mon Sep 17 00:00:00 2001 From: FrozenPasta <40991761+FrozenPasta@users.noreply.github.com> Date: Tue, 10 Sep 2024 17:36:24 +0200 Subject: [PATCH 31/78] Feature/improve language localization for fr (#3724) * Update translations * Update changelog --- CHANGELOG.md | 1 + apps/client/src/locales/messages.fr.xlf | 538 ++++++++++++------------ 2 files changed, 270 insertions(+), 269 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e4d92ad12..7cbc0519f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Optimized the asynchronous operations using `Promise.all()` in the info service - Optimized the asynchronous operations using `Promise.all()` in the admin control panel endpoint - Extracted the users from the admin control panel endpoint to a dedicated endpoint +- Improved the language localization for French (`fr`) - Improved the language localization for Italian (`it`) ## 2.106.0 - 2024-09-07 diff --git a/apps/client/src/locales/messages.fr.xlf b/apps/client/src/locales/messages.fr.xlf index ce7cc241b..ed2e892e8 100644 --- a/apps/client/src/locales/messages.fr.xlf +++ b/apps/client/src/locales/messages.fr.xlf @@ -219,7 +219,7 @@ Cash Balance - Balance Cash + Balance Cash apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html 45 @@ -459,7 +459,7 @@ Asset Profiles - Profil d’Actifs + Profil d’Actifs libs/ui/src/lib/assistant/assistant.html 67 @@ -467,7 +467,7 @@ Historical Market Data - Données de Marché Historiques + Données de Marché Historiques apps/client/src/app/components/admin-jobs/admin-jobs.html 37 @@ -1091,7 +1091,7 @@ Last Request - Dernière Requête + Dernière Requête apps/client/src/app/components/admin-users/admin-users.html 181 @@ -1851,7 +1851,7 @@ License - License + License apps/client/src/app/app.component.html 85 @@ -1863,7 +1863,7 @@ Privacy Policy - Politique de Vie Privée + Politique de Vie Privée apps/client/src/app/pages/about/about-page.component.ts 62 @@ -2123,7 +2123,7 @@ Sign in with fingerprint - Se connecter avec empreinte + Se connecter avec empreinte apps/client/src/app/components/user-account-settings/user-account-settings.html 191 @@ -2843,7 +2843,7 @@ Hello, has shared a Portfolio with you! - Bonjour, a partagé un Portefeuille avec vous ! + Bonjour, a partagé un Portefeuille avec vous ! apps/client/src/app/pages/public/public-page.html 4 @@ -3411,7 +3411,7 @@ Core - Core + Core libs/ui/src/lib/i18n.ts 10 @@ -3459,7 +3459,7 @@ Protection for sensitive information like absolute performances and quantity values - Protection pour les informations sensibles telles que la performance absolue et les montants + Protection pour les informations sensibles telles que la performance absolue et les montants apps/client/src/app/components/user-account-settings/user-account-settings.html 8 @@ -3467,7 +3467,7 @@ Distraction-free experience for turbulent times - Expérience sans distraction pour les périodes tumultueuses + Expérience sans distraction pour les périodes tumultueuses apps/client/src/app/components/user-account-settings/user-account-settings.html 174 @@ -3475,7 +3475,7 @@ Sneak peek at upcoming functionality - Avant-première de fonctionnalités futures + Avant-première de fonctionnalités futures apps/client/src/app/components/user-account-settings/user-account-settings.html 208 @@ -3879,7 +3879,7 @@ Our official Ghostfolio Premium cloud offering is the easiest way to get started. Due to the time it saves, this will be the best option for most people. Revenue is used to cover the costs of the hosting infrastructure and to fund ongoing development. - Notre offre Ghostfolio Premium cloud est la manière la plus simple de débuter. Grâce au temps qu’elle économise, ce sera la meilleure option pour la plupart des gens. Les revenus sont utilisés pour couvrir les frais d’infrastructures et financer le développement continu de Ghostfolio. + Notre offre Ghostfolio Premium cloud est la manière la plus simple de débuter. Grâce au temps qu’elle économise, ce sera la meilleure option pour la plupart des gens. Les revenus sont utilisés pour couvrir les frais d’infrastructures et financer le développement continu de Ghostfolio. apps/client/src/app/pages/pricing/pricing-page.html 6 @@ -3903,7 +3903,7 @@ Do you really want to delete these activities? - Voulez-vous vraiment supprimer toutes vos activités ? + Voulez-vous vraiment supprimer toutes vos activités ? libs/ui/src/lib/activities-table/activities-table.component.ts 225 @@ -4243,7 +4243,7 @@ Wealth Items - Wealth Items + Biens de luxe apps/client/src/app/pages/features/features-page.html 76 @@ -4267,7 +4267,7 @@ Portfolio Calculations - Portfolio Calculations + Calculs de portefeuille apps/client/src/app/pages/features/features-page.html 141 @@ -4315,7 +4315,7 @@ Liability - Dette + Dette libs/ui/src/lib/i18n.ts 39 @@ -4323,7 +4323,7 @@ Scraper Configuration - Scraper Configuration + Configuration du Scraper apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 304 @@ -4331,7 +4331,7 @@ Add Asset Profile - Add Asset Profile + Ajouter un Profil d'Actif apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html 7 @@ -4339,7 +4339,7 @@ Personal Finance Tools - Personal Finance Tools + Outils de Gestion de Patrimoine apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page-routing.module.ts 14 @@ -4347,7 +4347,7 @@ Discover Open Source Alternatives for Personal Finance Tools - Découvrez les alternatives Open Source pour les outils de finance personnelle + Découvrez les alternatives Open Source pour les outils de Gestion de Patrimoine apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.html 4 @@ -4455,7 +4455,7 @@ ❌ No - ❌ No + ❌ Non apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 140 @@ -4463,7 +4463,7 @@ Self-Hosting - Self-Hosting + Self-Hosting apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 145 @@ -4495,7 +4495,7 @@ Effortlessly track, analyze, and visualize your wealth with Ghostfolio. - Effortlessly track, analyze, and visualize your wealth with Ghostfolio. + Suivez, analysez et visualisez sans effort votre patrimoine avec Ghostfolio. apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 243 @@ -4503,7 +4503,7 @@ Personal Finance Tools - Personal Finance Tools + Outils de Gestion de Patrimoine apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 266 @@ -4511,7 +4511,7 @@ Guides - Guides + Guides apps/client/src/app/pages/resources/resources-page.html 22 @@ -4519,7 +4519,7 @@ Glossary - Glossary + Glossaire apps/client/src/app/pages/resources/resources-page.html 124 @@ -4527,7 +4527,7 @@ Stocks, ETFs, bonds, cryptocurrencies, commodities - Stocks, ETFs, bonds, cryptocurrencies, commodities + Actions, ETFs, Obligations, Cryptomonnaies, Matières Premières apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html 25 @@ -4539,7 +4539,7 @@ Mortgages, personal loans, credit cards - Mortgages, personal loans, credit cards + Hypothèques, Prêts personnels, Cartes de crédit apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html 57 @@ -4547,7 +4547,7 @@ Luxury items, real estate, private companies - Luxury items, real estate, private companies + Bien de luxes, Immobilier, sociétées privées apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html 73 @@ -4555,7 +4555,7 @@ Buy - Buy + Achat libs/ui/src/lib/i18n.ts 34 @@ -4563,7 +4563,7 @@ Valuable - Valuable + Actifs libs/ui/src/lib/i18n.ts 38 @@ -4571,7 +4571,7 @@ ETFs without Countries - ETFs without Countries + ETF sans Pays apps/client/src/app/components/admin-market-data/admin-market-data.component.ts 90 @@ -4579,7 +4579,7 @@ ETFs without Sectors - ETFs without Sectors + ETF sans Secteurs apps/client/src/app/components/admin-market-data/admin-market-data.component.ts 95 @@ -4587,7 +4587,7 @@ Assets - Assets + Actifs apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html 239 @@ -4595,7 +4595,7 @@ Preset - Preset + Configuration par défaut libs/ui/src/lib/i18n.ts 24 @@ -4603,7 +4603,7 @@ By Market - By Market + par Marchés apps/client/src/app/pages/portfolio/allocations/allocations-page.html 175 @@ -4611,7 +4611,7 @@ Asia-Pacific - Asia-Pacific + Asie-Pacifique libs/ui/src/lib/i18n.ts 5 @@ -4619,7 +4619,7 @@ Japan - Japan + Japon libs/ui/src/lib/i18n.ts 83 @@ -4627,7 +4627,7 @@ Welcome to Ghostfolio - Welcome to Ghostfolio + Bienvenue sur Ghostfolio apps/client/src/app/components/home-overview/home-overview.html 7 @@ -4635,7 +4635,7 @@ Setup your accounts - Setup your accounts + Configurer votre compte apps/client/src/app/components/home-overview/home-overview.html 15 @@ -4643,7 +4643,7 @@ Get a comprehensive financial overview by adding your bank and brokerage accounts. - Get a comprehensive financial overview by adding your bank and brokerage accounts. + Obtenir un aperçu de vos comptes financiers en ajoutant vos comptes bancaires et de courtages. apps/client/src/app/components/home-overview/home-overview.html 17 @@ -4651,7 +4651,7 @@ Capture your activities - Capture your activities + Capture vos activitées apps/client/src/app/components/home-overview/home-overview.html 24 @@ -4659,7 +4659,7 @@ Record your investment activities to keep your portfolio up to date. - Record your investment activities to keep your portfolio up to date. + Enregistrez vos activités immobilières pour maintenir votre portfolio à jour. apps/client/src/app/components/home-overview/home-overview.html 26 @@ -4667,7 +4667,7 @@ Monitor and analyze your portfolio - Monitor and analyze your portfolio + Monitorer et analyser votre portfolio apps/client/src/app/components/home-overview/home-overview.html 33 @@ -4675,7 +4675,7 @@ Track your progress in real-time with comprehensive analysis and insights. - Track your progress in real-time with comprehensive analysis and insights. + Suivez votre évolution en temps réel grâce à une analyse approfondie et complète. apps/client/src/app/components/home-overview/home-overview.html 35 @@ -4683,7 +4683,7 @@ No data available - No data available + Pas de données disponible apps/client/src/app/pages/portfolio/allocations/allocations-page.html 250 @@ -4699,7 +4699,7 @@ Ready to take control of your personal finances? - Ready to take control of your personal finances? + Prêt à reprendre le contrôle de votre patrimoine ? apps/client/src/app/components/home-overview/home-overview.html 8 @@ -4707,7 +4707,7 @@ Setup accounts - Setup accounts + Configurer le compte apps/client/src/app/components/home-overview/home-overview.html 44 @@ -4715,7 +4715,7 @@ Biometric Authentication - Biometric Authentication + Authentication biométrique apps/client/src/app/components/user-account-settings/user-account-settings.html 190 @@ -4723,7 +4723,7 @@ At Ghostfolio, transparency is at the core of our values. We publish the source code as open source software (OSS) under the AGPL-3.0 license and we openly share aggregated key metrics of the platform’s operational status. - At Ghostfolio, transparency is at the core of our values. We publish the source code as open source software (OSS) under the AGPL-3.0 license and we openly share aggregated key metrics of the platform’s operational status. + Chez Ghostfolio, la transparence est le centre de notre attention. Nous publions le code source sous open source software (OSS) sous la licence AGPL-3.0 et nous partageons ouvertement les indicateurs clés agrégés sur l'état opérationnel de la plateforme. apps/client/src/app/pages/open/open-page.html 6 @@ -4731,7 +4731,7 @@ Active Users - Active Users + Utilisateurs actifs apps/client/src/app/pages/open/open-page.html 40 @@ -4743,7 +4743,7 @@ New Users - New Users + Nouvel Utilisateur apps/client/src/app/pages/open/open-page.html 51 @@ -4751,7 +4751,7 @@ Users in Slack community - Users in Slack community + Membres de la communauté Slack apps/client/src/app/pages/open/open-page.html 75 @@ -4759,7 +4759,7 @@ Contributors on GitHub - Contributors on GitHub + Contributeurs GitHub apps/client/src/app/pages/open/open-page.html 89 @@ -4767,7 +4767,7 @@ Stars on GitHub - Stars on GitHub + Etoiles sur GitHub apps/client/src/app/pages/landing/landing-page.html 88 @@ -4779,7 +4779,7 @@ Pulls on Docker Hub - Pulls on Docker Hub + Téléchargement depuis Docker Hub apps/client/src/app/pages/landing/landing-page.html 106 @@ -4791,7 +4791,7 @@ Uptime - Uptime + Temps d'activité des serveurs apps/client/src/app/pages/open/open-page.html 132 @@ -4799,7 +4799,7 @@ Export Data - Export Data + Exporter les Data apps/client/src/app/components/user-account-settings/user-account-settings.html 232 @@ -4807,7 +4807,7 @@ Currencies - Currencies + Devises apps/client/src/app/components/admin-market-data/admin-market-data.component.ts 85 @@ -4815,7 +4815,7 @@ Our - Our + Notre apps/client/src/app/pages/about/oss-friends/oss-friends-page.html 6 @@ -4823,7 +4823,7 @@ Visit - Visit + Voir apps/client/src/app/pages/about/oss-friends/oss-friends-page.html 28 @@ -4831,7 +4831,7 @@ Discover other exciting Open Source Software projects - Discover other exciting Open Source Software projects + Découvrez d'autres projets passionnants de logiciels Open Source apps/client/src/app/pages/about/oss-friends/oss-friends-page.html 9 @@ -4839,7 +4839,7 @@ Frequently Asked Questions (FAQ) - Frequently Asked Questions (FAQ) + Frequently Asked Questions (FAQ) apps/client/src/app/pages/faq/overview/faq-overview-page.html 4 @@ -4855,7 +4855,7 @@ Check out the numerous features of Ghostfolio to manage your wealth - Check out the numerous features of Ghostfolio to manage your wealth + Découvrez les nombreuses fonctionnalités de Ghostfolio pour gérer votre patrimoine apps/client/src/app/pages/features/features-page.html 6 @@ -4863,7 +4863,7 @@ Discover the latest Ghostfolio updates and insights on personal finance - Discover the latest Ghostfolio updates and insights on personal finance + Découvrez les dernières mises à jour et informations de Ghostfolio sur la gestion de patrimoine apps/client/src/app/pages/blog/blog-page.html 7 @@ -4871,7 +4871,7 @@ If you prefer to run Ghostfolio on your own infrastructure, please find the source code and further instructions on GitHub. - If you prefer to run Ghostfolio on your own infrastructure, please find the source code and further instructions on GitHub. + Si vous préférez exécuter Ghostfolio sur votre propre infrastructure, veuilez trouver le code source ainsi que des instructions supplémentaires sur GitHub. apps/client/src/app/pages/pricing/pricing-page.html 26 @@ -4879,7 +4879,7 @@ Manage your wealth like a boss - Manage your wealth like a boss + Gérez votre patrimoine comme un chef apps/client/src/app/pages/landing/landing-page.html 5 @@ -4887,7 +4887,7 @@ Ghostfolio is a privacy-first, open source dashboard for your personal finances. Break down your asset allocation, know your net worth and make solid, data-driven investment decisions. - Ghostfolio is a privacy-first, open source dashboard for your personal finances. Break down your asset allocation, know your net worth and make solid, data-driven investment decisions. + Ghostfolio est un tableau de bord open-source axé sur la confidentialité pour votre Gestion de Patrimoine. Décomposez votre répartition d'actifs, connaissez votre valeur nette et prenez des décisions d'investissement solides et basées sur des données. apps/client/src/app/pages/landing/landing-page.html 9 @@ -4907,7 +4907,7 @@ Monthly Active Users - Monthly Active Users + Utilisateurs actifs mensuels apps/client/src/app/pages/landing/landing-page.html 70 @@ -4915,7 +4915,7 @@ As seen in - As seen in + Médias apps/client/src/app/pages/landing/landing-page.html 115 @@ -4923,7 +4923,7 @@ Protect your assets. Refine your personal investment strategy. - Protect your assets. Refine your personal investment strategy. + Protégez vos actifs. Affinez votre stratégie d'investissement personnelle.. apps/client/src/app/pages/landing/landing-page.html 225 @@ -4931,7 +4931,7 @@ Ghostfolio empowers busy people to keep track of stocks, ETFs or cryptocurrencies without being tracked. - Ghostfolio empowers busy people to keep track of stocks, ETFs or cryptocurrencies without being tracked. + Ghostfolio permet aux personnes occupées de suivre ses actions, ETF ou cryptomonnaies sans être pistées. apps/client/src/app/pages/landing/landing-page.html 229 @@ -4939,7 +4939,7 @@ 360° View - 360° View + Vision 360° apps/client/src/app/pages/landing/landing-page.html 240 @@ -4947,7 +4947,7 @@ Web3 Ready - Web3 Ready + Compatible Web3 apps/client/src/app/pages/landing/landing-page.html 251 @@ -4955,7 +4955,7 @@ Use Ghostfolio anonymously and own your financial data. - Use Ghostfolio anonymously and own your financial data. + Utilisez Ghostfolio de manière anonyme et soyez propriétaire de vos données financières. apps/client/src/app/pages/landing/landing-page.html 253 @@ -4963,7 +4963,7 @@ Open Source - Open Source + Open Source apps/client/src/app/pages/landing/landing-page.html 261 @@ -4971,7 +4971,7 @@ Benefit from continuous improvements through a strong community. - Benefit from continuous improvements through a strong community. + Bénéficiez d'améliorations continues grâce à une communauté impliquée. apps/client/src/app/pages/landing/landing-page.html 263 @@ -4979,7 +4979,7 @@ Why Ghostfolio? - Why Ghostfolio? + Pourquoi Ghostfolio? apps/client/src/app/pages/landing/landing-page.html 272 @@ -4987,7 +4987,7 @@ Ghostfolio is for you if you are... - Ghostfolio is for you if you are... + Ghostfolio est pour vous si vous ... apps/client/src/app/pages/landing/landing-page.html 273 @@ -4995,7 +4995,7 @@ trading stocks, ETFs or cryptocurrencies on multiple platforms - trading stocks, ETFs or cryptocurrencies on multiple platforms + tradez des actions, ETFs or crypto-monnaies sur plusieurs plateforme. apps/client/src/app/pages/landing/landing-page.html 280 @@ -5003,7 +5003,7 @@ pursuing a buy & hold strategy - pursuing a buy & hold strategy + adoptez une stratégie Buy & and Hold apps/client/src/app/pages/landing/landing-page.html 286 @@ -5011,7 +5011,7 @@ interested in getting insights of your portfolio composition - interested in getting insights of your portfolio composition + êtes intéressés d'avoir un aperçu de la composition de votre portefeuille apps/client/src/app/pages/landing/landing-page.html 291 @@ -5019,7 +5019,7 @@ valuing privacy and data ownership - valuing privacy and data ownership + valorisez la confidentialité et la propriété de vos données apps/client/src/app/pages/landing/landing-page.html 296 @@ -5027,7 +5027,7 @@ into minimalism - into minimalism + êtes minimaliste apps/client/src/app/pages/landing/landing-page.html 299 @@ -5035,7 +5035,7 @@ caring about diversifying your financial resources - caring about diversifying your financial resources + vous souciez de diversifier vos ressources financières apps/client/src/app/pages/landing/landing-page.html 303 @@ -5043,7 +5043,7 @@ interested in financial independence - interested in financial independence + êtes intéressés d'atteindre l'indépendance financière apps/client/src/app/pages/landing/landing-page.html 307 @@ -5051,7 +5051,7 @@ saying no to spreadsheets in - saying no to spreadsheets in + dites non aux feuilles de calcul en apps/client/src/app/pages/landing/landing-page.html 311 @@ -5059,7 +5059,7 @@ still reading this list - still reading this list + continuez à lire cette liste apps/client/src/app/pages/landing/landing-page.html 314 @@ -5067,7 +5067,7 @@ Learn more about Ghostfolio - Learn more about Ghostfolio + En appendre plus sur Ghostfolio apps/client/src/app/pages/landing/landing-page.html 319 @@ -5075,7 +5075,7 @@ What our users are saying - What our users are saying + Qu'en pensent nos utilisateurs apps/client/src/app/pages/landing/landing-page.html 327 @@ -5083,7 +5083,7 @@ Members from around the globe are using Ghostfolio Premium - Members from around the globe are using Ghostfolio Premium + Les utilisateurs du monde entier utilisent Ghostfolio Premium apps/client/src/app/pages/landing/landing-page.html 366 @@ -5091,7 +5091,7 @@ How does Ghostfolio work? - How does Ghostfolio work? + Comment fonctionne Ghostfolio ? apps/client/src/app/pages/landing/landing-page.html 383 @@ -5099,7 +5099,7 @@ Sign up anonymously* - Sign up anonymously* + Inscrivez-vous de manière anonyme* apps/client/src/app/pages/landing/landing-page.html 392 @@ -5107,7 +5107,7 @@ * no e-mail address nor credit card required - * no e-mail address nor credit card required + * aucune adresse mail ni carte de crédit requise apps/client/src/app/pages/landing/landing-page.html 394 @@ -5115,7 +5115,7 @@ Add any of your historical transactions - Add any of your historical transactions + Ajoutez l'une de vos transactions historiques apps/client/src/app/pages/landing/landing-page.html 405 @@ -5123,7 +5123,7 @@ Get valuable insights of your portfolio composition - Get valuable insights of your portfolio composition + Obtenez de précieuses informations sur la composition de votre portefeuille apps/client/src/app/pages/landing/landing-page.html 417 @@ -5131,7 +5131,7 @@ Are you ready? - Are you ready? + Êtes- vous prêts ? apps/client/src/app/pages/landing/landing-page.html 431 @@ -5139,7 +5139,7 @@ Live Demo - Live Demo + Démo en Live apps/client/src/app/pages/landing/landing-page.html 49 @@ -5151,7 +5151,7 @@ Get the full picture of your personal finances across multiple platforms. - Get the full picture of your personal finances across multiple platforms. + Obtenez une vue d'ensemble de vos finances personnelles sur plusieurs plateformes. apps/client/src/app/pages/landing/landing-page.html 242 @@ -5159,7 +5159,7 @@ Get started in only 3 steps - Get started in only 3 steps + Démarrer en seulement 3 étapes apps/client/src/app/pages/landing/landing-page.html 386 @@ -5567,7 +5567,7 @@ This overview page features a curated collection of personal finance tools compared to the open source alternative Ghostfolio. If you value transparency, data privacy, and community collaboration, Ghostfolio provides an excellent opportunity to take control of your financial management. - This overview page features a curated collection of personal finance tools compared to the open source alternative Ghostfolio. If you value transparency, data privacy, and community collaboration, Ghostfolio provides an excellent opportunity to take control of your financial management. + Cette page d'aperçu présente une collection d'outils de finances personnelles comparés à la solution open source alternative Ghostfolio. Si vous accordez de l'importance à la transparence, à la confidentialité des données et à la collaboration communautaire, Ghostfolio vous offre une excellente occasion de prendre le contrôle de votre gestion financière. apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.html 8 @@ -5575,7 +5575,7 @@ Explore the links below to compare a variety of personal finance tools with Ghostfolio. - Explore the links below to compare a variety of personal finance tools with Ghostfolio. + Explorez les liens ci-dessous pour comparer une variété d'outils de finances personnelles avec Ghostfolio. apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.html 16 @@ -5583,7 +5583,7 @@ Open Source Alternative to - Alternative open source à + Solutions open source alternatives à apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.html 42 @@ -5591,7 +5591,7 @@ Open Source Alternative to - Alternative open source à + Solutions open source alternatives à apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page-routing.module.ts 27 @@ -5607,7 +5607,7 @@ Are you looking for an open source alternative to ? Ghostfolio is a powerful portfolio management tool that provides individuals with a comprehensive platform to track, analyze, and optimize their investments. Whether you are an experienced investor or just starting out, Ghostfolio offers an intuitive user interface and a wide range of functionalities to help you make informed decisions and take control of your financial future. - Are you looking for an open source alternative to ? Ghostfolio is a powerful portfolio management tool that provides individuals with a comprehensive platform to track, analyze, and optimize their investments. Whether you are an experienced investor or just starting out, Ghostfolio offers an intuitive user interface and a wide range of functionalities to help you make informed decisions and take control of your financial future. + Cherchez-vous des alternatives open source à ? Ghostfolio est un outil de gestion de portefeuille puissant offrant aux particuliers une plateforme complète pour suivre, analyser et optimiser ses investissements. Que vous soyez un investisseur expérimenté ou que vous débutiez, Ghostfolio offre une interface utilisateur intuitive et une large gamme de fonctionnalités pour vous aider à prendre des décisions éclairées et à prendre le contrôle de votre avenir financier. apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 13 @@ -5615,7 +5615,7 @@ Ghostfolio is an open source software (OSS), providing a cost-effective alternative to making it particularly suitable for individuals on a tight budget, such as those pursuing Financial Independence, Retire Early (FIRE). By leveraging the collective efforts of a community of developers and personal finance enthusiasts, Ghostfolio continuously enhances its capabilities, security, and user experience. - Ghostfolio is an open source software (OSS), providing a cost-effective alternative to making it particularly suitable for individuals on a tight budget, such as those pursuing Financial Independence, Retire Early (FIRE). By leveraging the collective efforts of a community of developers and personal finance enthusiasts, Ghostfolio continuously enhances its capabilities, security, and user experience. + Ghostfolio est un logiciel open source (OSS), offrant une alternative économique, le rendant particulièrement adaptée aux personnes disposant d'un budget serré, telles que celles qui cherchent à atteindre le mouvement Financial Independence, Retire Early (FIRE). En s'appuyant sur les efforts collectifs d'une communauté de développeurs et de passionnés de finances personnelles, Ghostfolio améliore continuellement ses fonctionnalités, sa sécurité et son expérience utilisateur. apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 27 @@ -5623,7 +5623,7 @@ Let’s dive deeper into the detailed Ghostfolio vs comparison table below to gain a thorough understanding of how Ghostfolio positions itself relative to . We will explore various aspects such as features, data privacy, pricing, and more, allowing you to make a well-informed choice for your personal requirements. - Let’s dive deeper into the detailed Ghostfolio vs comparison table below to gain a thorough understanding of how Ghostfolio positions itself relative to . We will explore various aspects such as features, data privacy, pricing, and more, allowing you to make a well-informed choice for your personal requirements. + Regardons plus en détails ce que proposent Ghostfolio vs via la table de comparaison ci-dessous pour comprendre comment Ghostfolio se positionne par rapport à . Nous examinerons divers aspects tels que les fonctionnalités, la confidentialité des données, le prix, etc., afin de vous permettre de faire un choix éclairé en fonction de vos besoins personnels. apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 38 @@ -5643,7 +5643,7 @@ Please note that the information provided in the Ghostfolio vs comparison table is based on our independent research and analysis. This website is not affiliated with or any other product mentioned in the comparison. As the landscape of personal finance tools evolves, it is essential to verify any specific details or changes directly from the respective product page. Data needs a refresh? Help us maintain accurate data on GitHub. - Please note that the information provided in the Ghostfolio vs comparison table is based on our independent research and analysis. This website is not affiliated with or any other product mentioned in the comparison. As the landscape of personal finance tools evolves, it is essential to verify any specific details or changes directly from the respective product page. Data needs a refresh? Help us maintain accurate data on GitHub. + Veuillez noter que les informations fournies dans le Ghostfolio vs via la table de comparaison se basent de nos recherches et analyses indépendantes. Ce site n'est pas affilié à ou tout autre produit mentionné dans la comparaison. Le paysage des outils de finances personnelles évoluant, il est essentiel de vérifier tout détail ou changement spécifique directement sur la page du produit concerné. Certaines données doivent être mises à jour ? Aidez-nous à maintenir les données exactes sur GitHub. apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 226 @@ -5651,7 +5651,7 @@ Ready to take your investments to the next level? - Ready to take your investments to the next level? + Prêt à prendre vos investissements au niveau supérieur? apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 239 @@ -5667,7 +5667,7 @@ Switzerland - Switzerland + Suisse apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 60 @@ -5679,7 +5679,7 @@ Global - Global + Mondial apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 61 @@ -5691,7 +5691,7 @@ (Last 24 hours) - (Last 24 hours) + (Derniers 24 heures) apps/client/src/app/pages/open/open-page.html 37 @@ -5699,7 +5699,7 @@ (Last 30 days) - (Last 30 days) + (Derniers 30 jours) apps/client/src/app/pages/open/open-page.html 48 @@ -5711,7 +5711,7 @@ (Last 90 days) - (Last 90 days) + (Derniers 90 jours) apps/client/src/app/pages/open/open-page.html 127 @@ -5719,7 +5719,7 @@ Choose or drop a file here - Choose or drop a file here + Choisissez ou déposez un fichier ici apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.html 84 @@ -5727,7 +5727,7 @@ You are using the Live Demo. - You are using the Live Demo. + Vous utilisez la Démo en Live. apps/client/src/app/app.component.html 12 @@ -5735,7 +5735,7 @@ One-time fee, annual account fees - One-time fee, annual account fees + Paiement unique, Paiement annuel apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html 33 @@ -5743,7 +5743,7 @@ Distribution of corporate earnings - Distribution of corporate earnings + Distribution des bénéfices de la société apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html 41 @@ -5751,7 +5751,7 @@ Oops! Could not get the historical exchange rate from - Oops! Could not get the historical exchange rate from + Oops! Echec de la récupération des données historiques depuis apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html 318 @@ -5759,7 +5759,7 @@ Fee - Fee + Frais libs/ui/src/lib/i18n.ts 36 @@ -5767,7 +5767,7 @@ Interest - Interest + Intérêts apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html 331 @@ -5775,7 +5775,7 @@ Revenue for lending out money - Revenue for lending out money + Revenue lié au prêt d'argent apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html 49 @@ -5783,7 +5783,7 @@ Add Tag - Add Tag + Ajouter un Tag apps/client/src/app/components/admin-tag/admin-tag.component.html 11 @@ -5791,7 +5791,7 @@ Do you really want to delete this tag? - Do you really want to delete this tag? + Confirmez la suppression de ce tag ? apps/client/src/app/components/admin-tag/admin-tag.component.ts 86 @@ -5799,7 +5799,7 @@ Update tag - Update tag + Mettre à jour le tag apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.html 8 @@ -5807,7 +5807,7 @@ Add tag - Add tag + Ajouter un tag apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.html 10 @@ -5815,7 +5815,7 @@ Ghostfolio X-ray uses static analysis to identify potential issues and risks in your portfolio. - Ghostfolio X-ray uses static analysis to identify potential issues and risks in your portfolio. + Ghostfolio X-ray utilise l'analyse statique pour identifier de potentiels problèmes et risques dans votre portefeuille. apps/client/src/app/pages/portfolio/fire/fire-page.html 111 @@ -5823,7 +5823,7 @@ Currency Cluster Risks - Currency Cluster Risks + Risques de change apps/client/src/app/pages/portfolio/fire/fire-page.html 140 @@ -5831,7 +5831,7 @@ Account Cluster Risks - Account Cluster Risks + Risques liés aux regroupements de comptes apps/client/src/app/pages/portfolio/fire/fire-page.html 158 @@ -5839,7 +5839,7 @@ Transfer Cash Balance - Transfer Cash Balance + Transfert de Cash Balance apps/client/src/app/components/accounts-table/accounts-table.component.html 10 @@ -5851,7 +5851,7 @@ Benchmark - Benchmark + Benchmark apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 286 @@ -5859,7 +5859,7 @@ Version - Version + Version apps/client/src/app/components/admin-overview/admin-overview.html 7 @@ -5867,7 +5867,7 @@ Settings - Settings + Paramètres apps/client/src/app/components/user-account-settings/user-account-settings.html 2 @@ -5875,7 +5875,7 @@ From - From + De apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.html 11 @@ -5883,7 +5883,7 @@ To - To + A apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.html 32 @@ -5891,7 +5891,7 @@ Transfer - Transfer + Transférer apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.html 72 @@ -5899,7 +5899,7 @@ Membership - Membership + Statut apps/client/src/app/pages/user-account/user-account-page-routing.module.ts 23 @@ -5911,7 +5911,7 @@ Access - Access + Accès apps/client/src/app/pages/user-account/user-account-page-routing.module.ts 28 @@ -5923,7 +5923,7 @@ Find holding... - Find holding... + Chercher un actif... libs/ui/src/lib/assistant/assistant.component.ts 138 @@ -5931,7 +5931,7 @@ No entries... - No entries... + Pas d'entrées ... libs/ui/src/lib/assistant/assistant.html 63 @@ -5943,7 +5943,7 @@ Asset Profile - Asset Profile + Profil d'Actif apps/client/src/app/components/admin-jobs/admin-jobs.html 35 @@ -5951,7 +5951,7 @@ Do you really want to delete this asset profile? - Do you really want to delete this asset profile? + Confirmez la suppressoion de ce profil d'actif? apps/client/src/app/components/admin-market-data/admin-market-data.service.ts 33 @@ -5959,7 +5959,7 @@ Search - Search + Chercher apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html 16 @@ -5967,7 +5967,7 @@ Add Manually - Add Manually + Ajouter manuellement apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html 19 @@ -5975,7 +5975,7 @@ Ghostfolio is a personal finance dashboard to keep track of your net worth including cash, stocks, ETFs and cryptocurrencies across multiple platforms. - Ghostfolio est un dashboard de finances personnelles qui permet de suivre vos actifs comme les actions, les ETF ou les crypto-monnaies sur plusieurs plateformes. + Ghostfolio est un dashboard de finances personnelles qui permet de suivre vos actifs comme les actions, les ETF ou les crypto-monnaies sur plusieurs plateformes. apps/client/src/app/pages/i18n/i18n-page.html 4 @@ -5983,7 +5983,7 @@ Last All Time High - Last All Time High + Dernier All Time High libs/ui/src/lib/benchmark/benchmark.component.html 65 @@ -5991,7 +5991,7 @@ User - User + Utilisateurs apps/client/src/app/components/admin-users/admin-users.html 29 @@ -6007,7 +6007,7 @@ Open Source Wealth Management Software - Open Source Wealth Management Software + Logiciel libre de Gestion de Patrimoine apps/client/src/app/pages/i18n/i18n-page.html 14 @@ -6015,7 +6015,7 @@ app, asset, cryptocurrency, dashboard, etf, finance, management, performance, portfolio, software, stock, trading, wealth, web3 - app, asset, cryptocurrency, dashboard, etf, finance, management, performance, portfolio, software, stock, trading, wealth, web3 + application, actif, cryptomonnaies, dashboard, etf, finance, gestion, performance, portefeuille, logiciel, action, trading, patrimoine, web3 apps/client/src/app/pages/i18n/i18n-page.html 9 @@ -6023,7 +6023,7 @@ Oops, cash balance transfer has failed. - Oops, cash balance transfer has failed. + Oops, échec du transfert de la cash balance. apps/client/src/app/pages/accounts/accounts-page.component.ts 311 @@ -6031,7 +6031,7 @@ Extreme Fear - Extreme Fear + Extreme Peur libs/ui/src/lib/i18n.ts 94 @@ -6039,7 +6039,7 @@ Extreme Greed - Extreme Greed + Extreme Cupidité libs/ui/src/lib/i18n.ts 95 @@ -6047,7 +6047,7 @@ Neutral - Neutral + Neutre libs/ui/src/lib/i18n.ts 98 @@ -6055,7 +6055,7 @@ Oops! Could not parse historical data. - Oops! Could not parse historical data. + Oops! Echec du parsing des données historiques. apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 237 @@ -6063,7 +6063,7 @@ Do you really want to delete this system message? - Do you really want to delete this system message? + Confirmer la suppresion de ce message système? apps/client/src/app/components/admin-overview/admin-overview.component.ts 178 @@ -6071,7 +6071,7 @@ 50-Day Trend - 50-Day Trend + Tendance 50 jours libs/ui/src/lib/benchmark/benchmark.component.html 15 @@ -6079,7 +6079,7 @@ 200-Day Trend - 200-Day Trend + Tendance 200 jours libs/ui/src/lib/benchmark/benchmark.component.html 40 @@ -6087,7 +6087,7 @@ Cash Balances - Cash Balances + Cash Balances apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html 122 @@ -6095,7 +6095,7 @@ Starting from - Starting from + A partir de apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 204 @@ -6107,7 +6107,7 @@ year - year + années apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 205 @@ -6119,7 +6119,7 @@ Do you really want to delete this account balance? - Do you really want to delete this account balance? + Voulez-vous vraiment supprimer ce solde de compte ? libs/ui/src/lib/account-balances/account-balances.component.ts 110 @@ -6127,7 +6127,7 @@ is an invalid currency! - is an invalid currency! + est une devise non valide ! apps/client/src/app/components/admin-overview/admin-overview.component.ts 133 @@ -6135,7 +6135,7 @@ If a translation is missing, kindly support us in extending it here. - If a translation is missing, kindly support us in extending it here. + Si une traduction est manquante, veuillez nous aider à compléter la traduction here. apps/client/src/app/components/user-account-settings/user-account-settings.html 50 @@ -6143,7 +6143,7 @@ The current market price is - The current market price is + Le prix actuel du marché est apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 345 @@ -6151,7 +6151,7 @@ Test - Test + Test apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 322 @@ -6159,7 +6159,7 @@ Date Range - Date Range + Intervalle de Date libs/ui/src/lib/assistant/assistant.html 93 @@ -6167,7 +6167,7 @@ Permission - Permission + Autorisation apps/client/src/app/components/access-table/access-table.component.html 18 @@ -6179,7 +6179,7 @@ Restricted view - Restricted view + Vue restreinte apps/client/src/app/components/access-table/access-table.component.html 26 @@ -6191,7 +6191,7 @@ Oops! Could not grant access. - Oops! Could not grant access. + Oops! Impossible d'accorder l'accès. apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts 91 @@ -6199,7 +6199,7 @@ Private - Private + Privée apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 24 @@ -6207,7 +6207,7 @@ Job Queue - Job Queue + File d'attente apps/client/src/app/pages/admin/admin-page-routing.module.ts 25 @@ -6219,7 +6219,7 @@ Market data is delayed for - Market data is delayed for + Les données du marché sont retardées de apps/client/src/app/components/portfolio-performance/portfolio-performance.component.ts 86 @@ -6227,7 +6227,7 @@ Investment - Investment + Investissement apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts 42 @@ -6243,7 +6243,7 @@ Absolute Asset Performance - Absolute Asset Performance + Performance des Actifs en valeur absolue apps/client/src/app/pages/portfolio/analysis/analysis-page.html 29 @@ -6251,7 +6251,7 @@ Asset Performance - Asset Performance + Performance des Actifs apps/client/src/app/pages/portfolio/analysis/analysis-page.html 50 @@ -6259,7 +6259,7 @@ Absolute Currency Performance - Absolute Currency Performance + Performance des devises en valeur absolue apps/client/src/app/pages/portfolio/analysis/analysis-page.html 72 @@ -6267,7 +6267,7 @@ Currency Performance - Currency Performance + Performance des devises apps/client/src/app/pages/portfolio/analysis/analysis-page.html 96 @@ -6275,7 +6275,7 @@ Absolute Net Performance - Absolute Net Performance + Performance nette absolue apps/client/src/app/pages/portfolio/analysis/analysis-page.html 119 @@ -6283,7 +6283,7 @@ Net Performance - Net Performance + Performance nette apps/client/src/app/pages/portfolio/analysis/analysis-page.html 138 @@ -6291,7 +6291,7 @@ Week to date - Week to date + Week to date libs/ui/src/lib/assistant/assistant.component.ts 217 @@ -6299,7 +6299,7 @@ WTD - WTD + WTD libs/ui/src/lib/assistant/assistant.component.ts 217 @@ -6307,7 +6307,7 @@ Month to date - Month to date + Month to date libs/ui/src/lib/assistant/assistant.component.ts 221 @@ -6315,7 +6315,7 @@ MTD - MTD + MTD libs/ui/src/lib/assistant/assistant.component.ts 221 @@ -6323,7 +6323,7 @@ Year to date - Year to date + Year to date libs/ui/src/lib/assistant/assistant.component.ts 225 @@ -6331,7 +6331,7 @@ View - View + Vue apps/client/src/app/components/access-table/access-table.component.html 23 @@ -6343,7 +6343,7 @@ Oops! A data provider is experiencing the hiccups. - Oops! A data provider is experiencing the hiccups. + Oops! Un fournisseur de données rencontre des difficultés. apps/client/src/app/components/portfolio-performance/portfolio-performance.component.html 8 @@ -6351,7 +6351,7 @@ If you retire today, you would be able to withdraw per year or per month, based on your total assets of and a withdrawal rate of 4%. - If you retire today, you would be able to withdraw per year or per month, based on your total assets of and a withdrawal rate of 4%. + Si vous prenez votre retraite aujourd'hui, vous pourrez retirer par an ou par mois, sur la base de vos actifs totaux de et un taux de retrait de 4 %. apps/client/src/app/pages/portfolio/fire/fire-page.html 67 @@ -6359,7 +6359,7 @@ Reset Filters - Reset Filters + Réinitialiser les Filtres libs/ui/src/lib/assistant/assistant.html 155 @@ -6367,7 +6367,7 @@ year - year + année libs/ui/src/lib/assistant/assistant.component.ts 229 @@ -6375,7 +6375,7 @@ years - years + années libs/ui/src/lib/assistant/assistant.component.ts 250 @@ -6383,7 +6383,7 @@ Asset Classes - Asset Classes + Types d'Actifs libs/ui/src/lib/assistant/assistant.html 138 @@ -6391,7 +6391,7 @@ Apply Filters - Apply Filters + Appliquer les Filtres libs/ui/src/lib/assistant/assistant.html 165 @@ -6399,7 +6399,7 @@ Data Gathering - Data Gathering + Collecter les données apps/client/src/app/components/admin-overview/admin-overview.html 136 @@ -6407,7 +6407,7 @@ General - General + Général apps/client/src/app/pages/faq/faq-page.component.ts 36 @@ -6415,7 +6415,7 @@ Cloud - Cloud + Cloud apps/client/src/app/pages/faq/faq-page.component.ts 41 @@ -6427,7 +6427,7 @@ Self-Hosting - Self-Hosting + Self-Hosting apps/client/src/app/pages/faq/faq-page.component.ts 47 @@ -6439,7 +6439,7 @@ self-hosting - self-hosting + self-hosting apps/client/src/app/pages/faq/faq-page.component.ts 48 @@ -6447,7 +6447,7 @@ FAQ - FAQ + FAQ apps/client/src/app/pages/faq/saas/saas-page-routing.module.ts 13 @@ -6459,7 +6459,7 @@ Oops! It looks like you’re making too many requests. Please slow down a bit. - Oops! It looks like you’re making too many requests. Please slow down a bit. + Oops! Il semble que vous fassiez trop de requêtes. Veuillez ralentir un peu. apps/client/src/app/core/http-response.interceptor.ts 96 @@ -6467,7 +6467,7 @@ My Account - My Account + Mon Compte apps/client/src/app/pages/i18n/i18n-page.html 13 @@ -6475,7 +6475,7 @@ Active - Active + Actif apps/client/src/app/components/home-holdings/home-holdings.component.ts 38 @@ -6483,7 +6483,7 @@ Closed - Closed + Clôturé apps/client/src/app/components/home-holdings/home-holdings.component.ts 39 @@ -6491,7 +6491,7 @@ Activity - Activity + Activitées apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html 223 @@ -6499,7 +6499,7 @@ Dividend Yield - Dividend Yield + Rendement en Dividende apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html 191 @@ -6507,7 +6507,7 @@ Execute Job - Execute Job + Execute la tâche apps/client/src/app/components/admin-jobs/admin-jobs.html 174 @@ -6515,7 +6515,7 @@ Priority - Priority + Priorité apps/client/src/app/components/admin-jobs/admin-jobs.html 62 @@ -6523,7 +6523,7 @@ This action is not allowed. - This action is not allowed. + Cette action n'est pas autorisée. apps/client/src/app/core/http-response.interceptor.ts 61 @@ -6531,7 +6531,7 @@ Liquidity - Liquidity + Liquiditées libs/ui/src/lib/i18n.ts 47 @@ -6539,7 +6539,7 @@ Change with currency effect - Change with currency effect + Variation avec impact des devises apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html 53 @@ -6547,7 +6547,7 @@ Performance with currency effect - Performance with currency effect + Performance avec impact des devises apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html 81 @@ -6555,7 +6555,7 @@ {VAR_PLURAL, plural, =1 {activity} other {activities}} - {VAR_PLURAL, plural, =1 {activity} other {activities}} + {VAR_PLURAL, plural, =1 {activity} autres {activities}} apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html 14 @@ -6563,7 +6563,7 @@ Buy and sell - Buy and sell + Achat et Vente libs/ui/src/lib/i18n.ts 8 @@ -6571,7 +6571,7 @@ Delete Activities - Delete Activities + Supprimer les Activitées libs/ui/src/lib/activities-table/activities-table.component.html 66 @@ -6579,7 +6579,7 @@ Internationalization - Internationalization + Internationalisation apps/client/src/app/app-routing.module.ts 79 @@ -6587,7 +6587,7 @@ Do you really want to close your Ghostfolio account? - Do you really want to close your Ghostfolio account? + Confirmer la suppresion de votre compte Ghostfolio ? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts 174 @@ -6595,7 +6595,7 @@ Danger Zone - Danger Zone + Zone de danger apps/client/src/app/components/user-account-settings/user-account-settings.html 244 @@ -6603,7 +6603,7 @@ Close Account - Close Account + Supprimer le compte apps/client/src/app/components/user-account-settings/user-account-settings.html 279 @@ -6611,7 +6611,7 @@ By ETF Holding - By ETF Holding + Par détention ETF apps/client/src/app/pages/portfolio/allocations/allocations-page.html 333 @@ -6619,7 +6619,7 @@ Approximation based on the top holdings of each ETF - Approximation based on the top holdings of each ETF + Approximation basée sur les principaux titres de chaque ETF apps/client/src/app/pages/portfolio/allocations/allocations-page.html 340 @@ -6627,7 +6627,7 @@ Join now or check out the example account - Join now or check out the example account + Rejoindre ou voir un compte démo apps/client/src/app/pages/landing/landing-page.html 434 @@ -6635,7 +6635,7 @@ Oops! There was an error setting up biometric authentication. - Oops! There was an error setting up biometric authentication. + Oops! Une erreur s'est produite lors de la configuration de l'authentification biométrique. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts 308 @@ -6643,7 +6643,7 @@ Show more - Show more + Voir plus libs/ui/src/lib/top-holdings/top-holdings.component.html 81 @@ -6651,7 +6651,7 @@ Benchmarks - Benchmarks + Benchmarks apps/client/src/app/components/admin-market-data/admin-market-data.component.ts 80 @@ -6659,7 +6659,7 @@ Delete Profiles - Delete Profiles + Supprimer des Profils apps/client/src/app/components/admin-market-data/admin-market-data.html 190 @@ -6667,7 +6667,7 @@ Do you really want to delete these profiles? - Do you really want to delete these profiles? + Confirmer la suppression de ces Profils? apps/client/src/app/components/admin-market-data/admin-market-data.service.ts 65 @@ -6675,7 +6675,7 @@ Oops! Could not delete profiles. - Oops! Could not delete profiles. + Oops! Echec de la suppression de Profils. apps/client/src/app/components/admin-market-data/admin-market-data.service.ts 52 @@ -6683,7 +6683,7 @@ Table - Table + Table apps/client/src/app/components/home-holdings/home-holdings.html 17 @@ -6691,7 +6691,7 @@ Chart - Chart + Tableau apps/client/src/app/components/home-holdings/home-holdings.html 20 @@ -6699,7 +6699,7 @@ Would you like to refine your personal investment strategy? - Would you like to refine your personal investment strategy? + Souhaitez-vous affiner votre stratégie d'investissement personnelle? apps/client/src/app/pages/public/public-page.html 155 @@ -6707,7 +6707,7 @@ Alternative - Alternative + Alternative apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 83 @@ -6715,7 +6715,7 @@ App - App + App apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 84 @@ -6723,7 +6723,7 @@ Budgeting - Budgeting + Budget apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 85 @@ -6731,7 +6731,7 @@ Community - Community + Communauté apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 86 @@ -6739,7 +6739,7 @@ Family Office - Family Office + Family Office apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 87 @@ -6747,7 +6747,7 @@ Investor - Investor + Investisseur apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 90 @@ -6755,7 +6755,7 @@ Open Source - Open Source + Open Source apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 91 @@ -6763,7 +6763,7 @@ Personal Finance - Personal Finance + Gestion de Patrimoine apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 93 @@ -6771,7 +6771,7 @@ Privacy - Privacy + Confidentialité apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 94 @@ -6779,7 +6779,7 @@ Software - Software + Logiciels apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 96 @@ -6787,7 +6787,7 @@ Tool - Tool + Outils apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 97 @@ -6795,7 +6795,7 @@ User Experience - User Experience + Expérience Utilisateur apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 98 @@ -6803,7 +6803,7 @@ Wealth - Wealth + Patrimoine apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 99 @@ -6811,7 +6811,7 @@ Wealth Management - Wealth Management + Gestion de Patrimoine apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 100 @@ -6819,7 +6819,7 @@ Australia - Australia + Australie libs/ui/src/lib/i18n.ts 72 @@ -6827,7 +6827,7 @@ Austria - Austria + Autriche libs/ui/src/lib/i18n.ts 73 @@ -6835,7 +6835,7 @@ Belgium - Belgium + Belgique libs/ui/src/lib/i18n.ts 74 @@ -6843,7 +6843,7 @@ Bulgaria - Bulgaria + Bulgarie libs/ui/src/lib/i18n.ts 75 @@ -6851,7 +6851,7 @@ Canada - Canada + Canada libs/ui/src/lib/i18n.ts 76 @@ -6859,7 +6859,7 @@ Czech Republic - Czech Republic + République Tchèque libs/ui/src/lib/i18n.ts 77 @@ -6867,7 +6867,7 @@ Finland - Finland + Finlande libs/ui/src/lib/i18n.ts 78 @@ -6875,7 +6875,7 @@ France - France + France libs/ui/src/lib/i18n.ts 79 @@ -6883,7 +6883,7 @@ Germany - Germany + Allemagne libs/ui/src/lib/i18n.ts 80 @@ -6891,7 +6891,7 @@ India - India + Inde libs/ui/src/lib/i18n.ts 81 @@ -6899,7 +6899,7 @@ Italy - Italy + Italie libs/ui/src/lib/i18n.ts 82 @@ -6907,7 +6907,7 @@ Netherlands - Netherlands + Pays-Bas libs/ui/src/lib/i18n.ts 84 @@ -6915,7 +6915,7 @@ New Zealand - New Zealand + Nouvelle-Zélande libs/ui/src/lib/i18n.ts 85 @@ -6923,7 +6923,7 @@ Poland - Poland + Pologne libs/ui/src/lib/i18n.ts 86 @@ -6931,7 +6931,7 @@ Romania - Romania + Roumanie libs/ui/src/lib/i18n.ts 87 @@ -6939,7 +6939,7 @@ South Africa - South Africa + Afrique du Sud libs/ui/src/lib/i18n.ts 88 @@ -6947,7 +6947,7 @@ Thailand - Thailand + Thaïlande libs/ui/src/lib/i18n.ts 90 @@ -6955,7 +6955,7 @@ United States - United States + Etats-Unis libs/ui/src/lib/i18n.ts 91 @@ -6963,7 +6963,7 @@ Error - Error + Erreur apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 336 @@ -6971,7 +6971,7 @@ Deactivate - Deactivate + Désactiver apps/client/src/app/components/rule/rule.component.html 67 @@ -6979,7 +6979,7 @@ Activate - Activate + Activer apps/client/src/app/components/rule/rule.component.html 69 @@ -6987,7 +6987,7 @@ Inactive - Inactive + Inactif apps/client/src/app/pages/portfolio/fire/fire-page.html 194 @@ -6995,7 +6995,7 @@ Cancel - Cancel + Annuler libs/ui/src/lib/i18n.ts 9 @@ -7003,7 +7003,7 @@ Close - Close + Fermer libs/ui/src/lib/i18n.ts 11 @@ -7011,7 +7011,7 @@ Yes - Yes + Oui libs/ui/src/lib/i18n.ts 31 From a5211f6a2977d02a2243123b1834d2bcd427923e Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Tue, 10 Sep 2024 20:01:37 +0200 Subject: [PATCH 32/78] Feature/upgrade bull to version 4.16.2 (#3746) * Upgrade bull to version 4.16.2 * Update changelog --- CHANGELOG.md | 1 + package-lock.json | 29 ++++++++++------------------- package.json | 2 +- 3 files changed, 12 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7cbc0519f..ef6904603 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 - Extracted the users from the admin control panel endpoint to a dedicated endpoint - Improved the language localization for French (`fr`) - Improved the language localization for Italian (`it`) +- Upgraded `bull` from version `4.10.4` to `4.16.2` ## 2.106.0 - 2024-09-07 diff --git a/package-lock.json b/package-lock.json index fbb54d4e2..5f20e8427 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ghostfolio", - "version": "2.106.0-beta.3", + "version": "2.106.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ghostfolio", - "version": "2.106.0-beta.3", + "version": "2.106.0", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { @@ -48,7 +48,7 @@ "big.js": "6.2.1", "body-parser": "1.20.2", "bootstrap": "4.6.0", - "bull": "4.10.4", + "bull": "4.16.2", "cache-manager": "5.7.6", "cache-manager-redis-yet": "5.1.4", "chart.js": "4.2.0", @@ -14158,17 +14158,17 @@ } }, "node_modules/bull": { - "version": "4.10.4", - "resolved": "https://registry.npmjs.org/bull/-/bull-4.10.4.tgz", - "integrity": "sha512-o9m/7HjS/Or3vqRd59evBlWCXd9Lp+ALppKseoSKHaykK46SmRjAilX98PgmOz1yeVaurt8D5UtvEt4bUjM3eA==", + "version": "4.16.2", + "resolved": "https://registry.npmjs.org/bull/-/bull-4.16.2.tgz", + "integrity": "sha512-VCy33UdPGiIoZHDTrslGXKXWxcIUHNH5Z82pihr8HicbIfAH4SHug1HxlwKEbibVv85hq8rJ9tKAW/cuxv2T0A==", + "license": "MIT", "dependencies": { "cron-parser": "^4.2.1", - "debuglog": "^1.0.0", "get-port": "^5.1.1", - "ioredis": "^5.0.0", + "ioredis": "^5.3.2", "lodash": "^4.17.21", - "msgpackr": "^1.5.2", - "semver": "^7.3.2", + "msgpackr": "^1.10.1", + "semver": "^7.5.2", "uuid": "^8.3.0" }, "engines": { @@ -16776,15 +16776,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, - "node_modules/debuglog": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", - "integrity": "sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw==", - "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", - "engines": { - "node": "*" - } - }, "node_modules/decimal.js": { "version": "10.4.3", "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", diff --git a/package.json b/package.json index 81eb3859f..244ca0d7a 100644 --- a/package.json +++ b/package.json @@ -92,7 +92,7 @@ "big.js": "6.2.1", "body-parser": "1.20.2", "bootstrap": "4.6.0", - "bull": "4.10.4", + "bull": "4.16.2", "cache-manager": "5.7.6", "cache-manager-redis-yet": "5.1.4", "chart.js": "4.2.0", From 383a02519a03aa96d12ec3f3464a488f741b3d2c Mon Sep 17 00:00:00 2001 From: Shaunak Das <51281688+shaun-ak@users.noreply.github.com> Date: Tue, 10 Sep 2024 23:52:51 +0530 Subject: [PATCH 33/78] Feature/extend filters of order endpoint (#3743) * Extend filters of order endpoint * Update changelog --------- Co-authored-by: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> --- CHANGELOG.md | 4 +++ apps/api/src/app/order/order.controller.ts | 5 +++ apps/api/src/app/order/order.service.ts | 31 +++++++++++++++++++ ...form-data-source-in-request.interceptor.ts | 10 +++--- apps/api/src/services/api/api.service.ts | 20 ++++++++++++ .../holding-detail-dialog.component.ts | 20 +++++++++--- .../holding-detail-dialog.html | 5 +-- apps/client/src/app/services/data.service.ts | 10 ++++++ .../src/lib/interfaces/filter.interface.ts | 1 + 9 files changed, 95 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ef6904603..db47c8b61 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Added + +- Extended the filters of the activities endpoint by `dataSource` and `symbol` + ### Changed - Optimized the asynchronous operations using `Promise.all()` in the info service diff --git a/apps/api/src/app/order/order.controller.ts b/apps/api/src/app/order/order.controller.ts index 7a9cf3d17..f2acac5e4 100644 --- a/apps/api/src/app/order/order.controller.ts +++ b/apps/api/src/app/order/order.controller.ts @@ -94,15 +94,18 @@ export class OrderController { @Get() @UseGuards(AuthGuard('jwt'), HasPermissionGuard) @UseInterceptors(RedactValuesInResponseInterceptor) + @UseInterceptors(TransformDataSourceInRequestInterceptor) @UseInterceptors(TransformDataSourceInResponseInterceptor) public async getAllOrders( @Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId, @Query('accounts') filterByAccounts?: string, @Query('assetClasses') filterByAssetClasses?: string, + @Query('dataSource') filterByDataSource?: string, @Query('range') dateRange?: DateRange, @Query('skip') skip?: number, @Query('sortColumn') sortColumn?: string, @Query('sortDirection') sortDirection?: Prisma.SortOrder, + @Query('symbol') filterBySymbol?: string, @Query('tags') filterByTags?: string, @Query('take') take?: number ): Promise { @@ -116,6 +119,8 @@ export class OrderController { const filters = this.apiService.buildFiltersFromQueryParams({ filterByAccounts, filterByAssetClasses, + filterByDataSource, + filterBySymbol, filterByTags }); diff --git a/apps/api/src/app/order/order.service.ts b/apps/api/src/app/order/order.service.ts index d9ff68d61..dcbc20e2b 100644 --- a/apps/api/src/app/order/order.service.ts +++ b/apps/api/src/app/order/order.service.ts @@ -350,6 +350,14 @@ export class OrderService { return type; }); + const filterByDataSource = filters?.find(({ type }) => { + return type === 'DATA_SOURCE'; + })?.id; + + const filterBySymbol = filters?.find(({ type }) => { + return type === 'SYMBOL'; + })?.id; + const searchQuery = filters?.find(({ type }) => { return type === 'SEARCH_QUERY'; })?.id; @@ -395,6 +403,29 @@ export class OrderService { }; } + if (filterByDataSource && filterBySymbol) { + if (where.SymbolProfile) { + where.SymbolProfile = { + AND: [ + where.SymbolProfile, + { + AND: [ + { dataSource: filterByDataSource }, + { symbol: filterBySymbol } + ] + } + ] + }; + } else { + where.SymbolProfile = { + AND: [ + { dataSource: filterByDataSource }, + { symbol: filterBySymbol } + ] + }; + } + } + if (searchQuery) { const searchQueryWhereInput: Prisma.SymbolProfileWhereInput[] = [ { id: { mode: 'insensitive', startsWith: searchQuery } }, diff --git a/apps/api/src/interceptors/transform-data-source-in-request/transform-data-source-in-request.interceptor.ts b/apps/api/src/interceptors/transform-data-source-in-request/transform-data-source-in-request.interceptor.ts index df99c2da3..227d06d7b 100644 --- a/apps/api/src/interceptors/transform-data-source-in-request/transform-data-source-in-request.interceptor.ts +++ b/apps/api/src/interceptors/transform-data-source-in-request/transform-data-source-in-request.interceptor.ts @@ -39,12 +39,12 @@ export class TransformDataSourceInRequestInterceptor }); } - if (request.body.dataSource && !DataSource[request.body.dataSource]) { - request.body.dataSource = decodeDataSource(request.body.dataSource); - } + for (const type of ['body', 'params', 'query']) { + const dataSourceValue = request[type]?.dataSource; - if (request.params.dataSource && !DataSource[request.params.dataSource]) { - request.params.dataSource = decodeDataSource(request.params.dataSource); + if (dataSourceValue && !DataSource[dataSourceValue]) { + request[type].dataSource = decodeDataSource(dataSourceValue); + } } } diff --git a/apps/api/src/services/api/api.service.ts b/apps/api/src/services/api/api.service.ts index e961ec037..5bcc6bb1d 100644 --- a/apps/api/src/services/api/api.service.ts +++ b/apps/api/src/services/api/api.service.ts @@ -10,22 +10,28 @@ export class ApiService { filterByAccounts, filterByAssetClasses, filterByAssetSubClasses, + filterByDataSource, filterByHoldingType, filterBySearchQuery, + filterBySymbol, filterByTags }: { filterByAccounts?: string; filterByAssetClasses?: string; filterByAssetSubClasses?: string; + filterByDataSource?: string; filterByHoldingType?: string; filterBySearchQuery?: string; + filterBySymbol?: string; filterByTags?: string; }): Filter[] { const accountIds = filterByAccounts?.split(',') ?? []; const assetClasses = filterByAssetClasses?.split(',') ?? []; const assetSubClasses = filterByAssetSubClasses?.split(',') ?? []; + const dataSource = filterByDataSource; const holdingType = filterByHoldingType; const searchQuery = filterBySearchQuery?.toLowerCase(); + const symbol = filterBySymbol; const tagIds = filterByTags?.split(',') ?? []; const filters = [ @@ -55,6 +61,13 @@ export class ApiService { }) ]; + if (dataSource) { + filters.push({ + id: dataSource, + type: 'DATA_SOURCE' + }); + } + if (holdingType) { filters.push({ id: holdingType, @@ -69,6 +82,13 @@ export class ApiService { }); } + if (symbol) { + filters.push({ + id: symbol, + type: 'SYMBOL' + }); + } + return filters; } } diff --git a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts index 64c062c7e..70cd08874 100644 --- a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts +++ b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts @@ -89,7 +89,6 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { public activityForm: FormGroup; public accounts: Account[]; - public activities: Activity[]; public assetClass: string; public assetSubClass: string; public averagePrice: number; @@ -174,6 +173,22 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { .subscribe(); }); + this.dataService + .fetchActivities({ + filters: [ + { id: this.data.dataSource, type: 'DATA_SOURCE' }, + { id: this.data.symbol, type: 'SYMBOL' } + ], + sortColumn: this.sortColumn, + sortDirection: this.sortDirection + }) + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe(({ activities }) => { + this.dataSource = new MatTableDataSource(activities); + + this.changeDetectorRef.markForCheck(); + }); + this.dataService .fetchHoldingDetail({ dataSource: this.data.dataSource, @@ -198,7 +213,6 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { netPerformancePercent, netPerformancePercentWithCurrencyEffect, netPerformanceWithCurrencyEffect, - orders, quantity, SymbolProfile, tags, @@ -206,12 +220,10 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { value }) => { this.accounts = accounts; - this.activities = orders; this.averagePrice = averagePrice; this.benchmarkDataItems = []; this.countries = {}; this.dataProviderInfo = dataProviderInfo; - this.dataSource = new MatTableDataSource(orders.reverse()); this.dividendInBaseCurrency = dividendInBaseCurrency; if ( diff --git a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html index fab5bc452..f92ad54f8 100644 --- a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html +++ b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -311,7 +311,7 @@ animationDuration="0" class="mb-5" [mat-stretch-tabs]="false" - [ngClass]="{ 'd-none': !activities?.length }" + [ngClass]="{ 'd-none': !dataSource?.data.length }" > @@ -422,7 +422,8 @@ } @if ( - activities?.length > 0 && data.hasPermissionToReportDataGlitch === true + dataSource?.data.length > 0 && + data.hasPermissionToReportDataGlitch === true ) {
diff --git a/apps/client/src/app/services/data.service.ts b/apps/client/src/app/services/data.service.ts index 6de3d327d..64376a606 100644 --- a/apps/client/src/app/services/data.service.ts +++ b/apps/client/src/app/services/data.service.ts @@ -72,14 +72,24 @@ export class DataService { ACCOUNT: filtersByAccount, ASSET_CLASS: filtersByAssetClass, ASSET_SUB_CLASS: filtersByAssetSubClass, + DATA_SOURCE: [filterByDataSource], HOLDING_TYPE: filtersByHoldingType, PRESET_ID: filtersByPresetId, SEARCH_QUERY: filtersBySearchQuery, + SYMBOL: [filterBySymbol], TAG: filtersByTag } = groupBy(filters, (filter) => { return filter.type; }); + if (filterByDataSource) { + params = params.append('dataSource', filterByDataSource.id); + } + + if (filterBySymbol) { + params = params.append('symbol', filterBySymbol.id); + } + if (filtersByAccount) { params = params.append( 'accounts', diff --git a/libs/common/src/lib/interfaces/filter.interface.ts b/libs/common/src/lib/interfaces/filter.interface.ts index 3d555f796..43634f876 100644 --- a/libs/common/src/lib/interfaces/filter.interface.ts +++ b/libs/common/src/lib/interfaces/filter.interface.ts @@ -5,6 +5,7 @@ export interface Filter { | 'ACCOUNT' | 'ASSET_CLASS' | 'ASSET_SUB_CLASS' + | 'DATA_SOURCE' | 'HOLDING_TYPE' | 'PRESET_ID' | 'SEARCH_QUERY' From 403ee2741d2436f9c496da5465163367ef9f4039 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Tue, 10 Sep 2024 20:32:08 +0200 Subject: [PATCH 34/78] Feature/set up portfolio snapshot queue (#3725) * Set up portfolio snapshot queue * Update changelog --- CHANGELOG.md | 1 + apps/api/src/app/admin/admin.controller.ts | 2 +- apps/api/src/app/admin/admin.module.ts | 2 +- apps/api/src/app/admin/queue/queue.module.ts | 5 +- apps/api/src/app/admin/queue/queue.service.ts | 36 +++++-- apps/api/src/app/app.module.ts | 4 +- apps/api/src/app/import/import.module.ts | 2 +- apps/api/src/app/import/import.service.ts | 2 +- apps/api/src/app/info/info.module.ts | 2 +- apps/api/src/app/order/order.controller.ts | 2 +- apps/api/src/app/order/order.module.ts | 2 +- apps/api/src/app/order/order.service.ts | 2 +- .../portfolio-calculator.factory.ts | 4 + .../calculator/portfolio-calculator.ts | 75 +++++++++------ ...aln-buy-and-sell-in-two-activities.spec.ts | 26 ++++- ...folio-calculator-baln-buy-and-sell.spec.ts | 26 ++++- .../twr/portfolio-calculator-baln-buy.spec.ts | 26 ++++- ...ator-btcusd-buy-and-sell-partially.spec.ts | 26 ++++- .../twr/portfolio-calculator-fee.spec.ts | 26 ++++- .../portfolio-calculator-googl-buy.spec.ts | 26 ++++- .../twr/portfolio-calculator-item.spec.ts | 26 ++++- .../portfolio-calculator-liability.spec.ts | 31 ++++-- ...-calculator-msft-buy-with-dividend.spec.ts | 26 ++++- .../portfolio-calculator-no-orders.spec.ts | 28 ++++-- ...ulator-novn-buy-and-sell-partially.spec.ts | 26 ++++- ...folio-calculator-novn-buy-and-sell.spec.ts | 26 ++++- .../twr/portfolio-calculator.spec.ts | 9 +- .../api/src/app/portfolio/portfolio.module.ts | 4 +- .../redis-cache/redis-cache.service.mock.ts | 21 +++- apps/api/src/services/cron.service.ts | 2 +- .../data-gathering/data-gathering.module.ts | 2 +- .../data-gathering.processor.ts | 13 ++- .../data-gathering/data-gathering.service.ts | 8 +- .../portfolio-snapshot-queue-job.interface.ts | 7 ++ .../portfolio-snapshot.module.ts | 37 +++++++ .../portfolio-snapshot.processor.ts | 96 +++++++++++++++++++ .../portfolio-snapshot.service.mock.ts | 34 +++++++ .../portfolio-snapshot.service.ts | 31 ++++++ .../app/components/admin-jobs/admin-jobs.html | 2 + libs/common/src/lib/config.ts | 14 ++- 40 files changed, 621 insertions(+), 119 deletions(-) rename apps/api/src/services/{ => queues}/data-gathering/data-gathering.module.ts (93%) rename apps/api/src/services/{ => queues}/data-gathering/data-gathering.processor.ts (95%) rename apps/api/src/services/{ => queues}/data-gathering/data-gathering.service.ts (98%) create mode 100644 apps/api/src/services/queues/portfolio-snapshot/interfaces/portfolio-snapshot-queue-job.interface.ts create mode 100644 apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.module.ts create mode 100644 apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.processor.ts create mode 100644 apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock.ts create mode 100644 apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.service.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index db47c8b61..d1d6d787c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Migrated the portfolio snapshot calculation to the queue design pattern - Optimized the asynchronous operations using `Promise.all()` in the info service - Optimized the asynchronous operations using `Promise.all()` in the admin control panel endpoint - Extracted the users from the admin control panel endpoint to a dedicated endpoint diff --git a/apps/api/src/app/admin/admin.controller.ts b/apps/api/src/app/admin/admin.controller.ts index da4b5dd7e..e0444d112 100644 --- a/apps/api/src/app/admin/admin.controller.ts +++ b/apps/api/src/app/admin/admin.controller.ts @@ -2,10 +2,10 @@ import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorat import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard'; import { TransformDataSourceInRequestInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.interceptor'; import { ApiService } from '@ghostfolio/api/services/api/api.service'; -import { DataGatheringService } from '@ghostfolio/api/services/data-gathering/data-gathering.service'; import { ManualService } from '@ghostfolio/api/services/data-provider/manual/manual.service'; import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service'; import { PropertyDto } from '@ghostfolio/api/services/property/property.dto'; +import { DataGatheringService } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.service'; import { DATA_GATHERING_QUEUE_PRIORITY_HIGH, DATA_GATHERING_QUEUE_PRIORITY_MEDIUM, diff --git a/apps/api/src/app/admin/admin.module.ts b/apps/api/src/app/admin/admin.module.ts index f8cf8e8ac..81c58ff03 100644 --- a/apps/api/src/app/admin/admin.module.ts +++ b/apps/api/src/app/admin/admin.module.ts @@ -4,12 +4,12 @@ import { SubscriptionModule } from '@ghostfolio/api/app/subscription/subscriptio import { TransformDataSourceInRequestModule } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.module'; import { ApiModule } from '@ghostfolio/api/services/api/api.module'; import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module'; -import { DataGatheringModule } from '@ghostfolio/api/services/data-gathering/data-gathering.module'; import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module'; import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module'; import { 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 { DataGatheringModule } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.module'; import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/symbol-profile.module'; import { Module } from '@nestjs/common'; diff --git a/apps/api/src/app/admin/queue/queue.module.ts b/apps/api/src/app/admin/queue/queue.module.ts index 46ae3b8a5..22d1cefc6 100644 --- a/apps/api/src/app/admin/queue/queue.module.ts +++ b/apps/api/src/app/admin/queue/queue.module.ts @@ -1,4 +1,5 @@ -import { DataGatheringModule } from '@ghostfolio/api/services/data-gathering/data-gathering.module'; +import { DataGatheringModule } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.module'; +import { PortfolioSnapshotQueueModule } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.module'; import { Module } from '@nestjs/common'; @@ -7,7 +8,7 @@ import { QueueService } from './queue.service'; @Module({ controllers: [QueueController], - imports: [DataGatheringModule], + imports: [DataGatheringModule, PortfolioSnapshotQueueModule], providers: [QueueService] }) export class QueueModule {} diff --git a/apps/api/src/app/admin/queue/queue.service.ts b/apps/api/src/app/admin/queue/queue.service.ts index abae3cad1..7e4f0adb7 100644 --- a/apps/api/src/app/admin/queue/queue.service.ts +++ b/apps/api/src/app/admin/queue/queue.service.ts @@ -1,5 +1,6 @@ import { DATA_GATHERING_QUEUE, + PORTFOLIO_SNAPSHOT_QUEUE, QUEUE_JOB_STATUS_LIST } from '@ghostfolio/common/config'; import { AdminJobs } from '@ghostfolio/common/interfaces'; @@ -12,11 +13,19 @@ import { JobStatus, Queue } from 'bull'; export class QueueService { public constructor( @InjectQueue(DATA_GATHERING_QUEUE) - private readonly dataGatheringQueue: Queue + private readonly dataGatheringQueue: Queue, + @InjectQueue(PORTFOLIO_SNAPSHOT_QUEUE) + private readonly portfolioSnapshotQueue: Queue ) {} public async deleteJob(aId: string) { - return (await this.dataGatheringQueue.getJob(aId))?.remove(); + let job = await this.dataGatheringQueue.getJob(aId); + + if (!job) { + job = await this.portfolioSnapshotQueue.getJob(aId); + } + + return job?.remove(); } public async deleteJobs({ @@ -25,15 +34,21 @@ export class QueueService { status?: JobStatus[]; }) { for (const statusItem of status) { - await this.dataGatheringQueue.clean( - 300, - statusItem === 'waiting' ? 'wait' : statusItem - ); + const queueStatus = statusItem === 'waiting' ? 'wait' : statusItem; + + await this.dataGatheringQueue.clean(300, queueStatus); + await this.portfolioSnapshotQueue.clean(300, queueStatus); } } public async executeJob(aId: string) { - return (await this.dataGatheringQueue.getJob(aId))?.promote(); + let job = await this.dataGatheringQueue.getJob(aId); + + if (!job) { + job = await this.portfolioSnapshotQueue.getJob(aId); + } + + return job?.promote(); } public async getJobs({ @@ -43,10 +58,13 @@ export class QueueService { limit?: number; status?: JobStatus[]; }): Promise { - const jobs = await this.dataGatheringQueue.getJobs(status); + const [dataGatheringJobs, portfolioSnapshotJobs] = await Promise.all([ + this.dataGatheringQueue.getJobs(status), + this.portfolioSnapshotQueue.getJobs(status) + ]); const jobsWithState = await Promise.all( - jobs + [...dataGatheringJobs, ...portfolioSnapshotJobs] .filter((job) => { return job; }) diff --git a/apps/api/src/app/app.module.ts b/apps/api/src/app/app.module.ts index ca19d63bc..86d97eaf8 100644 --- a/apps/api/src/app/app.module.ts +++ b/apps/api/src/app/app.module.ts @@ -1,11 +1,12 @@ import { EventsModule } from '@ghostfolio/api/events/events.module'; import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module'; import { CronService } from '@ghostfolio/api/services/cron.service'; -import { DataGatheringModule } from '@ghostfolio/api/services/data-gathering/data-gathering.module'; import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module'; import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module'; import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module'; import { PropertyModule } from '@ghostfolio/api/services/property/property.module'; +import { DataGatheringModule } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.module'; +import { PortfolioSnapshotQueueModule } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.module'; import { TwitterBotModule } from '@ghostfolio/api/services/twitter-bot/twitter-bot.module'; import { DEFAULT_LANGUAGE_CODE, @@ -81,6 +82,7 @@ import { UserModule } from './user/user.module'; OrderModule, PlatformModule, PortfolioModule, + PortfolioSnapshotQueueModule, PrismaModule, PropertyModule, RedisCacheModule, diff --git a/apps/api/src/app/import/import.module.ts b/apps/api/src/app/import/import.module.ts index 47a4b5db3..142a939a6 100644 --- a/apps/api/src/app/import/import.module.ts +++ b/apps/api/src/app/import/import.module.ts @@ -7,10 +7,10 @@ import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.mo import { TransformDataSourceInRequestModule } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.module'; import { TransformDataSourceInResponseModule } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.module'; import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module'; -import { DataGatheringModule } from '@ghostfolio/api/services/data-gathering/data-gathering.module'; import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module'; import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module'; import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module'; +import { DataGatheringModule } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.module'; import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/symbol-profile.module'; import { Module } from '@nestjs/common'; diff --git a/apps/api/src/app/import/import.service.ts b/apps/api/src/app/import/import.service.ts index 30ab87069..c42cd300b 100644 --- a/apps/api/src/app/import/import.service.ts +++ b/apps/api/src/app/import/import.service.ts @@ -9,9 +9,9 @@ import { OrderService } from '@ghostfolio/api/app/order/order.service'; import { PlatformService } from '@ghostfolio/api/app/platform/platform.service'; import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; -import { DataGatheringService } from '@ghostfolio/api/services/data-gathering/data-gathering.service'; import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; +import { DataGatheringService } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.service'; import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service'; import { DATA_GATHERING_QUEUE_PRIORITY_HIGH } from '@ghostfolio/common/config'; import { diff --git a/apps/api/src/app/info/info.module.ts b/apps/api/src/app/info/info.module.ts index 473a966ad..9b7854160 100644 --- a/apps/api/src/app/info/info.module.ts +++ b/apps/api/src/app/info/info.module.ts @@ -4,10 +4,10 @@ import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.mo import { UserModule } from '@ghostfolio/api/app/user/user.module'; import { TransformDataSourceInResponseModule } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.module'; import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module'; -import { DataGatheringModule } from '@ghostfolio/api/services/data-gathering/data-gathering.module'; import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module'; import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module'; import { PropertyModule } from '@ghostfolio/api/services/property/property.module'; +import { DataGatheringModule } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.module'; import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/symbol-profile.module'; import { TagModule } from '@ghostfolio/api/services/tag/tag.module'; diff --git a/apps/api/src/app/order/order.controller.ts b/apps/api/src/app/order/order.controller.ts index f2acac5e4..907335aa0 100644 --- a/apps/api/src/app/order/order.controller.ts +++ b/apps/api/src/app/order/order.controller.ts @@ -4,8 +4,8 @@ import { RedactValuesInResponseInterceptor } from '@ghostfolio/api/interceptors/ import { TransformDataSourceInRequestInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.interceptor'; import { TransformDataSourceInResponseInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor'; import { ApiService } from '@ghostfolio/api/services/api/api.service'; -import { DataGatheringService } from '@ghostfolio/api/services/data-gathering/data-gathering.service'; import { ImpersonationService } from '@ghostfolio/api/services/impersonation/impersonation.service'; +import { DataGatheringService } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.service'; import { getIntervalFromDateRange } from '@ghostfolio/common/calculation-helper'; import { DATA_GATHERING_QUEUE_PRIORITY_HIGH, diff --git a/apps/api/src/app/order/order.module.ts b/apps/api/src/app/order/order.module.ts index 55b4cce82..9bc837aa6 100644 --- a/apps/api/src/app/order/order.module.ts +++ b/apps/api/src/app/order/order.module.ts @@ -6,11 +6,11 @@ import { RedactValuesInResponseModule } from '@ghostfolio/api/interceptors/redac import { TransformDataSourceInRequestModule } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.module'; import { TransformDataSourceInResponseModule } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.module'; import { ApiModule } from '@ghostfolio/api/services/api/api.module'; -import { DataGatheringModule } from '@ghostfolio/api/services/data-gathering/data-gathering.module'; import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module'; import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module'; import { ImpersonationModule } from '@ghostfolio/api/services/impersonation/impersonation.module'; import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module'; +import { DataGatheringModule } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.module'; import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/symbol-profile.module'; import { Module } from '@nestjs/common'; diff --git a/apps/api/src/app/order/order.service.ts b/apps/api/src/app/order/order.service.ts index dcbc20e2b..8e69aae6f 100644 --- a/apps/api/src/app/order/order.service.ts +++ b/apps/api/src/app/order/order.service.ts @@ -1,9 +1,9 @@ import { AccountService } from '@ghostfolio/api/app/account/account.service'; import { PortfolioChangedEvent } from '@ghostfolio/api/events/portfolio-changed.event'; import { LogPerformance } from '@ghostfolio/api/interceptors/performance-logging/performance-logging.interceptor'; -import { DataGatheringService } from '@ghostfolio/api/services/data-gathering/data-gathering.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; +import { DataGatheringService } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.service'; import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service'; import { DATA_GATHERING_QUEUE_PRIORITY_HIGH, diff --git a/apps/api/src/app/portfolio/calculator/portfolio-calculator.factory.ts b/apps/api/src/app/portfolio/calculator/portfolio-calculator.factory.ts index b531ffc9d..18738373e 100644 --- a/apps/api/src/app/portfolio/calculator/portfolio-calculator.factory.ts +++ b/apps/api/src/app/portfolio/calculator/portfolio-calculator.factory.ts @@ -3,6 +3,7 @@ import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.s import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; +import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service'; import { Filter, HistoricalDataItem } from '@ghostfolio/common/interfaces'; import { Injectable } from '@nestjs/common'; @@ -22,6 +23,7 @@ export class PortfolioCalculatorFactory { private readonly configurationService: ConfigurationService, private readonly currentRateService: CurrentRateService, private readonly exchangeRateDataService: ExchangeRateDataService, + private readonly portfolioSnapshotService: PortfolioSnapshotService, private readonly redisCacheService: RedisCacheService ) {} @@ -51,6 +53,7 @@ export class PortfolioCalculatorFactory { configurationService: this.configurationService, currentRateService: this.currentRateService, exchangeRateDataService: this.exchangeRateDataService, + portfolioSnapshotService: this.portfolioSnapshotService, redisCacheService: this.redisCacheService }); case PerformanceCalculationType.TWR: @@ -63,6 +66,7 @@ export class PortfolioCalculatorFactory { userId, configurationService: this.configurationService, exchangeRateDataService: this.exchangeRateDataService, + portfolioSnapshotService: this.portfolioSnapshotService, redisCacheService: this.redisCacheService }); default: diff --git a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts index 2938bd734..d2f68e628 100644 --- a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts @@ -10,8 +10,14 @@ import { LogPerformance } from '@ghostfolio/api/interceptors/performance-logging import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { IDataGatheringItem } from '@ghostfolio/api/services/interfaces/interfaces'; +import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service'; import { getIntervalFromDateRange } from '@ghostfolio/common/calculation-helper'; -import { CACHE_TTL_INFINITE } from '@ghostfolio/common/config'; +import { + PORTFOLIO_SNAPSHOT_PROCESS_JOB_NAME, + PORTFOLIO_SNAPSHOT_PROCESS_JOB_OPTIONS, + PORTFOLIO_SNAPSHOT_QUEUE_PRIORITY_HIGH, + PORTFOLIO_SNAPSHOT_QUEUE_PRIORITY_LOW +} from '@ghostfolio/common/config'; import { DATE_FORMAT, getSum, @@ -34,7 +40,6 @@ import { Logger } from '@nestjs/common'; import { Big } from 'big.js'; import { plainToClass } from 'class-transformer'; import { - addMilliseconds, differenceInDays, eachDayOfInterval, endOfDay, @@ -59,6 +64,7 @@ export abstract class PortfolioCalculator { private endDate: Date; private exchangeRateDataService: ExchangeRateDataService; private filters: Filter[]; + private portfolioSnapshotService: PortfolioSnapshotService; private redisCacheService: RedisCacheService; private snapshot: PortfolioSnapshot; private snapshotPromise: Promise; @@ -74,6 +80,7 @@ export abstract class PortfolioCalculator { currentRateService, exchangeRateDataService, filters, + portfolioSnapshotService, redisCacheService, userId }: { @@ -84,6 +91,7 @@ export abstract class PortfolioCalculator { currentRateService: CurrentRateService; exchangeRateDataService: ExchangeRateDataService; filters: Filter[]; + portfolioSnapshotService: PortfolioSnapshotService; redisCacheService: RedisCacheService; userId: string; }) { @@ -132,6 +140,7 @@ export abstract class PortfolioCalculator { return a.date?.localeCompare(b.date); }); + this.portfolioSnapshotService = portfolioSnapshotService; this.redisCacheService = redisCacheService; this.userId = userId; @@ -153,7 +162,7 @@ export abstract class PortfolioCalculator { ): PortfolioSnapshot; @LogPerformance - private async computeSnapshot(): Promise { + public async computeSnapshot(): Promise { const lastTransactionPoint = last(this.transactionPoints); const transactionPoints = this.transactionPoints?.filter(({ date }) => { @@ -866,29 +875,6 @@ export abstract class PortfolioCalculator { return chartDateMap; } - private async computeAndCacheSnapshot() { - const snapshot = await this.computeSnapshot(); - - const expiration = addMilliseconds( - new Date(), - this.configurationService.get('CACHE_QUOTES_TTL') - ); - - this.redisCacheService.set( - this.redisCacheService.getPortfolioSnapshotKey({ - filters: this.filters, - userId: this.userId - }), - JSON.stringify(({ - expiration: expiration.getTime(), - portfolioSnapshot: snapshot - })), - CACHE_TTL_INFINITE - ); - - return snapshot; - } - @LogPerformance private computeTransactionPoints() { this.transactionPoints = []; @@ -1034,6 +1020,7 @@ export abstract class PortfolioCalculator { let cachedPortfolioSnapshot: PortfolioSnapshot; let isCachedPortfolioSnapshotExpired = false; + const jobId = this.userId; try { const cachedPortfolioSnapshotValue = await this.redisCacheService.get( @@ -1069,11 +1056,43 @@ export abstract class PortfolioCalculator { if (isCachedPortfolioSnapshotExpired) { // Compute in the background - this.computeAndCacheSnapshot(); + this.portfolioSnapshotService.addJobToQueue({ + data: { + filters: this.filters, + userCurrency: this.currency, + userId: this.userId + }, + name: PORTFOLIO_SNAPSHOT_PROCESS_JOB_NAME, + opts: { + ...PORTFOLIO_SNAPSHOT_PROCESS_JOB_OPTIONS, + jobId, + priority: PORTFOLIO_SNAPSHOT_QUEUE_PRIORITY_LOW + } + }); } } else { // Wait for computation - this.snapshot = await this.computeAndCacheSnapshot(); + await this.portfolioSnapshotService.addJobToQueue({ + data: { + filters: this.filters, + userCurrency: this.currency, + userId: this.userId + }, + name: PORTFOLIO_SNAPSHOT_PROCESS_JOB_NAME, + opts: { + ...PORTFOLIO_SNAPSHOT_PROCESS_JOB_OPTIONS, + jobId, + priority: PORTFOLIO_SNAPSHOT_QUEUE_PRIORITY_HIGH + } + }); + + const job = await this.portfolioSnapshotService.getJob(jobId); + + if (job) { + await job.finished(); + } + + await this.initialize(); } } } diff --git a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts index 1ac86faf0..37499f0e3 100644 --- a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts +++ b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts @@ -14,6 +14,8 @@ import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.s import { RedisCacheServiceMock } from '@ghostfolio/api/app/redis-cache/redis-cache.service.mock'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; +import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service'; +import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock'; import { parseDate } from '@ghostfolio/common/helper'; import { Big } from 'big.js'; @@ -28,6 +30,18 @@ jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => { }; }); +jest.mock( + '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service', + () => { + return { + // eslint-disable-next-line @typescript-eslint/naming-convention + PortfolioSnapshotService: jest.fn().mockImplementation(() => { + return PortfolioSnapshotServiceMock; + }) + }; + } +); + jest.mock('@ghostfolio/api/app/redis-cache/redis-cache.service', () => { return { // eslint-disable-next-line @typescript-eslint/naming-convention @@ -41,7 +55,8 @@ describe('PortfolioCalculator', () => { let configurationService: ConfigurationService; let currentRateService: CurrentRateService; let exchangeRateDataService: ExchangeRateDataService; - let factory: PortfolioCalculatorFactory; + let portfolioCalculatorFactory: PortfolioCalculatorFactory; + let portfolioSnapshotService: PortfolioSnapshotService; let redisCacheService: RedisCacheService; beforeEach(() => { @@ -56,12 +71,15 @@ describe('PortfolioCalculator', () => { null ); + portfolioSnapshotService = new PortfolioSnapshotService(null); + redisCacheService = new RedisCacheService(null, null); - factory = new PortfolioCalculatorFactory( + portfolioCalculatorFactory = new PortfolioCalculatorFactory( configurationService, currentRateService, exchangeRateDataService, + portfolioSnapshotService, redisCacheService ); }); @@ -118,14 +136,14 @@ describe('PortfolioCalculator', () => { } ]; - const portfolioCalculator = factory.createCalculator({ + const portfolioCalculator = portfolioCalculatorFactory.createCalculator({ activities, calculationType: PerformanceCalculationType.TWR, currency: 'CHF', userId: userDummyData.id }); - const portfolioSnapshot = await portfolioCalculator.getSnapshot(); + const portfolioSnapshot = await portfolioCalculator.computeSnapshot(); const investments = portfolioCalculator.getInvestments(); diff --git a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-baln-buy-and-sell.spec.ts b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-baln-buy-and-sell.spec.ts index 54cea8dae..23c594e5b 100644 --- a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-baln-buy-and-sell.spec.ts +++ b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-baln-buy-and-sell.spec.ts @@ -14,6 +14,8 @@ import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.s import { RedisCacheServiceMock } from '@ghostfolio/api/app/redis-cache/redis-cache.service.mock'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; +import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service'; +import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock'; import { parseDate } from '@ghostfolio/common/helper'; import { Big } from 'big.js'; @@ -28,6 +30,18 @@ jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => { }; }); +jest.mock( + '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service', + () => { + return { + // eslint-disable-next-line @typescript-eslint/naming-convention + PortfolioSnapshotService: jest.fn().mockImplementation(() => { + return PortfolioSnapshotServiceMock; + }) + }; + } +); + jest.mock('@ghostfolio/api/app/redis-cache/redis-cache.service', () => { return { // eslint-disable-next-line @typescript-eslint/naming-convention @@ -41,7 +55,8 @@ describe('PortfolioCalculator', () => { let configurationService: ConfigurationService; let currentRateService: CurrentRateService; let exchangeRateDataService: ExchangeRateDataService; - let factory: PortfolioCalculatorFactory; + let portfolioCalculatorFactory: PortfolioCalculatorFactory; + let portfolioSnapshotService: PortfolioSnapshotService; let redisCacheService: RedisCacheService; beforeEach(() => { @@ -56,12 +71,15 @@ describe('PortfolioCalculator', () => { null ); + portfolioSnapshotService = new PortfolioSnapshotService(null); + redisCacheService = new RedisCacheService(null, null); - factory = new PortfolioCalculatorFactory( + portfolioCalculatorFactory = new PortfolioCalculatorFactory( configurationService, currentRateService, exchangeRateDataService, + portfolioSnapshotService, redisCacheService ); }); @@ -103,14 +121,14 @@ describe('PortfolioCalculator', () => { } ]; - const portfolioCalculator = factory.createCalculator({ + const portfolioCalculator = portfolioCalculatorFactory.createCalculator({ activities, calculationType: PerformanceCalculationType.TWR, currency: 'CHF', userId: userDummyData.id }); - const portfolioSnapshot = await portfolioCalculator.getSnapshot(); + const portfolioSnapshot = await portfolioCalculator.computeSnapshot(); const investments = portfolioCalculator.getInvestments(); diff --git a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-baln-buy.spec.ts b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-baln-buy.spec.ts index e638073eb..90f6a59d1 100644 --- a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-baln-buy.spec.ts +++ b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-baln-buy.spec.ts @@ -14,6 +14,8 @@ import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.s import { RedisCacheServiceMock } from '@ghostfolio/api/app/redis-cache/redis-cache.service.mock'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; +import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service'; +import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock'; import { parseDate } from '@ghostfolio/common/helper'; import { Big } from 'big.js'; @@ -28,6 +30,18 @@ jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => { }; }); +jest.mock( + '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service', + () => { + return { + // eslint-disable-next-line @typescript-eslint/naming-convention + PortfolioSnapshotService: jest.fn().mockImplementation(() => { + return PortfolioSnapshotServiceMock; + }) + }; + } +); + jest.mock('@ghostfolio/api/app/redis-cache/redis-cache.service', () => { return { // eslint-disable-next-line @typescript-eslint/naming-convention @@ -41,7 +55,8 @@ describe('PortfolioCalculator', () => { let configurationService: ConfigurationService; let currentRateService: CurrentRateService; let exchangeRateDataService: ExchangeRateDataService; - let factory: PortfolioCalculatorFactory; + let portfolioCalculatorFactory: PortfolioCalculatorFactory; + let portfolioSnapshotService: PortfolioSnapshotService; let redisCacheService: RedisCacheService; beforeEach(() => { @@ -56,12 +71,15 @@ describe('PortfolioCalculator', () => { null ); + portfolioSnapshotService = new PortfolioSnapshotService(null); + redisCacheService = new RedisCacheService(null, null); - factory = new PortfolioCalculatorFactory( + portfolioCalculatorFactory = new PortfolioCalculatorFactory( configurationService, currentRateService, exchangeRateDataService, + portfolioSnapshotService, redisCacheService ); }); @@ -88,14 +106,14 @@ describe('PortfolioCalculator', () => { } ]; - const portfolioCalculator = factory.createCalculator({ + const portfolioCalculator = portfolioCalculatorFactory.createCalculator({ activities, calculationType: PerformanceCalculationType.TWR, currency: 'CHF', userId: userDummyData.id }); - const portfolioSnapshot = await portfolioCalculator.getSnapshot(); + const portfolioSnapshot = await portfolioCalculator.computeSnapshot(); const investments = portfolioCalculator.getInvestments(); diff --git a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts index cc64a540b..e232b42c4 100644 --- a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts +++ b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts @@ -15,6 +15,8 @@ import { RedisCacheServiceMock } from '@ghostfolio/api/app/redis-cache/redis-cac import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { ExchangeRateDataServiceMock } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service.mock'; +import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service'; +import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock'; import { parseDate } from '@ghostfolio/common/helper'; import { Big } from 'big.js'; @@ -29,6 +31,18 @@ jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => { }; }); +jest.mock( + '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service', + () => { + return { + // eslint-disable-next-line @typescript-eslint/naming-convention + PortfolioSnapshotService: jest.fn().mockImplementation(() => { + return PortfolioSnapshotServiceMock; + }) + }; + } +); + jest.mock('@ghostfolio/api/app/redis-cache/redis-cache.service', () => { return { // eslint-disable-next-line @typescript-eslint/naming-convention @@ -54,7 +68,8 @@ describe('PortfolioCalculator', () => { let configurationService: ConfigurationService; let currentRateService: CurrentRateService; let exchangeRateDataService: ExchangeRateDataService; - let factory: PortfolioCalculatorFactory; + let portfolioCalculatorFactory: PortfolioCalculatorFactory; + let portfolioSnapshotService: PortfolioSnapshotService; let redisCacheService: RedisCacheService; beforeEach(() => { @@ -69,12 +84,15 @@ describe('PortfolioCalculator', () => { null ); + portfolioSnapshotService = new PortfolioSnapshotService(null); + redisCacheService = new RedisCacheService(null, null); - factory = new PortfolioCalculatorFactory( + portfolioCalculatorFactory = new PortfolioCalculatorFactory( configurationService, currentRateService, exchangeRateDataService, + portfolioSnapshotService, redisCacheService ); }); @@ -117,14 +135,14 @@ describe('PortfolioCalculator', () => { } ]; - const portfolioCalculator = factory.createCalculator({ + const portfolioCalculator = portfolioCalculatorFactory.createCalculator({ activities, calculationType: PerformanceCalculationType.TWR, currency: 'CHF', userId: userDummyData.id }); - const portfolioSnapshot = await portfolioCalculator.getSnapshot(); + const portfolioSnapshot = await portfolioCalculator.computeSnapshot(); const investments = portfolioCalculator.getInvestments(); diff --git a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-fee.spec.ts b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-fee.spec.ts index 4f4c05b13..fe379a92a 100644 --- a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-fee.spec.ts +++ b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-fee.spec.ts @@ -14,6 +14,8 @@ import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.s import { RedisCacheServiceMock } from '@ghostfolio/api/app/redis-cache/redis-cache.service.mock'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; +import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service'; +import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock'; import { parseDate } from '@ghostfolio/common/helper'; import { Big } from 'big.js'; @@ -28,6 +30,18 @@ jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => { }; }); +jest.mock( + '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service', + () => { + return { + // eslint-disable-next-line @typescript-eslint/naming-convention + PortfolioSnapshotService: jest.fn().mockImplementation(() => { + return PortfolioSnapshotServiceMock; + }) + }; + } +); + jest.mock('@ghostfolio/api/app/redis-cache/redis-cache.service', () => { return { // eslint-disable-next-line @typescript-eslint/naming-convention @@ -41,7 +55,8 @@ describe('PortfolioCalculator', () => { let configurationService: ConfigurationService; let currentRateService: CurrentRateService; let exchangeRateDataService: ExchangeRateDataService; - let factory: PortfolioCalculatorFactory; + let portfolioCalculatorFactory: PortfolioCalculatorFactory; + let portfolioSnapshotService: PortfolioSnapshotService; let redisCacheService: RedisCacheService; beforeEach(() => { @@ -56,12 +71,15 @@ describe('PortfolioCalculator', () => { null ); + portfolioSnapshotService = new PortfolioSnapshotService(null); + redisCacheService = new RedisCacheService(null, null); - factory = new PortfolioCalculatorFactory( + portfolioCalculatorFactory = new PortfolioCalculatorFactory( configurationService, currentRateService, exchangeRateDataService, + portfolioSnapshotService, redisCacheService ); }); @@ -88,14 +106,14 @@ describe('PortfolioCalculator', () => { } ]; - const portfolioCalculator = factory.createCalculator({ + const portfolioCalculator = portfolioCalculatorFactory.createCalculator({ activities, calculationType: PerformanceCalculationType.TWR, currency: 'USD', userId: userDummyData.id }); - const portfolioSnapshot = await portfolioCalculator.getSnapshot(); + const portfolioSnapshot = await portfolioCalculator.computeSnapshot(); expect(portfolioSnapshot).toMatchObject({ currentValueInBaseCurrency: new Big('0'), diff --git a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-googl-buy.spec.ts b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-googl-buy.spec.ts index c7cf7e2b3..60fe6dc6b 100644 --- a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-googl-buy.spec.ts +++ b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-googl-buy.spec.ts @@ -15,6 +15,8 @@ import { RedisCacheServiceMock } from '@ghostfolio/api/app/redis-cache/redis-cac import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { ExchangeRateDataServiceMock } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service.mock'; +import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service'; +import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock'; import { parseDate } from '@ghostfolio/common/helper'; import { Big } from 'big.js'; @@ -29,6 +31,18 @@ jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => { }; }); +jest.mock( + '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service', + () => { + return { + // eslint-disable-next-line @typescript-eslint/naming-convention + PortfolioSnapshotService: jest.fn().mockImplementation(() => { + return PortfolioSnapshotServiceMock; + }) + }; + } +); + jest.mock('@ghostfolio/api/app/redis-cache/redis-cache.service', () => { return { // eslint-disable-next-line @typescript-eslint/naming-convention @@ -54,7 +68,8 @@ describe('PortfolioCalculator', () => { let configurationService: ConfigurationService; let currentRateService: CurrentRateService; let exchangeRateDataService: ExchangeRateDataService; - let factory: PortfolioCalculatorFactory; + let portfolioCalculatorFactory: PortfolioCalculatorFactory; + let portfolioSnapshotService: PortfolioSnapshotService; let redisCacheService: RedisCacheService; beforeEach(() => { @@ -69,12 +84,15 @@ describe('PortfolioCalculator', () => { null ); + portfolioSnapshotService = new PortfolioSnapshotService(null); + redisCacheService = new RedisCacheService(null, null); - factory = new PortfolioCalculatorFactory( + portfolioCalculatorFactory = new PortfolioCalculatorFactory( configurationService, currentRateService, exchangeRateDataService, + portfolioSnapshotService, redisCacheService ); }); @@ -101,14 +119,14 @@ describe('PortfolioCalculator', () => { } ]; - const portfolioCalculator = factory.createCalculator({ + const portfolioCalculator = portfolioCalculatorFactory.createCalculator({ activities, calculationType: PerformanceCalculationType.TWR, currency: 'CHF', userId: userDummyData.id }); - const portfolioSnapshot = await portfolioCalculator.getSnapshot(); + const portfolioSnapshot = await portfolioCalculator.computeSnapshot(); const investments = portfolioCalculator.getInvestments(); diff --git a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-item.spec.ts b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-item.spec.ts index a0e62af57..228568374 100644 --- a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-item.spec.ts +++ b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-item.spec.ts @@ -14,6 +14,8 @@ import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.s import { RedisCacheServiceMock } from '@ghostfolio/api/app/redis-cache/redis-cache.service.mock'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; +import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service'; +import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock'; import { parseDate } from '@ghostfolio/common/helper'; import { Big } from 'big.js'; @@ -28,6 +30,18 @@ jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => { }; }); +jest.mock( + '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service', + () => { + return { + // eslint-disable-next-line @typescript-eslint/naming-convention + PortfolioSnapshotService: jest.fn().mockImplementation(() => { + return PortfolioSnapshotServiceMock; + }) + }; + } +); + jest.mock('@ghostfolio/api/app/redis-cache/redis-cache.service', () => { return { // eslint-disable-next-line @typescript-eslint/naming-convention @@ -41,7 +55,8 @@ describe('PortfolioCalculator', () => { let configurationService: ConfigurationService; let currentRateService: CurrentRateService; let exchangeRateDataService: ExchangeRateDataService; - let factory: PortfolioCalculatorFactory; + let portfolioCalculatorFactory: PortfolioCalculatorFactory; + let portfolioSnapshotService: PortfolioSnapshotService; let redisCacheService: RedisCacheService; beforeEach(() => { @@ -56,12 +71,15 @@ describe('PortfolioCalculator', () => { null ); + portfolioSnapshotService = new PortfolioSnapshotService(null); + redisCacheService = new RedisCacheService(null, null); - factory = new PortfolioCalculatorFactory( + portfolioCalculatorFactory = new PortfolioCalculatorFactory( configurationService, currentRateService, exchangeRateDataService, + portfolioSnapshotService, redisCacheService ); }); @@ -88,14 +106,14 @@ describe('PortfolioCalculator', () => { } ]; - const portfolioCalculator = factory.createCalculator({ + const portfolioCalculator = portfolioCalculatorFactory.createCalculator({ activities, calculationType: PerformanceCalculationType.TWR, currency: 'USD', userId: userDummyData.id }); - const portfolioSnapshot = await portfolioCalculator.getSnapshot(); + const portfolioSnapshot = await portfolioCalculator.computeSnapshot(); expect(portfolioSnapshot).toMatchObject({ currentValueInBaseCurrency: new Big('0'), diff --git a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-liability.spec.ts b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-liability.spec.ts index 0df8dee48..5fa90e94c 100644 --- a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-liability.spec.ts +++ b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-liability.spec.ts @@ -14,6 +14,8 @@ import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.s import { RedisCacheServiceMock } from '@ghostfolio/api/app/redis-cache/redis-cache.service.mock'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; +import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service'; +import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock'; import { parseDate } from '@ghostfolio/common/helper'; import { Big } from 'big.js'; @@ -27,6 +29,18 @@ jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => { }; }); +jest.mock( + '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service', + () => { + return { + // eslint-disable-next-line @typescript-eslint/naming-convention + PortfolioSnapshotService: jest.fn().mockImplementation(() => { + return PortfolioSnapshotServiceMock; + }) + }; + } +); + jest.mock('@ghostfolio/api/app/redis-cache/redis-cache.service', () => { return { // eslint-disable-next-line @typescript-eslint/naming-convention @@ -40,7 +54,8 @@ describe('PortfolioCalculator', () => { let configurationService: ConfigurationService; let currentRateService: CurrentRateService; let exchangeRateDataService: ExchangeRateDataService; - let factory: PortfolioCalculatorFactory; + let portfolioCalculatorFactory: PortfolioCalculatorFactory; + let portfolioSnapshotService: PortfolioSnapshotService; let redisCacheService: RedisCacheService; beforeEach(() => { @@ -55,12 +70,15 @@ describe('PortfolioCalculator', () => { null ); + portfolioSnapshotService = new PortfolioSnapshotService(null); + redisCacheService = new RedisCacheService(null, null); - factory = new PortfolioCalculatorFactory( + portfolioCalculatorFactory = new PortfolioCalculatorFactory( configurationService, currentRateService, exchangeRateDataService, + portfolioSnapshotService, redisCacheService ); }); @@ -87,17 +105,18 @@ describe('PortfolioCalculator', () => { } ]; - const portfolioCalculator = factory.createCalculator({ + const portfolioCalculator = portfolioCalculatorFactory.createCalculator({ activities, calculationType: PerformanceCalculationType.TWR, currency: 'USD', userId: userDummyData.id }); - const liabilitiesInBaseCurrency = - await portfolioCalculator.getLiabilitiesInBaseCurrency(); + const portfolioSnapshot = await portfolioCalculator.computeSnapshot(); - expect(liabilitiesInBaseCurrency).toEqual(new Big(3000)); + expect(portfolioSnapshot.totalLiabilitiesWithCurrencyEffect).toEqual( + new Big(3000) + ); }); }); }); diff --git a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-msft-buy-with-dividend.spec.ts b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-msft-buy-with-dividend.spec.ts index 8a1c5a517..97b860400 100644 --- a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-msft-buy-with-dividend.spec.ts +++ b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-msft-buy-with-dividend.spec.ts @@ -15,6 +15,8 @@ import { RedisCacheServiceMock } from '@ghostfolio/api/app/redis-cache/redis-cac import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { ExchangeRateDataServiceMock } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service.mock'; +import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service'; +import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock'; import { parseDate } from '@ghostfolio/common/helper'; import { Big } from 'big.js'; @@ -29,6 +31,18 @@ jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => { }; }); +jest.mock( + '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service', + () => { + return { + // eslint-disable-next-line @typescript-eslint/naming-convention + PortfolioSnapshotService: jest.fn().mockImplementation(() => { + return PortfolioSnapshotServiceMock; + }) + }; + } +); + jest.mock('@ghostfolio/api/app/redis-cache/redis-cache.service', () => { return { // eslint-disable-next-line @typescript-eslint/naming-convention @@ -54,7 +68,8 @@ describe('PortfolioCalculator', () => { let configurationService: ConfigurationService; let currentRateService: CurrentRateService; let exchangeRateDataService: ExchangeRateDataService; - let factory: PortfolioCalculatorFactory; + let portfolioCalculatorFactory: PortfolioCalculatorFactory; + let portfolioSnapshotService: PortfolioSnapshotService; let redisCacheService: RedisCacheService; beforeEach(() => { @@ -69,12 +84,15 @@ describe('PortfolioCalculator', () => { null ); + portfolioSnapshotService = new PortfolioSnapshotService(null); + redisCacheService = new RedisCacheService(null, null); - factory = new PortfolioCalculatorFactory( + portfolioCalculatorFactory = new PortfolioCalculatorFactory( configurationService, currentRateService, exchangeRateDataService, + portfolioSnapshotService, redisCacheService ); }); @@ -116,14 +134,14 @@ describe('PortfolioCalculator', () => { } ]; - const portfolioCalculator = factory.createCalculator({ + const portfolioCalculator = portfolioCalculatorFactory.createCalculator({ activities, calculationType: PerformanceCalculationType.TWR, currency: 'USD', userId: userDummyData.id }); - const portfolioSnapshot = await portfolioCalculator.getSnapshot(); + const portfolioSnapshot = await portfolioCalculator.computeSnapshot(); expect(portfolioSnapshot).toMatchObject({ errors: [], diff --git a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-no-orders.spec.ts b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-no-orders.spec.ts index a25e31dd3..84898490f 100644 --- a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-no-orders.spec.ts +++ b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-no-orders.spec.ts @@ -9,11 +9,11 @@ import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.s import { RedisCacheServiceMock } from '@ghostfolio/api/app/redis-cache/redis-cache.service.mock'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; +import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service'; +import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock'; import { parseDate } from '@ghostfolio/common/helper'; import { Big } from 'big.js'; -import { subDays } from 'date-fns'; -import { last } from 'lodash'; jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => { return { @@ -24,6 +24,18 @@ jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => { }; }); +jest.mock( + '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service', + () => { + return { + // eslint-disable-next-line @typescript-eslint/naming-convention + PortfolioSnapshotService: jest.fn().mockImplementation(() => { + return PortfolioSnapshotServiceMock; + }) + }; + } +); + jest.mock('@ghostfolio/api/app/redis-cache/redis-cache.service', () => { return { // eslint-disable-next-line @typescript-eslint/naming-convention @@ -37,7 +49,8 @@ describe('PortfolioCalculator', () => { let configurationService: ConfigurationService; let currentRateService: CurrentRateService; let exchangeRateDataService: ExchangeRateDataService; - let factory: PortfolioCalculatorFactory; + let portfolioCalculatorFactory: PortfolioCalculatorFactory; + let portfolioSnapshotService: PortfolioSnapshotService; let redisCacheService: RedisCacheService; beforeEach(() => { @@ -52,12 +65,15 @@ describe('PortfolioCalculator', () => { null ); + portfolioSnapshotService = new PortfolioSnapshotService(null); + redisCacheService = new RedisCacheService(null, null); - factory = new PortfolioCalculatorFactory( + portfolioCalculatorFactory = new PortfolioCalculatorFactory( configurationService, currentRateService, exchangeRateDataService, + portfolioSnapshotService, redisCacheService ); }); @@ -66,14 +82,14 @@ describe('PortfolioCalculator', () => { it('with no orders', async () => { jest.useFakeTimers().setSystemTime(parseDate('2021-12-18').getTime()); - const portfolioCalculator = factory.createCalculator({ + const portfolioCalculator = portfolioCalculatorFactory.createCalculator({ activities: [], calculationType: PerformanceCalculationType.TWR, currency: 'CHF', userId: userDummyData.id }); - const portfolioSnapshot = await portfolioCalculator.getSnapshot(); + const portfolioSnapshot = await portfolioCalculator.computeSnapshot(); const investments = portfolioCalculator.getInvestments(); diff --git a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell-partially.spec.ts b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell-partially.spec.ts index 967f8cd1f..30eb79754 100644 --- a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell-partially.spec.ts +++ b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell-partially.spec.ts @@ -14,6 +14,8 @@ import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.s import { RedisCacheServiceMock } from '@ghostfolio/api/app/redis-cache/redis-cache.service.mock'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; +import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service'; +import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock'; import { parseDate } from '@ghostfolio/common/helper'; import { Big } from 'big.js'; @@ -28,6 +30,18 @@ jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => { }; }); +jest.mock( + '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service', + () => { + return { + // eslint-disable-next-line @typescript-eslint/naming-convention + PortfolioSnapshotService: jest.fn().mockImplementation(() => { + return PortfolioSnapshotServiceMock; + }) + }; + } +); + jest.mock('@ghostfolio/api/app/redis-cache/redis-cache.service', () => { return { // eslint-disable-next-line @typescript-eslint/naming-convention @@ -41,7 +55,8 @@ describe('PortfolioCalculator', () => { let configurationService: ConfigurationService; let currentRateService: CurrentRateService; let exchangeRateDataService: ExchangeRateDataService; - let factory: PortfolioCalculatorFactory; + let portfolioCalculatorFactory: PortfolioCalculatorFactory; + let portfolioSnapshotService: PortfolioSnapshotService; let redisCacheService: RedisCacheService; beforeEach(() => { @@ -56,12 +71,15 @@ describe('PortfolioCalculator', () => { null ); + portfolioSnapshotService = new PortfolioSnapshotService(null); + redisCacheService = new RedisCacheService(null, null); - factory = new PortfolioCalculatorFactory( + portfolioCalculatorFactory = new PortfolioCalculatorFactory( configurationService, currentRateService, exchangeRateDataService, + portfolioSnapshotService, redisCacheService ); }); @@ -103,14 +121,14 @@ describe('PortfolioCalculator', () => { } ]; - const portfolioCalculator = factory.createCalculator({ + const portfolioCalculator = portfolioCalculatorFactory.createCalculator({ activities, calculationType: PerformanceCalculationType.TWR, currency: 'CHF', userId: userDummyData.id }); - const portfolioSnapshot = await portfolioCalculator.getSnapshot(); + const portfolioSnapshot = await portfolioCalculator.computeSnapshot(); const investments = portfolioCalculator.getInvestments(); diff --git a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell.spec.ts b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell.spec.ts index 068246eb6..db5aaf6bc 100644 --- a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell.spec.ts +++ b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell.spec.ts @@ -14,6 +14,8 @@ import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.s import { RedisCacheServiceMock } from '@ghostfolio/api/app/redis-cache/redis-cache.service.mock'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; +import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service'; +import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock'; import { parseDate } from '@ghostfolio/common/helper'; import { Big } from 'big.js'; @@ -28,6 +30,18 @@ jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => { }; }); +jest.mock( + '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service', + () => { + return { + // eslint-disable-next-line @typescript-eslint/naming-convention + PortfolioSnapshotService: jest.fn().mockImplementation(() => { + return PortfolioSnapshotServiceMock; + }) + }; + } +); + jest.mock('@ghostfolio/api/app/redis-cache/redis-cache.service', () => { return { // eslint-disable-next-line @typescript-eslint/naming-convention @@ -41,7 +55,8 @@ describe('PortfolioCalculator', () => { let configurationService: ConfigurationService; let currentRateService: CurrentRateService; let exchangeRateDataService: ExchangeRateDataService; - let factory: PortfolioCalculatorFactory; + let portfolioCalculatorFactory: PortfolioCalculatorFactory; + let portfolioSnapshotService: PortfolioSnapshotService; let redisCacheService: RedisCacheService; beforeEach(() => { @@ -56,12 +71,15 @@ describe('PortfolioCalculator', () => { null ); + portfolioSnapshotService = new PortfolioSnapshotService(null); + redisCacheService = new RedisCacheService(null, null); - factory = new PortfolioCalculatorFactory( + portfolioCalculatorFactory = new PortfolioCalculatorFactory( configurationService, currentRateService, exchangeRateDataService, + portfolioSnapshotService, redisCacheService ); }); @@ -103,14 +121,14 @@ describe('PortfolioCalculator', () => { } ]; - const portfolioCalculator = factory.createCalculator({ + const portfolioCalculator = portfolioCalculatorFactory.createCalculator({ activities, calculationType: PerformanceCalculationType.TWR, currency: 'CHF', userId: userDummyData.id }); - const portfolioSnapshot = await portfolioCalculator.getSnapshot(); + const portfolioSnapshot = await portfolioCalculator.computeSnapshot(); const investments = portfolioCalculator.getInvestments(); diff --git a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator.spec.ts b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator.spec.ts index 536581070..d8431cd83 100644 --- a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator.spec.ts +++ b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator.spec.ts @@ -3,12 +3,14 @@ import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.s import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; +import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service'; describe('PortfolioCalculator', () => { let configurationService: ConfigurationService; let currentRateService: CurrentRateService; let exchangeRateDataService: ExchangeRateDataService; - let factory: PortfolioCalculatorFactory; + let portfolioCalculatorFactory: PortfolioCalculatorFactory; + let portfolioSnapshotService: PortfolioSnapshotService; let redisCacheService: RedisCacheService; beforeEach(() => { @@ -23,12 +25,15 @@ describe('PortfolioCalculator', () => { null ); + portfolioSnapshotService = new PortfolioSnapshotService(null); + redisCacheService = new RedisCacheService(null, null); - factory = new PortfolioCalculatorFactory( + portfolioCalculatorFactory = new PortfolioCalculatorFactory( configurationService, currentRateService, exchangeRateDataService, + portfolioSnapshotService, redisCacheService ); }); diff --git a/apps/api/src/app/portfolio/portfolio.module.ts b/apps/api/src/app/portfolio/portfolio.module.ts index ad81e9e15..7ae74ee5f 100644 --- a/apps/api/src/app/portfolio/portfolio.module.ts +++ b/apps/api/src/app/portfolio/portfolio.module.ts @@ -10,12 +10,13 @@ import { TransformDataSourceInRequestModule } from '@ghostfolio/api/interceptors import { TransformDataSourceInResponseModule } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.module'; import { ApiModule } from '@ghostfolio/api/services/api/api.module'; import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module'; -import { DataGatheringModule } from '@ghostfolio/api/services/data-gathering/data-gathering.module'; import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module'; import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module'; import { ImpersonationModule } from '@ghostfolio/api/services/impersonation/impersonation.module'; import { MarketDataModule } from '@ghostfolio/api/services/market-data/market-data.module'; import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module'; +import { DataGatheringModule } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.module'; +import { PortfolioSnapshotQueueModule } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.module'; import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/symbol-profile.module'; import { Module } from '@nestjs/common'; @@ -40,6 +41,7 @@ import { RulesService } from './rules.service'; MarketDataModule, OrderModule, PerformanceLoggingModule, + PortfolioSnapshotQueueModule, PrismaModule, RedactValuesInResponseModule, RedisCacheModule, diff --git a/apps/api/src/app/redis-cache/redis-cache.service.mock.ts b/apps/api/src/app/redis-cache/redis-cache.service.mock.ts index 094c7e6a0..2779308bd 100644 --- a/apps/api/src/app/redis-cache/redis-cache.service.mock.ts +++ b/apps/api/src/app/redis-cache/redis-cache.service.mock.ts @@ -1,13 +1,28 @@ +import { Filter } from '@ghostfolio/common/interfaces'; + import { Milliseconds } from 'cache-manager'; export const RedisCacheServiceMock = { + cache: new Map(), get: (key: string): Promise => { - return Promise.resolve(null); + const value = RedisCacheServiceMock.cache.get(key) || null; + + return Promise.resolve(value); }, - getPortfolioSnapshotKey: (userId: string): string => { - return `portfolio-snapshot-${userId}`; + getPortfolioSnapshotKey: ({ + filters, + userId + }: { + filters?: Filter[]; + userId: string; + }): string => { + const filtersHash = filters?.length; + + return `portfolio-snapshot-${userId}${filtersHash > 0 ? `-${filtersHash}` : ''}`; }, set: (key: string, value: string, ttl?: Milliseconds): Promise => { + RedisCacheServiceMock.cache.set(key, value); + return Promise.resolve(value); } }; diff --git a/apps/api/src/services/cron.service.ts b/apps/api/src/services/cron.service.ts index 864891c6a..17e970c1b 100644 --- a/apps/api/src/services/cron.service.ts +++ b/apps/api/src/services/cron.service.ts @@ -9,9 +9,9 @@ import { getAssetProfileIdentifier } from '@ghostfolio/common/helper'; import { Injectable } from '@nestjs/common'; import { Cron, CronExpression } from '@nestjs/schedule'; -import { DataGatheringService } from './data-gathering/data-gathering.service'; import { ExchangeRateDataService } from './exchange-rate-data/exchange-rate-data.service'; import { PropertyService } from './property/property.service'; +import { DataGatheringService } from './queues/data-gathering/data-gathering.service'; import { TwitterBotService } from './twitter-bot/twitter-bot.service'; @Injectable() diff --git a/apps/api/src/services/data-gathering/data-gathering.module.ts b/apps/api/src/services/queues/data-gathering/data-gathering.module.ts similarity index 93% rename from apps/api/src/services/data-gathering/data-gathering.module.ts rename to apps/api/src/services/queues/data-gathering/data-gathering.module.ts index f3ab2fc9c..b51823476 100644 --- a/apps/api/src/services/data-gathering/data-gathering.module.ts +++ b/apps/api/src/services/queues/data-gathering/data-gathering.module.ts @@ -1,11 +1,11 @@ import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module'; -import { DataGatheringService } from '@ghostfolio/api/services/data-gathering/data-gathering.service'; import { DataEnhancerModule } from '@ghostfolio/api/services/data-provider/data-enhancer/data-enhancer.module'; import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module'; import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module'; import { 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 { DataGatheringService } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.service'; import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/symbol-profile.module'; import { DATA_GATHERING_QUEUE } from '@ghostfolio/common/config'; diff --git a/apps/api/src/services/data-gathering/data-gathering.processor.ts b/apps/api/src/services/queues/data-gathering/data-gathering.processor.ts similarity index 95% rename from apps/api/src/services/data-gathering/data-gathering.processor.ts rename to apps/api/src/services/queues/data-gathering/data-gathering.processor.ts index d8a6a7644..62f52d45b 100644 --- a/apps/api/src/services/data-gathering/data-gathering.processor.ts +++ b/apps/api/src/services/queues/data-gathering/data-gathering.processor.ts @@ -4,7 +4,7 @@ import { MarketDataService } from '@ghostfolio/api/services/market-data/market-d import { DATA_GATHERING_QUEUE, GATHER_ASSET_PROFILE_PROCESS, - GATHER_HISTORICAL_MARKET_DATA_PROCESS + GATHER_HISTORICAL_MARKET_DATA_PROCESS_JOB_NAME } from '@ghostfolio/common/config'; import { DATE_FORMAT, getStartOfUtcDate } from '@ghostfolio/common/helper'; import { AssetProfileIdentifier } from '@ghostfolio/common/interfaces'; @@ -58,7 +58,10 @@ export class DataGatheringProcessor { } } - @Process({ concurrency: 1, name: GATHER_HISTORICAL_MARKET_DATA_PROCESS }) + @Process({ + concurrency: 1, + name: GATHER_HISTORICAL_MARKET_DATA_PROCESS_JOB_NAME + }) public async gatherHistoricalMarketData(job: Job) { try { const { dataSource, date, symbol } = job.data; @@ -69,7 +72,7 @@ export class DataGatheringProcessor { currentDate, DATE_FORMAT )}`, - `DataGatheringProcessor (${GATHER_HISTORICAL_MARKET_DATA_PROCESS})` + `DataGatheringProcessor (${GATHER_HISTORICAL_MARKET_DATA_PROCESS_JOB_NAME})` ); const historicalData = await this.dataProviderService.getHistoricalRaw({ @@ -123,12 +126,12 @@ export class DataGatheringProcessor { currentDate, DATE_FORMAT )}`, - `DataGatheringProcessor (${GATHER_HISTORICAL_MARKET_DATA_PROCESS})` + `DataGatheringProcessor (${GATHER_HISTORICAL_MARKET_DATA_PROCESS_JOB_NAME})` ); } catch (error) { Logger.error( error, - `DataGatheringProcessor (${GATHER_HISTORICAL_MARKET_DATA_PROCESS})` + `DataGatheringProcessor (${GATHER_HISTORICAL_MARKET_DATA_PROCESS_JOB_NAME})` ); throw new Error(error); diff --git a/apps/api/src/services/data-gathering/data-gathering.service.ts b/apps/api/src/services/queues/data-gathering/data-gathering.service.ts similarity index 98% rename from apps/api/src/services/data-gathering/data-gathering.service.ts rename to apps/api/src/services/queues/data-gathering/data-gathering.service.ts index 8b8c65a21..72b8ac716 100644 --- a/apps/api/src/services/data-gathering/data-gathering.service.ts +++ b/apps/api/src/services/queues/data-gathering/data-gathering.service.ts @@ -11,8 +11,8 @@ import { DATA_GATHERING_QUEUE_PRIORITY_HIGH, DATA_GATHERING_QUEUE_PRIORITY_LOW, DATA_GATHERING_QUEUE_PRIORITY_MEDIUM, - GATHER_HISTORICAL_MARKET_DATA_PROCESS, - GATHER_HISTORICAL_MARKET_DATA_PROCESS_OPTIONS, + GATHER_HISTORICAL_MARKET_DATA_PROCESS_JOB_NAME, + GATHER_HISTORICAL_MARKET_DATA_PROCESS_JOB_OPTIONS, PROPERTY_BENCHMARKS } from '@ghostfolio/common/config'; import { @@ -279,9 +279,9 @@ export class DataGatheringService { date, symbol }, - name: GATHER_HISTORICAL_MARKET_DATA_PROCESS, + name: GATHER_HISTORICAL_MARKET_DATA_PROCESS_JOB_NAME, opts: { - ...GATHER_HISTORICAL_MARKET_DATA_PROCESS_OPTIONS, + ...GATHER_HISTORICAL_MARKET_DATA_PROCESS_JOB_OPTIONS, priority, jobId: `${getAssetProfileIdentifier({ dataSource, diff --git a/apps/api/src/services/queues/portfolio-snapshot/interfaces/portfolio-snapshot-queue-job.interface.ts b/apps/api/src/services/queues/portfolio-snapshot/interfaces/portfolio-snapshot-queue-job.interface.ts new file mode 100644 index 000000000..24948e211 --- /dev/null +++ b/apps/api/src/services/queues/portfolio-snapshot/interfaces/portfolio-snapshot-queue-job.interface.ts @@ -0,0 +1,7 @@ +import { Filter } from '@ghostfolio/common/interfaces'; + +export interface IPortfolioSnapshotQueueJob { + filters: Filter[]; + userCurrency: string; + userId: string; +} diff --git a/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.module.ts b/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.module.ts new file mode 100644 index 000000000..331e5849f --- /dev/null +++ b/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.module.ts @@ -0,0 +1,37 @@ +import { OrderModule } from '@ghostfolio/api/app/order/order.module'; +import { PortfolioCalculatorFactory } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory'; +import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service'; +import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.module'; +import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module'; +import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module'; +import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module'; +import { MarketDataModule } from '@ghostfolio/api/services/market-data/market-data.module'; +import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service'; +import { PORTFOLIO_SNAPSHOT_QUEUE } from '@ghostfolio/common/config'; + +import { BullModule } from '@nestjs/bull'; +import { Module } from '@nestjs/common'; + +import { PortfolioSnapshotProcessor } from './portfolio-snapshot.processor'; + +@Module({ + exports: [BullModule, PortfolioSnapshotService], + imports: [ + BullModule.registerQueue({ + name: PORTFOLIO_SNAPSHOT_QUEUE + }), + ConfigurationModule, + DataProviderModule, + ExchangeRateDataModule, + MarketDataModule, + OrderModule, + RedisCacheModule + ], + providers: [ + CurrentRateService, + PortfolioCalculatorFactory, + PortfolioSnapshotProcessor, + PortfolioSnapshotService + ] +}) +export class PortfolioSnapshotQueueModule {} diff --git a/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.processor.ts b/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.processor.ts new file mode 100644 index 000000000..f8173559e --- /dev/null +++ b/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.processor.ts @@ -0,0 +1,96 @@ +import { OrderService } from '@ghostfolio/api/app/order/order.service'; +import { + PerformanceCalculationType, + PortfolioCalculatorFactory +} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory'; +import { PortfolioSnapshotValue } from '@ghostfolio/api/app/portfolio/interfaces/snapshot-value.interface'; +import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service'; +import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; +import { + CACHE_TTL_INFINITE, + PORTFOLIO_SNAPSHOT_PROCESS_JOB_NAME, + PORTFOLIO_SNAPSHOT_QUEUE +} from '@ghostfolio/common/config'; + +import { Process, Processor } from '@nestjs/bull'; +import { Injectable, Logger } from '@nestjs/common'; +import { Job } from 'bull'; +import { addMilliseconds } from 'date-fns'; + +import { IPortfolioSnapshotQueueJob } from './interfaces/portfolio-snapshot-queue-job.interface'; + +@Injectable() +@Processor(PORTFOLIO_SNAPSHOT_QUEUE) +export class PortfolioSnapshotProcessor { + public constructor( + private readonly calculatorFactory: PortfolioCalculatorFactory, + private readonly configurationService: ConfigurationService, + private readonly orderService: OrderService, + private readonly redisCacheService: RedisCacheService + ) {} + + @Process({ concurrency: 1, name: PORTFOLIO_SNAPSHOT_PROCESS_JOB_NAME }) + public async calculatePortfolioSnapshot( + job: Job + ) { + try { + const startTime = performance.now(); + + Logger.log( + `Portfolio snapshot calculation of user '${job.data.userId}' has been started`, + `PortfolioSnapshotProcessor (${PORTFOLIO_SNAPSHOT_PROCESS_JOB_NAME})` + ); + + const { activities } = + await this.orderService.getOrdersForPortfolioCalculator({ + filters: job.data.filters, + userCurrency: job.data.userCurrency, + userId: job.data.userId + }); + + const portfolioCalculator = this.calculatorFactory.createCalculator({ + activities, + calculationType: PerformanceCalculationType.TWR, + currency: job.data.userCurrency, + filters: job.data.filters, + userId: job.data.userId + }); + + const snapshot = await portfolioCalculator.computeSnapshot(); + + Logger.log( + `Portfolio snapshot calculation of user '${job.data.userId}' has been completed in ${( + (performance.now() - startTime) / + 1000 + ).toFixed(3)} seconds`, + `PortfolioSnapshotProcessor (${PORTFOLIO_SNAPSHOT_PROCESS_JOB_NAME})` + ); + + const expiration = addMilliseconds( + new Date(), + this.configurationService.get('CACHE_QUOTES_TTL') + ); + + this.redisCacheService.set( + this.redisCacheService.getPortfolioSnapshotKey({ + filters: job.data.filters, + userId: job.data.userId + }), + JSON.stringify(({ + expiration: expiration.getTime(), + portfolioSnapshot: snapshot + })), + CACHE_TTL_INFINITE + ); + + return snapshot; + } catch (error) { + Logger.error( + error, + `PortfolioSnapshotProcessor (${PORTFOLIO_SNAPSHOT_PROCESS_JOB_NAME})` + ); + + throw new Error(error); + } + } +} diff --git a/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock.ts b/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock.ts new file mode 100644 index 000000000..8d7526906 --- /dev/null +++ b/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock.ts @@ -0,0 +1,34 @@ +import { Job, JobOptions } from 'bull'; +import { setTimeout } from 'timers/promises'; + +import { IPortfolioSnapshotQueueJob } from './interfaces/portfolio-snapshot-queue-job.interface'; + +export const PortfolioSnapshotServiceMock = { + addJobToQueue({ + data, + name, + opts + }: { + data: IPortfolioSnapshotQueueJob; + name: string; + opts?: JobOptions; + }): Promise> { + const mockJob: Partial> = { + finished: async () => { + await setTimeout(100); + + return Promise.resolve(); + } + }; + + this.jobsStore.set(opts?.jobId, mockJob); + + return Promise.resolve(mockJob as Job); + }, + getJob(jobId: string): Promise> { + const job = this.jobsStore.get(jobId); + + return Promise.resolve(job as Job); + }, + jobsStore: new Map>>() +}; diff --git a/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.service.ts b/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.service.ts new file mode 100644 index 000000000..27ebdee53 --- /dev/null +++ b/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.service.ts @@ -0,0 +1,31 @@ +import { PORTFOLIO_SNAPSHOT_QUEUE } from '@ghostfolio/common/config'; + +import { InjectQueue } from '@nestjs/bull'; +import { Injectable } from '@nestjs/common'; +import { JobOptions, Queue } from 'bull'; + +import { IPortfolioSnapshotQueueJob } from './interfaces/portfolio-snapshot-queue-job.interface'; + +@Injectable() +export class PortfolioSnapshotService { + public constructor( + @InjectQueue(PORTFOLIO_SNAPSHOT_QUEUE) + private readonly portfolioSnapshotQueue: Queue + ) {} + + public async addJobToQueue({ + data, + name, + opts + }: { + data: IPortfolioSnapshotQueueJob; + name: string; + opts?: JobOptions; + }) { + return this.portfolioSnapshotQueue.add(name, data, opts); + } + + public async getJob(jobId: string) { + return this.portfolioSnapshotQueue.getJob(jobId); + } +} diff --git a/apps/client/src/app/components/admin-jobs/admin-jobs.html b/apps/client/src/app/components/admin-jobs/admin-jobs.html index e194b2b37..ef46d766e 100644 --- a/apps/client/src/app/components/admin-jobs/admin-jobs.html +++ b/apps/client/src/app/components/admin-jobs/admin-jobs.html @@ -35,6 +35,8 @@ Asset Profile } @else if (element.name === 'GATHER_HISTORICAL_MARKET_DATA') { Historical Market Data + } @else if (element.name === 'PORTFOLIO') { + Portfolio Snapshot } diff --git a/libs/common/src/lib/config.ts b/libs/common/src/lib/config.ts index 00e756810..79fdf6d05 100644 --- a/libs/common/src/lib/config.ts +++ b/libs/common/src/lib/config.ts @@ -40,6 +40,10 @@ export const DATA_GATHERING_QUEUE_PRIORITY_MEDIUM = Math.round( DATA_GATHERING_QUEUE_PRIORITY_LOW / 2 ); +export const PORTFOLIO_SNAPSHOT_QUEUE = 'PORTFOLIO_SNAPSHOT_QUEUE'; +export const PORTFOLIO_SNAPSHOT_QUEUE_PRIORITY_HIGH = 1; +export const PORTFOLIO_SNAPSHOT_QUEUE_PRIORITY_LOW = Number.MAX_SAFE_INTEGER; + export const DEFAULT_CURRENCY = 'USD'; export const DEFAULT_DATE_FORMAT_MONTH_YEAR = 'MMM yyyy'; export const DEFAULT_LANGUAGE_CODE = 'en'; @@ -76,9 +80,10 @@ export const GATHER_ASSET_PROFILE_PROCESS_OPTIONS: JobOptions = { }, removeOnComplete: true }; -export const GATHER_HISTORICAL_MARKET_DATA_PROCESS = + +export const GATHER_HISTORICAL_MARKET_DATA_PROCESS_JOB_NAME = 'GATHER_HISTORICAL_MARKET_DATA'; -export const GATHER_HISTORICAL_MARKET_DATA_PROCESS_OPTIONS: JobOptions = { +export const GATHER_HISTORICAL_MARKET_DATA_PROCESS_JOB_OPTIONS: JobOptions = { attempts: 12, backoff: { delay: ms('1 minute'), @@ -87,6 +92,11 @@ export const GATHER_HISTORICAL_MARKET_DATA_PROCESS_OPTIONS: JobOptions = { removeOnComplete: true }; +export const PORTFOLIO_SNAPSHOT_PROCESS_JOB_NAME = 'PORTFOLIO'; +export const PORTFOLIO_SNAPSHOT_PROCESS_JOB_OPTIONS: JobOptions = { + removeOnComplete: true +}; + export const HEADER_KEY_IMPERSONATION = 'Impersonation-Id'; export const HEADER_KEY_TIMEZONE = 'Timezone'; export const HEADER_KEY_TOKEN = 'Authorization'; From c4cbdfc6433d89fed757285da1fa8ecae2ecd56f Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Tue, 10 Sep 2024 20:34:36 +0200 Subject: [PATCH 35/78] Release 2.107.0 (#3748) --- CHANGELOG.md | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d1d6d787c..1779a268d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased +## 2.107.0 - 2024-09-10 ### Added diff --git a/package.json b/package.json index 244ca0d7a..3a91229f0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "2.106.0", + "version": "2.107.0", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "repository": "https://github.com/ghostfolio/ghostfolio", From 0ef2b828520f30ef5a296158ba31334e6e23ac56 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Thu, 12 Sep 2024 20:33:21 +0200 Subject: [PATCH 36/78] Bugfix/fix destructuring in activities filters (#3756) * Provide default value during destructuring * Update changelog --- CHANGELOG.md | 6 ++++++ apps/client/src/app/services/data.service.ts | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1779a268d..4b2072118 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 an issue in the activities filters that occured during destructuring + ## 2.107.0 - 2024-09-10 ### Added diff --git a/apps/client/src/app/services/data.service.ts b/apps/client/src/app/services/data.service.ts index 64376a606..cbdde0265 100644 --- a/apps/client/src/app/services/data.service.ts +++ b/apps/client/src/app/services/data.service.ts @@ -72,11 +72,11 @@ export class DataService { ACCOUNT: filtersByAccount, ASSET_CLASS: filtersByAssetClass, ASSET_SUB_CLASS: filtersByAssetSubClass, - DATA_SOURCE: [filterByDataSource], + DATA_SOURCE: [filterByDataSource] = [], HOLDING_TYPE: filtersByHoldingType, PRESET_ID: filtersByPresetId, SEARCH_QUERY: filtersBySearchQuery, - SYMBOL: [filterBySymbol], + SYMBOL: [filterBySymbol] = [], TAG: filtersByTag } = groupBy(filters, (filter) => { return filter.type; From 5a4f1c03cbc8bc38d96e8d117fcffffeacc3f2c2 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Thu, 12 Sep 2024 20:34:06 +0200 Subject: [PATCH 37/78] Feature/extend personal finance tools (#3751) Add etops --- libs/common/src/lib/personal-finance-tools.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libs/common/src/lib/personal-finance-tools.ts b/libs/common/src/lib/personal-finance-tools.ts index e19b1eb5b..ec1d78564 100644 --- a/libs/common/src/lib/personal-finance-tools.ts +++ b/libs/common/src/lib/personal-finance-tools.ts @@ -163,6 +163,14 @@ export const personalFinanceTools: Product[] = [ origin: 'United States', slogan: 'Portfolio Tracker Designed by Professional Investors' }, + { + founded: 2010, + hasFreePlan: false, + key: 'etops', + name: 'etops', + origin: 'Switzerland', + slogan: 'Your financial superpower' + }, { founded: 2020, hasFreePlan: true, From 7b8dc480f4fefa4f6c02cfd71af77ac67848eacb Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Thu, 12 Sep 2024 20:35:42 +0200 Subject: [PATCH 38/78] Release 2.107.1 (#3757) --- CHANGELOG.md | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b2072118..0042fa7d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased +## 2.107.1 - 2024-09-12 ### Fixed diff --git a/package.json b/package.json index 3a91229f0..4bdb8e19d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "2.107.0", + "version": "2.107.1", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "repository": "https://github.com/ghostfolio/ghostfolio", From 8735fc3fad9c5a119c75e2b6604daf1f65994970 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 14 Sep 2024 10:27:12 +0200 Subject: [PATCH 39/78] Bugfix/fix typo in changelog (#3758) --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0042fa7d0..273b5457e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed -- Fixed an issue in the activities filters that occured during destructuring +- Fixed an issue in the activities filters that occurred during destructuring ## 2.107.0 - 2024-09-10 From 323cfbfcaa7d3700af02508d0b63d231f08af34f Mon Sep 17 00:00:00 2001 From: Shaunak Das <51281688+shaun-ak@users.noreply.github.com> Date: Sat, 14 Sep 2024 14:23:39 +0530 Subject: [PATCH 40/78] Feature/introduce filters in account endpoint (#3764) * Introduce filters in acount endpoint * Integrate endpoint in holding detail dialog * Update changelog --------- Co-authored-by: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> --- CHANGELOG.md | 10 +++++++ .../api/src/app/account/account.controller.ts | 15 +++++++++- apps/api/src/app/account/account.module.ts | 2 ++ .../src/app/portfolio/portfolio.service.ts | 29 ++++++++++++++++--- .../holding-detail-dialog.component.ts | 24 +++++++++++---- apps/client/src/app/services/data.service.ts | 6 ++-- 6 files changed, 73 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 273b5457e..b69e9703f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,16 @@ 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 + +- Introduced filters (`dataSource` and `symbol`) in the accounts endpoint + +### Changed + +- Switched to the accounts endpoint in the holding detail dialog + ## 2.107.1 - 2024-09-12 ### Fixed diff --git a/apps/api/src/app/account/account.controller.ts b/apps/api/src/app/account/account.controller.ts index 594a733f7..d8c3dd002 100644 --- a/apps/api/src/app/account/account.controller.ts +++ b/apps/api/src/app/account/account.controller.ts @@ -3,6 +3,8 @@ import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.servic import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator'; import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard'; import { RedactValuesInResponseInterceptor } from '@ghostfolio/api/interceptors/redact-values-in-response/redact-values-in-response.interceptor'; +import { TransformDataSourceInRequestInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.interceptor'; +import { ApiService } from '@ghostfolio/api/services/api/api.service'; import { ImpersonationService } from '@ghostfolio/api/services/impersonation/impersonation.service'; import { HEADER_KEY_IMPERSONATION } from '@ghostfolio/common/config'; import { @@ -26,6 +28,7 @@ import { Param, Post, Put, + Query, UseGuards, UseInterceptors } from '@nestjs/common'; @@ -44,6 +47,7 @@ export class AccountController { public constructor( private readonly accountBalanceService: AccountBalanceService, private readonly accountService: AccountService, + private readonly apiService: ApiService, private readonly impersonationService: ImpersonationService, private readonly portfolioService: PortfolioService, @Inject(REQUEST) private readonly request: RequestWithUser @@ -84,13 +88,22 @@ export class AccountController { @Get() @UseGuards(AuthGuard('jwt'), HasPermissionGuard) @UseInterceptors(RedactValuesInResponseInterceptor) + @UseInterceptors(TransformDataSourceInRequestInterceptor) public async getAllAccounts( - @Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId + @Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId, + @Query('dataSource') filterByDataSource?: string, + @Query('symbol') filterBySymbol?: string ): Promise { const impersonationUserId = await this.impersonationService.validateImpersonationId(impersonationId); + const filters = this.apiService.buildFiltersFromQueryParams({ + filterByDataSource, + filterBySymbol + }); + return this.portfolioService.getAccountsWithAggregations({ + filters, userId: impersonationUserId || this.request.user.id, withExcludedAccounts: true }); diff --git a/apps/api/src/app/account/account.module.ts b/apps/api/src/app/account/account.module.ts index 1c2d20216..fb89bb2b6 100644 --- a/apps/api/src/app/account/account.module.ts +++ b/apps/api/src/app/account/account.module.ts @@ -1,6 +1,7 @@ import { AccountBalanceModule } from '@ghostfolio/api/app/account-balance/account-balance.module'; import { PortfolioModule } from '@ghostfolio/api/app/portfolio/portfolio.module'; import { RedactValuesInResponseModule } from '@ghostfolio/api/interceptors/redact-values-in-response/redact-values-in-response.module'; +import { ApiModule } from '@ghostfolio/api/services/api/api.module'; import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module'; import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module'; import { ImpersonationModule } from '@ghostfolio/api/services/impersonation/impersonation.module'; @@ -16,6 +17,7 @@ import { AccountService } from './account.service'; exports: [AccountService], imports: [ AccountBalanceModule, + ApiModule, ConfigurationModule, ExchangeRateDataModule, ImpersonationModule, diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index 0cd602046..e1dfc888d 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -115,12 +115,33 @@ export class PortfolioService { }): Promise { const where: Prisma.AccountWhereInput = { userId }; - const accountFilter = filters?.find(({ type }) => { + const filterByAccount = filters?.find(({ type }) => { return type === 'ACCOUNT'; - }); + })?.id; + + const filterByDataSource = filters?.find(({ type }) => { + return type === 'DATA_SOURCE'; + })?.id; + + const filterBySymbol = filters?.find(({ type }) => { + return type === 'SYMBOL'; + })?.id; - if (accountFilter) { - where.id = accountFilter.id; + if (filterByAccount) { + where.id = filterByAccount; + } + + if (filterByDataSource && filterBySymbol) { + where.Order = { + some: { + SymbolProfile: { + AND: [ + { dataSource: filterByDataSource }, + { symbol: filterBySymbol } + ] + } + } + }; } const [accounts, details] = await Promise.all([ diff --git a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts index 70cd08874..8541f65ac 100644 --- a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts +++ b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts @@ -9,6 +9,7 @@ import { DATE_FORMAT, downloadAsFile } from '@ghostfolio/common/helper'; import { DataProviderInfo, EnhancedSymbolProfile, + Filter, LineChartItem, User } from '@ghostfolio/common/interfaces'; @@ -152,6 +153,11 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { tags: [] }); + const filters: Filter[] = [ + { id: this.data.dataSource, type: 'DATA_SOURCE' }, + { id: this.data.symbol, type: 'SYMBOL' } + ]; + this.tagsAvailable = tags.map(({ id, name }) => { return { id, @@ -173,12 +179,20 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { .subscribe(); }); + this.dataService + .fetchAccounts({ + filters + }) + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe(({ accounts }) => { + this.accounts = accounts; + + this.changeDetectorRef.markForCheck(); + }); + this.dataService .fetchActivities({ - filters: [ - { id: this.data.dataSource, type: 'DATA_SOURCE' }, - { id: this.data.symbol, type: 'SYMBOL' } - ], + filters, sortColumn: this.sortColumn, sortDirection: this.sortDirection }) @@ -197,7 +211,6 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { .pipe(takeUntil(this.unsubscribeSubject)) .subscribe( ({ - accounts, averagePrice, dataProviderInfo, dividendInBaseCurrency, @@ -219,7 +232,6 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { transactionCount, value }) => { - this.accounts = accounts; this.averagePrice = averagePrice; this.benchmarkDataItems = []; this.countries = {}; diff --git a/apps/client/src/app/services/data.service.ts b/apps/client/src/app/services/data.service.ts index cbdde0265..78373adcc 100644 --- a/apps/client/src/app/services/data.service.ts +++ b/apps/client/src/app/services/data.service.ts @@ -173,8 +173,10 @@ export class DataService { ); } - public fetchAccounts() { - return this.http.get('/api/v1/account'); + public fetchAccounts({ filters }: { filters?: Filter[] } = {}) { + const params = this.buildFiltersAsQueryParams({ filters }); + + return this.http.get('/api/v1/account', { params }); } public fetchActivities({ From d236ecfe8501201a344d8e345a186f294ca1b032 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 14 Sep 2024 17:29:01 +0200 Subject: [PATCH 41/78] Feature/extend personal finance tools 20240914 (#3767) * Add Buxfer * Add Moneydance * Add Banktivity * Add Microsoft Money * Add Masttro * Add WealthPosition --- libs/common/src/lib/personal-finance-tools.ts | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/libs/common/src/lib/personal-finance-tools.ts b/libs/common/src/lib/personal-finance-tools.ts index ec1d78564..29fcc391e 100644 --- a/libs/common/src/lib/personal-finance-tools.ts +++ b/libs/common/src/lib/personal-finance-tools.ts @@ -44,6 +44,15 @@ export const personalFinanceTools: Product[] = [ pricingPerYear: '$120', slogan: 'Analyze and track your portfolio.' }, + { + hasFreePlan: false, + hasSelfHostingAbility: true, + key: 'banktivity', + name: 'Banktivity', + origin: 'United States', + pricingPerYear: '$59.99', + slogan: 'Proactive money management app for macOS & iOS' + }, { founded: 2022, hasFreePlan: true, @@ -62,6 +71,17 @@ export const personalFinanceTools: Product[] = [ pricingPerYear: '$100', slogan: 'Stock Portfolio Tracker for Smart Investors' }, + { + founded: 2007, + hasFreePlan: false, + hasSelfHostingAbility: false, + key: 'buxfer', + name: 'Buxfer', + origin: 'United States', + pricingPerYear: '$48', + regions: ['Global'], + slogan: 'Take control of your financial future' + }, { founded: 2013, hasFreePlan: true, @@ -329,6 +349,13 @@ export const personalFinanceTools: Product[] = [ regions: ['Global'], slogan: 'Track your investments' }, + { + founded: 2010, + key: 'masttro', + name: 'Masttro', + origin: 'United States', + slogan: 'Your platform for wealth in full view' + }, { founded: 2021, hasSelfHostingAbility: false, @@ -352,6 +379,14 @@ export const personalFinanceTools: Product[] = [ regions: ['Canada', 'United States'], slogan: 'The smartest way to track your crypto' }, + { + founded: 1991, + hasSelfHostingAbility: true, + key: 'microsoft-money', + name: 'Microsoft Money', + note: 'Microsoft Money was discontinued in 2010', + origin: 'United States' + }, { founded: 2019, hasFreePlan: false, @@ -362,6 +397,16 @@ export const personalFinanceTools: Product[] = [ pricingPerYear: '$99.99', slogan: 'The modern way to manage your money' }, + { + founded: 1999, + hasFreePlan: false, + hasSelfHostingAbility: true, + key: 'moneydance', + name: 'Moneydance', + origin: 'Scotland', + pricingPerYear: '$100', + slogan: 'Personal Finance Manager for Mac, Windows, and Linux' + }, { hasFreePlan: false, hasSelfHostingAbility: false, @@ -640,6 +685,14 @@ export const personalFinanceTools: Product[] = [ pricingPerYear: '$50', slogan: 'See all your investments in one place' }, + { + founded: 2018, + hasFreePlan: true, + key: 'wealthposition', + name: 'WealthPosition', + pricingPerYear: '$60', + slogan: 'Personal Finance & Budgeting App' + }, { founded: 2018, hasSelfHostingAbility: false, From 9fb80e5067e991b101813d7b0782dc99df78cb46 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 14 Sep 2024 17:29:52 +0200 Subject: [PATCH 42/78] Feature/remove accounts from holding endpoint (#3765) * Clean up accounts --- .../portfolio-holding-detail.interface.ts | 3 +-- apps/api/src/app/portfolio/portfolio.service.ts | 14 +------------- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/apps/api/src/app/portfolio/interfaces/portfolio-holding-detail.interface.ts b/apps/api/src/app/portfolio/interfaces/portfolio-holding-detail.interface.ts index 3ce23a3bc..79e4d40dc 100644 --- a/apps/api/src/app/portfolio/interfaces/portfolio-holding-detail.interface.ts +++ b/apps/api/src/app/portfolio/interfaces/portfolio-holding-detail.interface.ts @@ -5,10 +5,9 @@ import { HistoricalDataItem } from '@ghostfolio/common/interfaces'; -import { Account, Tag } from '@prisma/client'; +import { Tag } from '@prisma/client'; export interface PortfolioHoldingDetail { - accounts: Account[]; averagePrice: number; dataProviderInfo: DataProviderInfo; dividendInBaseCurrency: number; diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index e1dfc888d..39ac9cc6f 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -73,7 +73,7 @@ import { parseISO, set } from 'date-fns'; -import { isEmpty, last, uniq, uniqBy } from 'lodash'; +import { isEmpty, last, uniq } from 'lodash'; import { PortfolioCalculator } from './calculator/portfolio-calculator'; import { @@ -625,7 +625,6 @@ export class PortfolioService { if (activities.length === 0) { return { - accounts: [], averagePrice: undefined, dataProviderInfo: undefined, dividendInBaseCurrency: undefined, @@ -699,15 +698,6 @@ export class PortfolioService { ); }); - const accounts: PortfolioHoldingDetail['accounts'] = uniqBy( - activitiesOfPosition.filter(({ Account }) => { - return Account; - }), - 'Account.id' - ).map(({ Account }) => { - return Account; - }); - const dividendYieldPercent = getAnnualizedPerformancePercent({ daysInMarket: differenceInDays(new Date(), parseDate(firstBuyDate)), netPerformancePercentage: timeWeightedInvestment.eq(0) @@ -788,7 +778,6 @@ export class PortfolioService { } return { - accounts, firstBuyDate, marketPrice, maxPrice, @@ -883,7 +872,6 @@ export class PortfolioService { maxPrice, minPrice, SymbolProfile, - accounts: [], averagePrice: 0, dataProviderInfo: undefined, dividendInBaseCurrency: 0, From 3de192c65ef65b8e0e4b9c8f26a3921e1524d073 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 14 Sep 2024 19:42:37 +0200 Subject: [PATCH 43/78] Feature/expose thresholds in rule settings (#3770) --- apps/api/src/app/portfolio/rules.service.ts | 21 ++++++++++++------- .../portfolio-report-rule.interface.ts | 4 ++++ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/apps/api/src/app/portfolio/rules.service.ts b/apps/api/src/app/portfolio/rules.service.ts index 6b6526144..fd9d794b2 100644 --- a/apps/api/src/app/portfolio/rules.service.ts +++ b/apps/api/src/app/portfolio/rules.service.ts @@ -1,6 +1,9 @@ import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface'; import { Rule } from '@ghostfolio/api/models/rule'; -import { UserSettings } from '@ghostfolio/common/interfaces'; +import { + PortfolioReportRule, + UserSettings +} from '@ghostfolio/common/interfaces'; import { Injectable } from '@nestjs/common'; @@ -11,19 +14,23 @@ export class RulesService { public async evaluate( aRules: Rule[], aUserSettings: UserSettings - ) { + ): Promise { return aRules.map((rule) => { - if (rule.getSettings(aUserSettings)?.isActive) { - const { evaluation, value } = rule.evaluate( - rule.getSettings(aUserSettings) - ); + const settings = rule.getSettings(aUserSettings); + + if (settings?.isActive) { + const { evaluation, value } = rule.evaluate(settings); return { evaluation, value, isActive: true, key: rule.getKey(), - name: rule.getName() + name: rule.getName(), + settings: { + thresholdMax: settings['thresholdMax'], + thresholdMin: settings['thresholdMin'] + } }; } else { return { diff --git a/libs/common/src/lib/interfaces/portfolio-report-rule.interface.ts b/libs/common/src/lib/interfaces/portfolio-report-rule.interface.ts index 61fe389af..29cbb4a8f 100644 --- a/libs/common/src/lib/interfaces/portfolio-report-rule.interface.ts +++ b/libs/common/src/lib/interfaces/portfolio-report-rule.interface.ts @@ -3,5 +3,9 @@ export interface PortfolioReportRule { isActive: boolean; key: string; name: string; + settings?: { + thresholdMax?: number; + thresholdMin?: number; + }; value?: boolean; } From fbf377f67f938395e961dbf599349e0f9156d4a8 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 14 Sep 2024 20:44:36 +0200 Subject: [PATCH 44/78] Feature/set up rule settings dialog (#3771) --- .../interfaces/interfaces.ts | 5 ++ .../rule-settings-dialog.component.ts | 40 +++++++++++++++ .../rule-settings-dialog.html | 23 +++++++++ .../rule-settings-dialog.scss | 2 + .../app/components/rule/rule.component.html | 5 ++ .../src/app/components/rule/rule.component.ts | 49 ++++++++++++++++++- 6 files changed, 122 insertions(+), 2 deletions(-) create mode 100644 apps/client/src/app/components/rule/rule-settings-dialog/interfaces/interfaces.ts create mode 100644 apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.component.ts create mode 100644 apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html create mode 100644 apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.scss diff --git a/apps/client/src/app/components/rule/rule-settings-dialog/interfaces/interfaces.ts b/apps/client/src/app/components/rule/rule-settings-dialog/interfaces/interfaces.ts new file mode 100644 index 000000000..a409ab503 --- /dev/null +++ b/apps/client/src/app/components/rule/rule-settings-dialog/interfaces/interfaces.ts @@ -0,0 +1,5 @@ +import { PortfolioReportRule } from '@ghostfolio/common/interfaces'; + +export interface IRuleSettingsDialogParams { + rule: PortfolioReportRule; +} diff --git a/apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.component.ts b/apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.component.ts new file mode 100644 index 000000000..41ebf49db --- /dev/null +++ b/apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.component.ts @@ -0,0 +1,40 @@ +import { PortfolioReportRule } from '@ghostfolio/common/interfaces'; + +import { CommonModule } from '@angular/common'; +import { Component, Inject } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { + MAT_DIALOG_DATA, + MatDialogModule, + MatDialogRef +} from '@angular/material/dialog'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatInputModule } from '@angular/material/input'; + +import { IRuleSettingsDialogParams } from './interfaces/interfaces'; + +@Component({ + imports: [ + CommonModule, + MatButtonModule, + MatDialogModule, + MatFormFieldModule, + MatInputModule + ], + selector: 'gf-rule-settings-dialog', + standalone: true, + styleUrls: ['./rule-settings-dialog.scss'], + templateUrl: './rule-settings-dialog.html' +}) +export class GfRuleSettingsDialogComponent { + public settings: PortfolioReportRule['settings']; + + public constructor( + @Inject(MAT_DIALOG_DATA) public data: IRuleSettingsDialogParams, + public dialogRef: MatDialogRef + ) { + console.log(this.data.rule); + + this.settings = this.data.rule.settings; + } +} diff --git a/apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html b/apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html new file mode 100644 index 000000000..e24db29f7 --- /dev/null +++ b/apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html @@ -0,0 +1,23 @@ +
{{ data.rule.name }}
+ +
+ + Threshold Min + + + + Threshold Max + + +
+ +
+ + +
diff --git a/apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.scss b/apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.scss new file mode 100644 index 000000000..dc9093b45 --- /dev/null +++ b/apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.scss @@ -0,0 +1,2 @@ +:host { +} diff --git a/apps/client/src/app/components/rule/rule.component.html b/apps/client/src/app/components/rule/rule.component.html index 80b442b7b..f19436aba 100644 --- a/apps/client/src/app/components/rule/rule.component.html +++ b/apps/client/src/app/components/rule/rule.component.html @@ -62,6 +62,11 @@ + @if (rule?.isActive && !isEmpty(rule.settings) && false) { + + } + @if (element.type === 'PUBLIC') { + + } diff --git a/apps/client/src/app/components/access-table/access-table.component.ts b/apps/client/src/app/components/access-table/access-table.component.ts index 7772451d4..3d47c6087 100644 --- a/apps/client/src/app/components/access-table/access-table.component.ts +++ b/apps/client/src/app/components/access-table/access-table.component.ts @@ -3,6 +3,7 @@ import { NotificationService } from '@ghostfolio/client/core/notification/notifi import { DEFAULT_LANGUAGE_CODE } from '@ghostfolio/common/config'; import { Access } from '@ghostfolio/common/interfaces'; +import { Clipboard } from '@angular/cdk/clipboard'; import { ChangeDetectionStrategy, Component, @@ -31,7 +32,10 @@ export class AccessTableComponent implements OnChanges, OnInit { public defaultLanguageCode = DEFAULT_LANGUAGE_CODE; public displayedColumns = []; - public constructor(private notificationService: NotificationService) {} + public constructor( + private clipboard: Clipboard, + private notificationService: NotificationService + ) {} public ngOnInit() {} @@ -47,6 +51,14 @@ export class AccessTableComponent implements OnChanges, OnInit { } } + public getPublicUrl(aId: string): string { + return `${this.baseUrl}/${this.defaultLanguageCode}/p/${aId}`; + } + + public onCopyToClipboard(aId: string): void { + this.clipboard.copy(this.getPublicUrl(aId)); + } + public onDeleteAccess(aId: string) { this.notificationService.confirm({ confirmFn: () => { diff --git a/apps/client/src/app/components/access-table/access-table.module.ts b/apps/client/src/app/components/access-table/access-table.module.ts index 2ace3cfc1..4cbc7b580 100644 --- a/apps/client/src/app/components/access-table/access-table.module.ts +++ b/apps/client/src/app/components/access-table/access-table.module.ts @@ -1,3 +1,4 @@ +import { ClipboardModule } from '@angular/cdk/clipboard'; import { CommonModule } from '@angular/common'; import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; @@ -11,6 +12,7 @@ import { AccessTableComponent } from './access-table.component'; declarations: [AccessTableComponent], exports: [AccessTableComponent], imports: [ + ClipboardModule, CommonModule, MatButtonModule, MatMenuModule, From 4865aa1665ce4cba159875423a43d5f6cbe509fa Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Tue, 17 Sep 2024 20:15:16 +0200 Subject: [PATCH 49/78] Feature/add fallback in get quotes of eod historical data service (#3776) * Add fallback to previousClose in getQuotes() * Update changelog --- CHANGELOG.md | 1 + .../eod-historical-data.service.ts | 30 +++++++++++++------ 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd2ec27a0..a3c1f6c4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Improved the usability of the toggle component - Switched to the accounts endpoint in the holding detail dialog +- Added a fallback in the get quotes functionality of the _EOD Historical Data_ service ## 2.107.1 - 2024-09-12 diff --git a/apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts b/apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts index cf2fd42de..8b2a1828b 100644 --- a/apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts +++ b/apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts @@ -18,6 +18,7 @@ import { } from '@ghostfolio/common/config'; import { DATE_FORMAT, isCurrency } from '@ghostfolio/common/helper'; import { DataProviderInfo } from '@ghostfolio/common/interfaces'; +import { MarketState } from '@ghostfolio/common/types'; import { Injectable, Logger } from '@nestjs/common'; import { @@ -229,7 +230,12 @@ export class EodHistoricalDataService implements DataProviderInterface { } ).json(); - const quotes = + const quotes: { + close: number; + code: string; + previousClose: number; + timestamp: number; + }[] = eodHistoricalDataSymbols.length === 1 ? [realTimeResponse] : realTimeResponse; @@ -243,7 +249,7 @@ export class EodHistoricalDataService implements DataProviderInterface { }) ); - for (const { close, code, timestamp } of quotes) { + for (const { close, code, previousClose, timestamp } of quotes) { let currency: string; if (this.isForex(code)) { @@ -267,15 +273,21 @@ export class EodHistoricalDataService implements DataProviderInterface { } } - if (isNumber(close)) { + if (isNumber(close) || isNumber(previousClose)) { + const marketPrice: number = isNumber(close) ? close : previousClose; + let marketState: MarketState = 'closed'; + + if (this.isForex(code) || isToday(new Date(timestamp * 1000))) { + marketState = 'open'; + } else if (!isNumber(close)) { + marketState = 'delayed'; + } + response[this.convertFromEodSymbol(code)] = { currency, - dataSource: this.getName(), - marketPrice: close, - marketState: - this.isForex(code) || isToday(new Date(timestamp * 1000)) - ? 'open' - : 'closed' + marketPrice, + marketState, + dataSource: this.getName() }; } else { Logger.error( From 22127b59151f4d1a045d2bf7e6f5578f4602322a Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Tue, 17 Sep 2024 20:17:23 +0200 Subject: [PATCH 50/78] Release 2.108.0 (#3777) --- CHANGELOG.md | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3c1f6c4e..bf5b0aa78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased +## 2.108.0 - 2024-09-17 ### Added diff --git a/package.json b/package.json index 4bdb8e19d..d8d6b2d53 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "2.107.1", + "version": "2.108.0", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "repository": "https://github.com/ghostfolio/ghostfolio", From 97467a380909a19ba274a2db77a5636eaf3df56a Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Wed, 18 Sep 2024 15:58:19 +0200 Subject: [PATCH 51/78] Feature/improve language localization for de 20240917 (#3778) * Update translations * Update changelog --- CHANGELOG.md | 6 + apps/client/src/locales/messages.ca.xlf | 288 +++++++++++--------- apps/client/src/locales/messages.de.xlf | 288 +++++++++++--------- apps/client/src/locales/messages.es.xlf | 288 +++++++++++--------- apps/client/src/locales/messages.fr.xlf | 344 +++++++++++++----------- apps/client/src/locales/messages.it.xlf | 312 +++++++++++---------- apps/client/src/locales/messages.nl.xlf | 288 +++++++++++--------- apps/client/src/locales/messages.pl.xlf | 288 +++++++++++--------- apps/client/src/locales/messages.pt.xlf | 288 +++++++++++--------- apps/client/src/locales/messages.tr.xlf | 288 +++++++++++--------- apps/client/src/locales/messages.xlf | 275 ++++++++++--------- apps/client/src/locales/messages.zh.xlf | 288 +++++++++++--------- 12 files changed, 1841 insertions(+), 1400 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bf5b0aa78..c8f722116 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 language localization for German (`de`) + ## 2.108.0 - 2024-09-17 ### Added diff --git a/apps/client/src/locales/messages.ca.xlf b/apps/client/src/locales/messages.ca.xlf index 89083200c..eb370f7e5 100644 --- a/apps/client/src/locales/messages.ca.xlf +++ b/apps/client/src/locales/messages.ca.xlf @@ -26,7 +26,7 @@ apps/client/src/app/components/header/header.component.ts - 231 + 227 @@ -818,7 +818,7 @@ Revocar apps/client/src/app/components/access-table/access-table.component.html - 62 + 65 @@ -826,7 +826,7 @@ Realment vol revocar aquest accés? apps/client/src/app/components/access-table/access-table.component.ts - 56 + 68 @@ -834,7 +834,7 @@ Balanç de Caixa apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 45 + 47 apps/client/src/app/components/accounts-table/accounts-table.component.html @@ -850,7 +850,7 @@ Patrimoni apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 56 + 58 @@ -858,11 +858,11 @@ Activitats apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 61 + 63 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 90 + 92 apps/client/src/app/components/accounts-table/accounts-table.component.html @@ -882,11 +882,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 225 + 209 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 335 + 319 apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -898,7 +898,7 @@ Plataforma apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 65 + 67 apps/client/src/app/components/accounts-table/accounts-table.component.html @@ -914,7 +914,7 @@ En cartera apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 77 + 79 apps/client/src/app/components/home-holdings/home-holdings.html @@ -934,7 +934,7 @@ Balanç de Caixa apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 122 + 124 @@ -1110,7 +1110,7 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html - 215 + 230 apps/client/src/app/components/admin-overview/admin-overview.html @@ -1138,7 +1138,7 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html - 236 + 251 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -1218,7 +1218,7 @@ Símbol apps/client/src/app/components/admin-jobs/admin-jobs.html - 44 + 46 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -1234,7 +1234,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 305 + 289 @@ -1242,7 +1242,7 @@ Origen de les Dades apps/client/src/app/components/admin-jobs/admin-jobs.html - 53 + 55 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -1262,7 +1262,7 @@ Prioritat apps/client/src/app/components/admin-jobs/admin-jobs.html - 62 + 64 @@ -1270,7 +1270,7 @@ Intents apps/client/src/app/components/admin-jobs/admin-jobs.html - 81 + 83 @@ -1278,7 +1278,7 @@ Creat apps/client/src/app/components/admin-jobs/admin-jobs.html - 90 + 92 @@ -1286,7 +1286,7 @@ Finalitzat apps/client/src/app/components/admin-jobs/admin-jobs.html - 99 + 101 @@ -1294,7 +1294,7 @@ Estat apps/client/src/app/components/admin-jobs/admin-jobs.html - 108 + 110 @@ -1302,7 +1302,7 @@ Aturar Processos apps/client/src/app/components/admin-jobs/admin-jobs.html - 149 + 151 @@ -1310,7 +1310,7 @@ Veure les Dades apps/client/src/app/components/admin-jobs/admin-jobs.html - 164 + 166 @@ -1318,7 +1318,7 @@ View Stacktrace apps/client/src/app/components/admin-jobs/admin-jobs.html - 171 + 173 @@ -1326,7 +1326,7 @@ Executar Procés apps/client/src/app/components/admin-jobs/admin-jobs.html - 174 + 176 @@ -1334,7 +1334,7 @@ Suprimir Procés apps/client/src/app/components/admin-jobs/admin-jobs.html - 177 + 179 @@ -1372,9 +1372,13 @@ apps/client/src/app/components/admin-market-data-detail/market-data-detail-dialog/market-data-detail-dialog.html 26 + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 104 + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 114 + 98 @@ -1444,6 +1448,10 @@ apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.html 32 + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 21 + apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 65 @@ -1494,7 +1502,7 @@ Filtra per... apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 328 + 329 @@ -1514,7 +1522,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 232 + 216 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -1538,7 +1546,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 241 + 225 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -1550,7 +1558,7 @@ Primera Activitat apps/client/src/app/components/admin-market-data/admin-market-data.html - 104 + 119 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -1558,7 +1566,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 213 + 197 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -1570,7 +1578,7 @@ Nombre d’Activitats apps/client/src/app/components/admin-market-data/admin-market-data.html - 113 + 128 @@ -1578,7 +1586,7 @@ Dades Històriques apps/client/src/app/components/admin-market-data/admin-market-data.html - 122 + 137 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -1590,7 +1598,7 @@ Nombre de Sectors apps/client/src/app/components/admin-market-data/admin-market-data.html - 131 + 146 @@ -1598,7 +1606,7 @@ Nombre de Països apps/client/src/app/components/admin-market-data/admin-market-data.html - 140 + 155 @@ -1606,7 +1614,7 @@ Recopilar Dades Recents apps/client/src/app/components/admin-market-data/admin-market-data.html - 177 + 192 @@ -1614,7 +1622,7 @@ Recopilar Totes les Dades apps/client/src/app/components/admin-market-data/admin-market-data.html - 180 + 195 @@ -1622,7 +1630,7 @@ Recopilar Dades del Perfil apps/client/src/app/components/admin-market-data/admin-market-data.html - 183 + 198 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -1634,7 +1642,7 @@ Eliminar Perfils apps/client/src/app/components/admin-market-data/admin-market-data.html - 190 + 205 @@ -1718,7 +1726,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 258 + 242 @@ -1734,7 +1742,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 268 + 252 @@ -1750,7 +1758,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 274 + 258 apps/client/src/app/pages/public/public-page.html @@ -1770,7 +1778,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 286 + 270 @@ -2082,7 +2090,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 368 + 352 apps/client/src/app/pages/accounts/accounts-page.html @@ -2134,11 +2142,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 393 + 377 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 430 + 414 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -2186,7 +2194,7 @@ Està segur que vol eliminar aquest usuari? apps/client/src/app/components/admin-users/admin-users.component.ts - 125 + 126 @@ -2244,10 +2252,6 @@ apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html 6 - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 91 - libs/ui/src/lib/holdings-table/holdings-table.component.html 142 @@ -2434,47 +2438,27 @@ Oooh! El testimoni de seguretat és incorrecte. apps/client/src/app/components/header/header.component.ts - 246 + 242 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 159 - - - - Change with currency effect - Canvia amb els efectes de la divisa - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 53 + 157 Change Canvia - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 65 - libs/ui/src/lib/holdings-table/holdings-table.component.html 119 - - Performance with currency effect - Rendiment amb els efectes de la divisa - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 81 - - Average Unit Price Preu Mig per Unitat apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 103 + 87 @@ -2482,7 +2466,7 @@ Preu Mínim apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 130 + 114 @@ -2490,7 +2474,7 @@ Preu Màxim apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 146 + 130 @@ -2498,7 +2482,7 @@ Quantitat apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 156 + 140 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -2514,7 +2498,7 @@ Inversió apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 168 + 152 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -2526,11 +2510,11 @@ Dividend apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 181 + 165 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 343 + 319 apps/client/src/app/pages/features/features-page.html @@ -2550,7 +2534,7 @@ Rendiment del Dividend apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 191 + 175 @@ -2558,11 +2542,11 @@ Comissions apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 203 + 187 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 108 + 84 apps/client/src/app/pages/portfolio/fire/fire-page.html @@ -2574,7 +2558,7 @@ Activitat apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 223 + 207 @@ -2582,7 +2566,7 @@ Informar d’un Problema amb les Dades apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 448 + 433 @@ -2889,20 +2873,12 @@ 70 - - Gross Performance - Gross Performance - - apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 85 - - Absolute Net Performance Absolute Net Performance apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 126 + 102 @@ -2910,7 +2886,7 @@ Net Performance apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 141 + 117 @@ -2918,7 +2894,7 @@ Total Assets apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 167 + 143 @@ -2926,7 +2902,7 @@ Valuables apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 180 + 156 @@ -2934,7 +2910,7 @@ Emergency Fund apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 192 + 168 apps/client/src/app/pages/features/features-page.html @@ -2950,7 +2926,7 @@ Cash apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 202 @@ -2958,7 +2934,7 @@ Assets apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 239 + 215 @@ -2966,7 +2942,7 @@ Buying Power apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 252 + 228 @@ -2974,7 +2950,7 @@ Excluded from Analysis apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 264 + 240 @@ -2982,7 +2958,7 @@ Liabilities apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 279 + 255 apps/client/src/app/pages/features/features-page.html @@ -2994,7 +2970,7 @@ Net Worth apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 297 + 273 @@ -3002,7 +2978,7 @@ Annualized Performance apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 309 + 285 @@ -3010,7 +2986,7 @@ Interest apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 331 + 307 @@ -3194,7 +3170,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 250 + 251 @@ -3206,7 +3182,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 253 + 254 @@ -3334,7 +3310,7 @@ Do you really want to close your Ghostfolio account? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 174 + 172 @@ -3342,7 +3318,7 @@ Do you really want to remove this sign in method? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 252 + 246 @@ -3350,7 +3326,7 @@ Oops! There was an error setting up biometric authentication. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 308 + 300 @@ -3546,7 +3522,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 138 + 142 @@ -3566,7 +3542,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 136 + 140 @@ -3578,7 +3554,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 139 + 143 @@ -4690,7 +4666,7 @@ Importing data... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 120 + 124 @@ -4698,7 +4674,7 @@ Import has been completed apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 128 + 132 @@ -4706,7 +4682,7 @@ Validating data... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 234 + 238 @@ -5978,7 +5954,7 @@ Do you really want to delete these activities? libs/ui/src/lib/activities-table/activities-table.component.ts - 225 + 223 @@ -5986,7 +5962,7 @@ Do you really want to delete this activity? libs/ui/src/lib/activities-table/activities-table.component.ts - 235 + 233 @@ -6050,7 +6026,7 @@ years libs/ui/src/lib/assistant/assistant.component.ts - 250 + 251 @@ -6974,7 +6950,7 @@ Deactivate apps/client/src/app/components/rule/rule.component.html - 67 + 72 @@ -6982,7 +6958,7 @@ Activate apps/client/src/app/components/rule/rule.component.html - 69 + 74 @@ -7017,6 +6993,70 @@ 31 + + Copy link to clipboard + Copy link to clipboard + + apps/client/src/app/components/access-table/access-table.component.html + 61 + + + + Portfolio Snapshot + Portfolio Snapshot + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 39 + + + + Change with currency effect Change + Change with currency effect Change + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 50 + + + + Performance with currency effect Performance + Performance with currency effect Performance + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 69 + + + + Threshold Min + Threshold Min + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 5 + + + + Threshold Max + Threshold Max + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 9 + + + + Close + Close + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 15 + + + + Customize + Customize + + apps/client/src/app/components/rule/rule.component.html + 67 + + diff --git a/apps/client/src/locales/messages.de.xlf b/apps/client/src/locales/messages.de.xlf index 7b14fd7ff..745e7fe84 100644 --- a/apps/client/src/locales/messages.de.xlf +++ b/apps/client/src/locales/messages.de.xlf @@ -66,7 +66,7 @@ Widerrufen apps/client/src/app/components/access-table/access-table.component.html - 62 + 65 @@ -74,7 +74,7 @@ Möchtest du diese Zugangsberechtigung wirklich widerrufen? apps/client/src/app/components/access-table/access-table.component.ts - 56 + 68 @@ -82,11 +82,11 @@ Aktivitäten apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 61 + 63 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 90 + 92 apps/client/src/app/components/accounts-table/accounts-table.component.html @@ -106,11 +106,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 225 + 209 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 335 + 319 apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -250,7 +250,7 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html - 215 + 230 apps/client/src/app/components/admin-overview/admin-overview.html @@ -278,7 +278,7 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html - 236 + 251 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -322,7 +322,7 @@ Jobs löschen apps/client/src/app/components/admin-jobs/admin-jobs.html - 149 + 151 @@ -330,7 +330,7 @@ Symbol apps/client/src/app/components/admin-jobs/admin-jobs.html - 44 + 46 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -346,7 +346,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 305 + 289 @@ -354,7 +354,7 @@ Datenquelle apps/client/src/app/components/admin-jobs/admin-jobs.html - 53 + 55 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -374,7 +374,7 @@ Versuche apps/client/src/app/components/admin-jobs/admin-jobs.html - 81 + 83 @@ -382,7 +382,7 @@ Erstellt apps/client/src/app/components/admin-jobs/admin-jobs.html - 90 + 92 @@ -390,7 +390,7 @@ Abgeschlossen apps/client/src/app/components/admin-jobs/admin-jobs.html - 99 + 101 @@ -398,7 +398,7 @@ Status apps/client/src/app/components/admin-jobs/admin-jobs.html - 108 + 110 @@ -422,7 +422,7 @@ Daten anzeigen apps/client/src/app/components/admin-jobs/admin-jobs.html - 164 + 166 @@ -430,7 +430,7 @@ Stacktrace anzeigen apps/client/src/app/components/admin-jobs/admin-jobs.html - 171 + 173 @@ -438,7 +438,7 @@ Job löschen apps/client/src/app/components/admin-jobs/admin-jobs.html - 177 + 179 @@ -476,9 +476,13 @@ apps/client/src/app/components/admin-market-data-detail/market-data-detail-dialog/market-data-detail-dialog.html 26 + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 104 + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 114 + 98 @@ -548,6 +552,10 @@ apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.html 32 + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 21 + apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 65 @@ -566,7 +574,7 @@ Erste Aktivität apps/client/src/app/components/admin-market-data/admin-market-data.html - 104 + 119 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -574,7 +582,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 213 + 197 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -594,7 +602,7 @@ Historische Daten apps/client/src/app/components/admin-market-data/admin-market-data.html - 122 + 137 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -662,7 +670,7 @@ Letzte Daten einholen apps/client/src/app/components/admin-market-data/admin-market-data.html - 177 + 192 @@ -670,7 +678,7 @@ Alle Daten einholen apps/client/src/app/components/admin-market-data/admin-market-data.html - 180 + 195 @@ -678,7 +686,7 @@ Profildaten herunterladen apps/client/src/app/components/admin-market-data/admin-market-data.html - 183 + 198 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -766,7 +774,7 @@ Möchtest du diesen Benutzer wirklich löschen? apps/client/src/app/components/admin-users/admin-users.component.ts - 125 + 126 @@ -854,7 +862,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 368 + 352 apps/client/src/app/pages/accounts/accounts-page.html @@ -1022,7 +1030,7 @@ apps/client/src/app/components/header/header.component.ts - 231 + 227 @@ -1030,11 +1038,11 @@ Ups! Falsches Sicherheits-Token. apps/client/src/app/components/header/header.component.ts - 246 + 242 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 159 + 157 @@ -1170,7 +1178,7 @@ Einlage apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 168 + 152 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -1185,20 +1193,12 @@ 70 - - Gross Performance - Brutto Performance - - apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 85 - - Absolute Net Performance Absolute Netto Performance apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 126 + 102 @@ -1206,7 +1206,7 @@ Netto Performance apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 141 + 117 @@ -1214,7 +1214,7 @@ Gesamtanlagevermögen apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 167 + 143 @@ -1222,7 +1222,7 @@ Wertsachen apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 180 + 156 @@ -1230,7 +1230,7 @@ Notfallfonds apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 192 + 168 apps/client/src/app/pages/features/features-page.html @@ -1246,7 +1246,7 @@ Kaufkraft apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 252 + 228 @@ -1254,7 +1254,7 @@ Gesamtvermögen apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 297 + 273 @@ -1262,7 +1262,7 @@ Performance pro Jahr apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 309 + 285 @@ -1270,11 +1270,11 @@ Dividenden apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 181 + 165 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 343 + 319 apps/client/src/app/pages/features/features-page.html @@ -1310,7 +1310,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 274 + 258 apps/client/src/app/pages/public/public-page.html @@ -1330,7 +1330,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 286 + 270 @@ -1342,11 +1342,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 393 + 377 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 430 + 414 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -1362,7 +1362,7 @@ Datenfehler melden apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 448 + 433 @@ -1384,10 +1384,6 @@ apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html 6 - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 91 - libs/ui/src/lib/holdings-table/holdings-table.component.html 142 @@ -1446,7 +1442,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 250 + 251 @@ -1458,7 +1454,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 253 + 254 @@ -1470,7 +1466,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 139 + 143 @@ -1670,7 +1666,7 @@ Möchtest du diese Anmeldemethode wirklich löschen? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 252 + 246 @@ -1838,7 +1834,7 @@ Bargeld apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 202 @@ -1874,7 +1870,7 @@ Cash-Bestand apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 45 + 47 apps/client/src/app/components/accounts-table/accounts-table.component.html @@ -1890,7 +1886,7 @@ Plattform apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 65 + 67 apps/client/src/app/components/accounts-table/accounts-table.component.html @@ -2178,7 +2174,7 @@ Positionen apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 77 + 79 apps/client/src/app/components/home-holdings/home-holdings.html @@ -2238,7 +2234,7 @@ Anzahl apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 156 + 140 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -2314,7 +2310,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 232 + 216 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -2338,7 +2334,7 @@ Daten importieren... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 120 + 124 @@ -2346,7 +2342,7 @@ Der Import wurde abgeschlossen apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 128 + 132 @@ -2538,7 +2534,7 @@ Möchtest du diese Aktivität wirklich löschen? libs/ui/src/lib/activities-table/activities-table.component.ts - 235 + 233 @@ -2618,7 +2614,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 138 + 142 @@ -2630,16 +2626,12 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 136 + 140 Change Änderung - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 65 - libs/ui/src/lib/holdings-table/holdings-table.component.html 119 @@ -2650,7 +2642,7 @@ Ø Preis pro Einheit apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 103 + 87 @@ -2658,7 +2650,7 @@ Minimum Preis apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 130 + 114 @@ -2666,7 +2658,7 @@ Maximum Preis apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 146 + 130 @@ -2686,7 +2678,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 241 + 225 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -2702,7 +2694,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 258 + 242 @@ -2718,7 +2710,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 268 + 252 @@ -2806,7 +2798,7 @@ Anzahl Länder apps/client/src/app/components/admin-market-data/admin-market-data.html - 140 + 155 @@ -2814,7 +2806,7 @@ Anzahl Sektoren apps/client/src/app/components/admin-market-data/admin-market-data.html - 131 + 146 @@ -2846,7 +2838,7 @@ Filtern nach... apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 328 + 329 @@ -2906,7 +2898,7 @@ Von der Analyse ausgenommen apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 264 + 240 @@ -3254,7 +3246,7 @@ Anzahl Aktivitäten apps/client/src/app/components/admin-market-data/admin-market-data.html - 113 + 128 @@ -3314,7 +3306,7 @@ Daten validieren... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 234 + 238 @@ -3714,11 +3706,11 @@ Gebühren apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 203 + 187 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 108 + 84 apps/client/src/app/pages/portfolio/fire/fire-page.html @@ -3906,7 +3898,7 @@ Möchtest du diese Aktivitäten wirklich löschen? libs/ui/src/lib/activities-table/activities-table.component.ts - 225 + 223 @@ -4030,7 +4022,7 @@ Beteiligungskapital apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 56 + 58 @@ -4178,7 +4170,7 @@ Verbindlichkeiten apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 279 + 255 apps/client/src/app/pages/features/features-page.html @@ -4590,7 +4582,7 @@ Anlagevermögen apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 239 + 215 @@ -5770,7 +5762,7 @@ Zins apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 331 + 307 @@ -6090,7 +6082,7 @@ Cash-Bestände apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 122 + 124 @@ -6378,7 +6370,7 @@ Jahre libs/ui/src/lib/assistant/assistant.component.ts - 250 + 251 @@ -6494,7 +6486,7 @@ Aktivität apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 223 + 207 @@ -6502,7 +6494,7 @@ Dividendenrendite apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 191 + 175 @@ -6510,7 +6502,7 @@ Job ausführen apps/client/src/app/components/admin-jobs/admin-jobs.html - 174 + 176 @@ -6518,7 +6510,7 @@ Priorität apps/client/src/app/components/admin-jobs/admin-jobs.html - 62 + 64 @@ -6537,22 +6529,6 @@ 47 - - Change with currency effect - Änderung mit Währungseffekt - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 53 - - - - Performance with currency effect - Performance mit Währungseffekt - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 81 - - {VAR_PLURAL, plural, =1 {activity} other {activities}} {VAR_PLURAL, plural, =1 {Aktivität} other {Aktivitäten}} @@ -6590,7 +6566,7 @@ Möchtest du dieses Ghostfolio Konto wirklich schliessen? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 174 + 172 @@ -6638,7 +6614,7 @@ Ups! Beim Einrichten der biometrischen Authentifizierung ist ein Fehler aufgetreten. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 308 + 300 @@ -6662,7 +6638,7 @@ Profile löschen apps/client/src/app/components/admin-market-data/admin-market-data.html - 190 + 205 @@ -6974,7 +6950,7 @@ Deaktivieren apps/client/src/app/components/rule/rule.component.html - 67 + 72 @@ -6982,7 +6958,7 @@ Aktivieren apps/client/src/app/components/rule/rule.component.html - 69 + 74 @@ -7017,6 +6993,70 @@ 31 + + Copy link to clipboard + Link in die Zwischenablage kopieren + + apps/client/src/app/components/access-table/access-table.component.html + 61 + + + + Portfolio Snapshot + Portfolio Snapshot + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 39 + + + + Change with currency effect Change + Änderung mit Währungseffekt Change + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 50 + + + + Performance with currency effect Performance + Performance mit Währungseffekt Performance + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 69 + + + + Threshold Min + Threshold Min + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 5 + + + + Threshold Max + Threshold Max + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 9 + + + + Close + Schliessen + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 15 + + + + Customize + Anpassen + + apps/client/src/app/components/rule/rule.component.html + 67 + + diff --git a/apps/client/src/locales/messages.es.xlf b/apps/client/src/locales/messages.es.xlf index 9eea191db..60619a1ea 100644 --- a/apps/client/src/locales/messages.es.xlf +++ b/apps/client/src/locales/messages.es.xlf @@ -67,7 +67,7 @@ Revoca apps/client/src/app/components/access-table/access-table.component.html - 62 + 65 @@ -75,7 +75,7 @@ ¿Quieres revocar el acceso concedido? apps/client/src/app/components/access-table/access-table.component.ts - 56 + 68 @@ -83,11 +83,11 @@ Operaciones apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 61 + 63 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 90 + 92 apps/client/src/app/components/accounts-table/accounts-table.component.html @@ -107,11 +107,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 225 + 209 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 335 + 319 apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -251,7 +251,7 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html - 215 + 230 apps/client/src/app/components/admin-overview/admin-overview.html @@ -279,7 +279,7 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html - 236 + 251 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -323,7 +323,7 @@ Elimina los trabajos apps/client/src/app/components/admin-jobs/admin-jobs.html - 149 + 151 @@ -331,7 +331,7 @@ Símbolo apps/client/src/app/components/admin-jobs/admin-jobs.html - 44 + 46 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -347,7 +347,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 305 + 289 @@ -355,7 +355,7 @@ Fuente de datos apps/client/src/app/components/admin-jobs/admin-jobs.html - 53 + 55 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -375,7 +375,7 @@ Intentos apps/client/src/app/components/admin-jobs/admin-jobs.html - 81 + 83 @@ -383,7 +383,7 @@ Creado apps/client/src/app/components/admin-jobs/admin-jobs.html - 90 + 92 @@ -391,7 +391,7 @@ Finalizado apps/client/src/app/components/admin-jobs/admin-jobs.html - 99 + 101 @@ -399,7 +399,7 @@ Estado apps/client/src/app/components/admin-jobs/admin-jobs.html - 108 + 110 @@ -423,7 +423,7 @@ Visualiza los datos apps/client/src/app/components/admin-jobs/admin-jobs.html - 164 + 166 @@ -431,7 +431,7 @@ Visualiza Stacktrace apps/client/src/app/components/admin-jobs/admin-jobs.html - 171 + 173 @@ -439,7 +439,7 @@ Elimina el trabajo apps/client/src/app/components/admin-jobs/admin-jobs.html - 177 + 179 @@ -477,9 +477,13 @@ apps/client/src/app/components/admin-market-data-detail/market-data-detail-dialog/market-data-detail-dialog.html 26 + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 104 + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 114 + 98 @@ -549,6 +553,10 @@ apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.html 32 + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 21 + apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 65 @@ -567,7 +575,7 @@ Primera actividad apps/client/src/app/components/admin-market-data/admin-market-data.html - 104 + 119 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -575,7 +583,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 213 + 197 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -595,7 +603,7 @@ Datos históricos apps/client/src/app/components/admin-market-data/admin-market-data.html - 122 + 137 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -663,7 +671,7 @@ Recoger datos recientes apps/client/src/app/components/admin-market-data/admin-market-data.html - 177 + 192 @@ -671,7 +679,7 @@ Recoger todos los datos apps/client/src/app/components/admin-market-data/admin-market-data.html - 180 + 195 @@ -679,7 +687,7 @@ Recoger los datos del perfil apps/client/src/app/components/admin-market-data/admin-market-data.html - 183 + 198 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -767,7 +775,7 @@ ¿Estás seguro de eliminar este usuario? apps/client/src/app/components/admin-users/admin-users.component.ts - 125 + 126 @@ -855,7 +863,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 368 + 352 apps/client/src/app/pages/accounts/accounts-page.html @@ -1023,7 +1031,7 @@ apps/client/src/app/components/header/header.component.ts - 231 + 227 @@ -1031,11 +1039,11 @@ Vaya! Token de seguridad incorrecto. apps/client/src/app/components/header/header.component.ts - 246 + 242 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 159 + 157 @@ -1171,7 +1179,7 @@ Inversión apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 168 + 152 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -1186,20 +1194,12 @@ 70 - - Gross Performance - Rendimiento bruto - - apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 85 - - Absolute Net Performance Rendimiento neto absoluto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 126 + 102 @@ -1207,7 +1207,7 @@ Rendimiento neto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 141 + 117 @@ -1215,7 +1215,7 @@ Total de activos apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 167 + 143 @@ -1223,7 +1223,7 @@ Objetos de valor apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 180 + 156 @@ -1231,7 +1231,7 @@ Fondo de emergencia apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 192 + 168 apps/client/src/app/pages/features/features-page.html @@ -1247,7 +1247,7 @@ Capacidad de compra apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 252 + 228 @@ -1255,7 +1255,7 @@ Patrimonio neto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 297 + 273 @@ -1263,7 +1263,7 @@ Rendimiento anualizado apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 309 + 285 @@ -1271,11 +1271,11 @@ Dividendo apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 181 + 165 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 343 + 319 apps/client/src/app/pages/features/features-page.html @@ -1311,7 +1311,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 274 + 258 apps/client/src/app/pages/public/public-page.html @@ -1331,7 +1331,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 286 + 270 @@ -1343,11 +1343,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 393 + 377 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 430 + 414 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -1363,7 +1363,7 @@ Reporta un anomalía de los datos apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 448 + 433 @@ -1385,10 +1385,6 @@ apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html 6 - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 91 - libs/ui/src/lib/holdings-table/holdings-table.component.html 142 @@ -1447,7 +1443,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 250 + 251 @@ -1459,7 +1455,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 253 + 254 @@ -1471,7 +1467,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 139 + 143 @@ -1671,7 +1667,7 @@ ¿Estás seguro de eliminar este método de acceso? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 252 + 246 @@ -1839,7 +1835,7 @@ Efectivo apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 202 @@ -1875,7 +1871,7 @@ Saldo en efectivo apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 45 + 47 apps/client/src/app/components/accounts-table/accounts-table.component.html @@ -1891,7 +1887,7 @@ Plataforma apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 65 + 67 apps/client/src/app/components/accounts-table/accounts-table.component.html @@ -2179,7 +2175,7 @@ Participaciones apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 77 + 79 apps/client/src/app/components/home-holdings/home-holdings.html @@ -2239,7 +2235,7 @@ Cantidad apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 156 + 140 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -2315,7 +2311,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 232 + 216 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -2339,7 +2335,7 @@ Importando datos... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 120 + 124 @@ -2347,7 +2343,7 @@ La importación se ha completado apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 128 + 132 @@ -2539,7 +2535,7 @@ ¿Estás seguro de eliminar esta operación? libs/ui/src/lib/activities-table/activities-table.component.ts - 235 + 233 @@ -2615,7 +2611,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 136 + 140 @@ -2631,16 +2627,12 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 138 + 142 Change Modificar - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 65 - libs/ui/src/lib/holdings-table/holdings-table.component.html 119 @@ -2675,7 +2667,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 241 + 225 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -2687,7 +2679,7 @@ Precio unitario medio apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 103 + 87 @@ -2695,7 +2687,7 @@ Precio máximo apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 146 + 130 @@ -2731,7 +2723,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 258 + 242 @@ -2747,7 +2739,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 268 + 252 @@ -2755,7 +2747,7 @@ Precio mínimo apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 130 + 114 @@ -2807,7 +2799,7 @@ Número de sectores apps/client/src/app/components/admin-market-data/admin-market-data.html - 131 + 146 @@ -2815,7 +2807,7 @@ Número de países apps/client/src/app/components/admin-market-data/admin-market-data.html - 140 + 155 @@ -2847,7 +2839,7 @@ Filtrar por... apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 328 + 329 @@ -2907,7 +2899,7 @@ Excluido del análisis apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 264 + 240 @@ -3255,7 +3247,7 @@ Recuento de actividades apps/client/src/app/components/admin-market-data/admin-market-data.html - 113 + 128 @@ -3315,7 +3307,7 @@ Validando datos... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 234 + 238 @@ -3715,11 +3707,11 @@ Comisiones apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 203 + 187 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 108 + 84 apps/client/src/app/pages/portfolio/fire/fire-page.html @@ -3907,7 +3899,7 @@ Do you really want to delete these activities? libs/ui/src/lib/activities-table/activities-table.component.ts - 225 + 223 @@ -4031,7 +4023,7 @@ Equity apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 56 + 58 @@ -4179,7 +4171,7 @@ Liabilities apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 279 + 255 apps/client/src/app/pages/features/features-page.html @@ -4591,7 +4583,7 @@ Assets apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 239 + 215 @@ -5771,7 +5763,7 @@ Interest apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 331 + 307 @@ -6091,7 +6083,7 @@ Cash Balances apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 122 + 124 @@ -6379,7 +6371,7 @@ años libs/ui/src/lib/assistant/assistant.component.ts - 250 + 251 @@ -6495,7 +6487,7 @@ Activity apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 223 + 207 @@ -6503,7 +6495,7 @@ Dividend Yield apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 191 + 175 @@ -6511,7 +6503,7 @@ Ejecutar Tarea apps/client/src/app/components/admin-jobs/admin-jobs.html - 174 + 176 @@ -6519,7 +6511,7 @@ Prioridad apps/client/src/app/components/admin-jobs/admin-jobs.html - 62 + 64 @@ -6538,22 +6530,6 @@ 47 - - Change with currency effect - Change with currency effect - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 53 - - - - Performance with currency effect - Performance with currency effect - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 81 - - {VAR_PLURAL, plural, =1 {activity} other {activities}} {VAR_PLURAL, plural, =1 {activity} other {activities}} @@ -6591,7 +6567,7 @@ ¿Estás seguro de querer borrar tu cuenta de Ghostfolio? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 174 + 172 @@ -6639,7 +6615,7 @@ Oops! There was an error setting up biometric authentication. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 308 + 300 @@ -6663,7 +6639,7 @@ Borrar Perfiles apps/client/src/app/components/admin-market-data/admin-market-data.html - 190 + 205 @@ -6975,7 +6951,7 @@ Deactivate apps/client/src/app/components/rule/rule.component.html - 67 + 72 @@ -6983,7 +6959,7 @@ Activate apps/client/src/app/components/rule/rule.component.html - 69 + 74 @@ -7018,6 +6994,70 @@ 31 + + Copy link to clipboard + Copy link to clipboard + + apps/client/src/app/components/access-table/access-table.component.html + 61 + + + + Portfolio Snapshot + Portfolio Snapshot + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 39 + + + + Change with currency effect Change + Change with currency effect Change + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 50 + + + + Performance with currency effect Performance + Performance with currency effect Performance + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 69 + + + + Threshold Min + Threshold Min + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 5 + + + + Threshold Max + Threshold Max + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 9 + + + + Close + Close + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 15 + + + + Customize + Customize + + apps/client/src/app/components/rule/rule.component.html + 67 + + diff --git a/apps/client/src/locales/messages.fr.xlf b/apps/client/src/locales/messages.fr.xlf index ed2e892e8..047e9845b 100644 --- a/apps/client/src/locales/messages.fr.xlf +++ b/apps/client/src/locales/messages.fr.xlf @@ -62,7 +62,7 @@ Révoquer apps/client/src/app/components/access-table/access-table.component.html - 62 + 65 @@ -70,7 +70,7 @@ Voulez-vous vraiment révoquer cet accès ? apps/client/src/app/components/access-table/access-table.component.ts - 56 + 68 @@ -78,7 +78,7 @@ Plateforme apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 65 + 67 apps/client/src/app/components/accounts-table/accounts-table.component.html @@ -94,11 +94,11 @@ Activités apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 61 + 63 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 90 + 92 apps/client/src/app/components/accounts-table/accounts-table.component.html @@ -118,11 +118,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 225 + 209 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 335 + 319 apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -222,7 +222,7 @@ Balance Cash apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 45 + 47 apps/client/src/app/components/accounts-table/accounts-table.component.html @@ -306,7 +306,7 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html - 215 + 230 apps/client/src/app/components/admin-overview/admin-overview.html @@ -334,7 +334,7 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html - 236 + 251 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -378,7 +378,7 @@ Symbole apps/client/src/app/components/admin-jobs/admin-jobs.html - 44 + 46 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -394,7 +394,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 305 + 289 @@ -402,7 +402,7 @@ Source Données apps/client/src/app/components/admin-jobs/admin-jobs.html - 53 + 55 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -422,7 +422,7 @@ Tentatives apps/client/src/app/components/admin-jobs/admin-jobs.html - 81 + 83 @@ -430,7 +430,7 @@ Créé apps/client/src/app/components/admin-jobs/admin-jobs.html - 90 + 92 @@ -438,7 +438,7 @@ Terminé apps/client/src/app/components/admin-jobs/admin-jobs.html - 99 + 101 @@ -446,7 +446,7 @@ Statut apps/client/src/app/components/admin-jobs/admin-jobs.html - 108 + 110 @@ -454,7 +454,7 @@ Supprimer Tâches apps/client/src/app/components/admin-jobs/admin-jobs.html - 149 + 151 @@ -478,7 +478,7 @@ Voir Données apps/client/src/app/components/admin-jobs/admin-jobs.html - 164 + 166 @@ -486,7 +486,7 @@ Voir la Stacktrace apps/client/src/app/components/admin-jobs/admin-jobs.html - 171 + 173 @@ -494,7 +494,7 @@ Supprimer Tâche apps/client/src/app/components/admin-jobs/admin-jobs.html - 177 + 179 @@ -532,9 +532,13 @@ apps/client/src/app/components/admin-market-data-detail/market-data-detail-dialog/market-data-detail-dialog.html 26 + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 104 + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 114 + 98 @@ -604,6 +608,10 @@ apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.html 32 + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 21 + apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 65 @@ -622,7 +630,7 @@ Filtrer par... apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 328 + 329 @@ -642,7 +650,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 232 + 216 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -666,7 +674,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 241 + 225 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -678,7 +686,7 @@ Première Activité apps/client/src/app/components/admin-market-data/admin-market-data.html - 104 + 119 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -686,7 +694,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 213 + 197 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -698,7 +706,7 @@ Nombre d’Activités apps/client/src/app/components/admin-market-data/admin-market-data.html - 113 + 128 @@ -706,7 +714,7 @@ Données Historiques apps/client/src/app/components/admin-market-data/admin-market-data.html - 122 + 137 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -718,7 +726,7 @@ Nombre de Secteurs apps/client/src/app/components/admin-market-data/admin-market-data.html - 131 + 146 @@ -726,7 +734,7 @@ Nombre de Pays apps/client/src/app/components/admin-market-data/admin-market-data.html - 140 + 155 @@ -734,7 +742,7 @@ Obtenir les Données Récentes apps/client/src/app/components/admin-market-data/admin-market-data.html - 177 + 192 @@ -742,7 +750,7 @@ Obtenir toutes les Données apps/client/src/app/components/admin-market-data/admin-market-data.html - 180 + 195 @@ -750,7 +758,7 @@ Obtenir les Données du Profil apps/client/src/app/components/admin-market-data/admin-market-data.html - 183 + 198 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -774,7 +782,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 258 + 242 @@ -790,7 +798,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 268 + 252 @@ -806,7 +814,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 274 + 258 apps/client/src/app/pages/public/public-page.html @@ -826,7 +834,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 286 + 270 @@ -942,11 +950,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 393 + 377 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 430 + 414 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -1030,7 +1038,7 @@ Voulez-vous vraiment supprimer cet·te utilisateur·rice ? apps/client/src/app/components/admin-users/admin-users.component.ts - 125 + 126 @@ -1070,7 +1078,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 368 + 352 apps/client/src/app/pages/accounts/accounts-page.html @@ -1104,10 +1112,6 @@ apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html 6 - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 91 - libs/ui/src/lib/holdings-table/holdings-table.component.html 142 @@ -1342,7 +1346,7 @@ apps/client/src/app/components/header/header.component.ts - 231 + 227 @@ -1350,11 +1354,11 @@ Oups! Jeton de Sécurité Incorrect. apps/client/src/app/components/header/header.component.ts - 246 + 242 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 159 + 157 @@ -1518,7 +1522,7 @@ Investissement apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 168 + 152 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -1533,20 +1537,12 @@ 70 - - Gross Performance - Performance Brute - - apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 85 - - Absolute Net Performance Performance Absolue Nette apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 126 + 102 @@ -1554,7 +1550,7 @@ Performance nette apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 141 + 117 @@ -1562,7 +1558,7 @@ Actifs Totaux apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 167 + 143 @@ -1570,7 +1566,7 @@ Biens apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 180 + 156 @@ -1578,7 +1574,7 @@ Fonds d’Urgence apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 192 + 168 apps/client/src/app/pages/features/features-page.html @@ -1594,7 +1590,7 @@ Pouvoir d’Achat apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 252 + 228 @@ -1602,7 +1598,7 @@ Exclus de l’Analyse apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 264 + 240 @@ -1610,7 +1606,7 @@ Fortune apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 297 + 273 @@ -1618,7 +1614,7 @@ Performance annualisée apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 309 + 285 @@ -1626,11 +1622,11 @@ Dividende apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 181 + 165 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 343 + 319 apps/client/src/app/pages/features/features-page.html @@ -1656,10 +1652,6 @@ Change Différence - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 65 - libs/ui/src/lib/holdings-table/holdings-table.component.html 119 @@ -1670,7 +1662,7 @@ Prix Unitaire Moyen apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 103 + 87 @@ -1678,7 +1670,7 @@ Prix Minimum apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 130 + 114 @@ -1686,7 +1678,7 @@ Prix Maximum apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 146 + 130 @@ -1694,7 +1686,7 @@ Quantité apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 156 + 140 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -1710,7 +1702,7 @@ Signaler une Erreur de Données apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 448 + 433 @@ -1758,7 +1750,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 250 + 251 @@ -1770,7 +1762,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 253 + 254 @@ -1794,7 +1786,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 138 + 142 @@ -1806,7 +1798,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 136 + 140 @@ -1818,7 +1810,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 139 + 143 @@ -1938,7 +1930,7 @@ Voulez-vous vraiment supprimer cette méthode de connexion ? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 252 + 246 @@ -2202,7 +2194,7 @@ Cash apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 202 @@ -2506,7 +2498,7 @@ Import des données... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 120 + 124 @@ -2514,7 +2506,7 @@ L’import est terminé apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 128 + 132 @@ -2522,7 +2514,7 @@ Validation des données... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 234 + 238 @@ -2818,7 +2810,7 @@ Positions apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 77 + 79 apps/client/src/app/components/home-holdings/home-holdings.html @@ -3062,7 +3054,7 @@ Voulez-vous vraiment supprimer cette activité ? libs/ui/src/lib/activities-table/activities-table.component.ts - 235 + 233 @@ -3714,11 +3706,11 @@ Frais apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 203 + 187 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 108 + 84 apps/client/src/app/pages/portfolio/fire/fire-page.html @@ -3906,7 +3898,7 @@ Voulez-vous vraiment supprimer toutes vos activités ? libs/ui/src/lib/activities-table/activities-table.component.ts - 225 + 223 @@ -4030,7 +4022,7 @@ Capital apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 56 + 58 @@ -4178,7 +4170,7 @@ Dettes apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 279 + 255 apps/client/src/app/pages/features/features-page.html @@ -4331,7 +4323,7 @@ Add Asset Profile - Ajouter un Profil d'Actif + Ajouter un Profil d'Actif apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html 7 @@ -4590,7 +4582,7 @@ Actifs apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 239 + 215 @@ -4723,7 +4715,7 @@ At Ghostfolio, transparency is at the core of our values. We publish the source code as open source software (OSS) under the AGPL-3.0 license and we openly share aggregated key metrics of the platform’s operational status. - Chez Ghostfolio, la transparence est le centre de notre attention. Nous publions le code source sous open source software (OSS) sous la licence AGPL-3.0 et nous partageons ouvertement les indicateurs clés agrégés sur l'état opérationnel de la plateforme. + Chez Ghostfolio, la transparence est le centre de notre attention. Nous publions le code source sous open source software (OSS) sous la licence AGPL-3.0 et nous partageons ouvertement les indicateurs clés agrégés sur l'état opérationnel de la plateforme. apps/client/src/app/pages/open/open-page.html 6 @@ -4791,7 +4783,7 @@ Uptime - Temps d'activité des serveurs + Temps d'activité des serveurs apps/client/src/app/pages/open/open-page.html 132 @@ -4831,7 +4823,7 @@ Discover other exciting Open Source Software projects - Découvrez d'autres projets passionnants de logiciels Open Source + Découvrez d'autres projets passionnants de logiciels Open Source apps/client/src/app/pages/about/oss-friends/oss-friends-page.html 9 @@ -4887,7 +4879,7 @@ Ghostfolio is a privacy-first, open source dashboard for your personal finances. Break down your asset allocation, know your net worth and make solid, data-driven investment decisions. - Ghostfolio est un tableau de bord open-source axé sur la confidentialité pour votre Gestion de Patrimoine. Décomposez votre répartition d'actifs, connaissez votre valeur nette et prenez des décisions d'investissement solides et basées sur des données. + Ghostfolio est un tableau de bord open-source axé sur la confidentialité pour votre Gestion de Patrimoine. Décomposez votre répartition d'actifs, connaissez votre valeur nette et prenez des décisions d'investissement solides et basées sur des données. apps/client/src/app/pages/landing/landing-page.html 9 @@ -4923,7 +4915,7 @@ Protect your assets. Refine your personal investment strategy. - Protégez vos actifs. Affinez votre stratégie d'investissement personnelle.. + Protégez vos actifs. Affinez votre stratégie d'investissement personnelle.. apps/client/src/app/pages/landing/landing-page.html 225 @@ -4971,7 +4963,7 @@ Benefit from continuous improvements through a strong community. - Bénéficiez d'améliorations continues grâce à une communauté impliquée. + Bénéficiez d'améliorations continues grâce à une communauté impliquée. apps/client/src/app/pages/landing/landing-page.html 263 @@ -5011,7 +5003,7 @@ interested in getting insights of your portfolio composition - êtes intéressés d'avoir un aperçu de la composition de votre portefeuille + êtes intéressés d'avoir un aperçu de la composition de votre portefeuille apps/client/src/app/pages/landing/landing-page.html 291 @@ -5043,7 +5035,7 @@ interested in financial independence - êtes intéressés d'atteindre l'indépendance financière + êtes intéressés d'atteindre l'indépendance financière apps/client/src/app/pages/landing/landing-page.html 307 @@ -5075,7 +5067,7 @@ What our users are saying - Qu'en pensent nos utilisateurs + Qu'en pensent nos utilisateurs apps/client/src/app/pages/landing/landing-page.html 327 @@ -5115,7 +5107,7 @@ Add any of your historical transactions - Ajoutez l'une de vos transactions historiques + Ajoutez l'une de vos transactions historiques apps/client/src/app/pages/landing/landing-page.html 405 @@ -5151,7 +5143,7 @@ Get the full picture of your personal finances across multiple platforms. - Obtenez une vue d'ensemble de vos finances personnelles sur plusieurs plateformes. + Obtenez une vue d'ensemble de vos finances personnelles sur plusieurs plateformes. apps/client/src/app/pages/landing/landing-page.html 242 @@ -5567,7 +5559,7 @@ This overview page features a curated collection of personal finance tools compared to the open source alternative Ghostfolio. If you value transparency, data privacy, and community collaboration, Ghostfolio provides an excellent opportunity to take control of your financial management. - Cette page d'aperçu présente une collection d'outils de finances personnelles comparés à la solution open source alternative Ghostfolio. Si vous accordez de l'importance à la transparence, à la confidentialité des données et à la collaboration communautaire, Ghostfolio vous offre une excellente occasion de prendre le contrôle de votre gestion financière. + Cette page d'aperçu présente une collection d'outils de finances personnelles comparés à la solution open source alternative Ghostfolio. Si vous accordez de l'importance à la transparence, à la confidentialité des données et à la collaboration communautaire, Ghostfolio vous offre une excellente occasion de prendre le contrôle de votre gestion financière. apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.html 8 @@ -5575,7 +5567,7 @@ Explore the links below to compare a variety of personal finance tools with Ghostfolio. - Explorez les liens ci-dessous pour comparer une variété d'outils de finances personnelles avec Ghostfolio. + Explorez les liens ci-dessous pour comparer une variété d'outils de finances personnelles avec Ghostfolio. apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.html 16 @@ -5615,7 +5607,7 @@ Ghostfolio is an open source software (OSS), providing a cost-effective alternative to making it particularly suitable for individuals on a tight budget, such as those pursuing Financial Independence, Retire Early (FIRE). By leveraging the collective efforts of a community of developers and personal finance enthusiasts, Ghostfolio continuously enhances its capabilities, security, and user experience. - Ghostfolio est un logiciel open source (OSS), offrant une alternative économique, le rendant particulièrement adaptée aux personnes disposant d'un budget serré, telles que celles qui cherchent à atteindre le mouvement Financial Independence, Retire Early (FIRE). En s'appuyant sur les efforts collectifs d'une communauté de développeurs et de passionnés de finances personnelles, Ghostfolio améliore continuellement ses fonctionnalités, sa sécurité et son expérience utilisateur. + Ghostfolio est un logiciel open source (OSS), offrant une alternative économique, le rendant particulièrement adaptée aux personnes disposant d'un budget serré, telles que celles qui cherchent à atteindre le mouvement Financial Independence, Retire Early (FIRE). En s'appuyant sur les efforts collectifs d'une communauté de développeurs et de passionnés de finances personnelles, Ghostfolio améliore continuellement ses fonctionnalités, sa sécurité et son expérience utilisateur. apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 27 @@ -5643,7 +5635,7 @@ Please note that the information provided in the Ghostfolio vs comparison table is based on our independent research and analysis. This website is not affiliated with or any other product mentioned in the comparison. As the landscape of personal finance tools evolves, it is essential to verify any specific details or changes directly from the respective product page. Data needs a refresh? Help us maintain accurate data on GitHub. - Veuillez noter que les informations fournies dans le Ghostfolio vs via la table de comparaison se basent de nos recherches et analyses indépendantes. Ce site n'est pas affilié à ou tout autre produit mentionné dans la comparaison. Le paysage des outils de finances personnelles évoluant, il est essentiel de vérifier tout détail ou changement spécifique directement sur la page du produit concerné. Certaines données doivent être mises à jour ? Aidez-nous à maintenir les données exactes sur GitHub. + Veuillez noter que les informations fournies dans le Ghostfolio vs via la table de comparaison se basent de nos recherches et analyses indépendantes. Ce site n'est pas affilié à ou tout autre produit mentionné dans la comparaison. Le paysage des outils de finances personnelles évoluant, il est essentiel de vérifier tout détail ou changement spécifique directement sur la page du produit concerné. Certaines données doivent être mises à jour ? Aidez-nous à maintenir les données exactes sur GitHub. apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 226 @@ -5770,12 +5762,12 @@ Intérêts apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 331 + 307 Revenue for lending out money - Revenue lié au prêt d'argent + Revenue lié au prêt d'argent apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html 49 @@ -5815,7 +5807,7 @@ Ghostfolio X-ray uses static analysis to identify potential issues and risks in your portfolio. - Ghostfolio X-ray utilise l'analyse statique pour identifier de potentiels problèmes et risques dans votre portefeuille. + Ghostfolio X-ray utilise l'analyse statique pour identifier de potentiels problèmes et risques dans votre portefeuille. apps/client/src/app/pages/portfolio/fire/fire-page.html 111 @@ -5931,7 +5923,7 @@ No entries... - Pas d'entrées ... + Pas d'entrées ... libs/ui/src/lib/assistant/assistant.html 63 @@ -5943,7 +5935,7 @@ Asset Profile - Profil d'Actif + Profil d'Actif apps/client/src/app/components/admin-jobs/admin-jobs.html 35 @@ -5951,7 +5943,7 @@ Do you really want to delete this asset profile? - Confirmez la suppressoion de ce profil d'actif? + Confirmez la suppressoion de ce profil d'actif? apps/client/src/app/components/admin-market-data/admin-market-data.service.ts 33 @@ -6090,7 +6082,7 @@ Cash Balances apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 122 + 124 @@ -6191,7 +6183,7 @@ Oops! Could not grant access. - Oops! Impossible d'accorder l'accès. + Oops! Impossible d'accorder l'accès. apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts 91 @@ -6207,7 +6199,7 @@ Job Queue - File d'attente + File d'attente apps/client/src/app/pages/admin/admin-page-routing.module.ts 25 @@ -6351,7 +6343,7 @@ If you retire today, you would be able to withdraw per year or per month, based on your total assets of and a withdrawal rate of 4%. - Si vous prenez votre retraite aujourd'hui, vous pourrez retirer par an ou par mois, sur la base de vos actifs totaux de et un taux de retrait de 4 %. + Si vous prenez votre retraite aujourd'hui, vous pourrez retirer par an ou par mois, sur la base de vos actifs totaux de et un taux de retrait de 4 %. apps/client/src/app/pages/portfolio/fire/fire-page.html 67 @@ -6378,12 +6370,12 @@ années libs/ui/src/lib/assistant/assistant.component.ts - 250 + 251 Asset Classes - Types d'Actifs + Types d'Actifs libs/ui/src/lib/assistant/assistant.html 138 @@ -6494,7 +6486,7 @@ Activitées apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 223 + 207 @@ -6502,7 +6494,7 @@ Rendement en Dividende apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 191 + 175 @@ -6510,7 +6502,7 @@ Execute la tâche apps/client/src/app/components/admin-jobs/admin-jobs.html - 174 + 176 @@ -6518,12 +6510,12 @@ Priorité apps/client/src/app/components/admin-jobs/admin-jobs.html - 62 + 64 This action is not allowed. - Cette action n'est pas autorisée. + Cette action n'est pas autorisée. apps/client/src/app/core/http-response.interceptor.ts 61 @@ -6537,22 +6529,6 @@ 47 - - Change with currency effect - Variation avec impact des devises - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 53 - - - - Performance with currency effect - Performance avec impact des devises - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 81 - - {VAR_PLURAL, plural, =1 {activity} other {activities}} {VAR_PLURAL, plural, =1 {activity} autres {activities}} @@ -6590,7 +6566,7 @@ Confirmer la suppresion de votre compte Ghostfolio ? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 174 + 172 @@ -6635,10 +6611,10 @@ Oops! There was an error setting up biometric authentication. - Oops! Une erreur s'est produite lors de la configuration de l'authentification biométrique. + Oops! Une erreur s'est produite lors de la configuration de l'authentification biométrique. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 308 + 300 @@ -6662,7 +6638,7 @@ Supprimer des Profils apps/client/src/app/components/admin-market-data/admin-market-data.html - 190 + 205 @@ -6699,7 +6675,7 @@ Would you like to refine your personal investment strategy? - Souhaitez-vous affiner votre stratégie d'investissement personnelle? + Souhaitez-vous affiner votre stratégie d'investissement personnelle? apps/client/src/app/pages/public/public-page.html 155 @@ -6974,7 +6950,7 @@ Désactiver apps/client/src/app/components/rule/rule.component.html - 67 + 72 @@ -6982,7 +6958,7 @@ Activer apps/client/src/app/components/rule/rule.component.html - 69 + 74 @@ -7017,6 +6993,70 @@ 31 + + Copy link to clipboard + Copy link to clipboard + + apps/client/src/app/components/access-table/access-table.component.html + 61 + + + + Portfolio Snapshot + Portfolio Snapshot + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 39 + + + + Change with currency effect Change + Change with currency effect Change + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 50 + + + + Performance with currency effect Performance + Performance with currency effect Performance + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 69 + + + + Threshold Min + Threshold Min + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 5 + + + + Threshold Max + Threshold Max + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 9 + + + + Close + Close + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 15 + + + + Customize + Customize + + apps/client/src/app/components/rule/rule.component.html + 67 + + diff --git a/apps/client/src/locales/messages.it.xlf b/apps/client/src/locales/messages.it.xlf index 592df3152..a7b92ec50 100644 --- a/apps/client/src/locales/messages.it.xlf +++ b/apps/client/src/locales/messages.it.xlf @@ -67,7 +67,7 @@ Revoca apps/client/src/app/components/access-table/access-table.component.html - 62 + 65 @@ -75,7 +75,7 @@ Vuoi davvero revocare l’accesso concesso? apps/client/src/app/components/access-table/access-table.component.ts - 56 + 68 @@ -83,11 +83,11 @@ Attività apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 61 + 63 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 90 + 92 apps/client/src/app/components/accounts-table/accounts-table.component.html @@ -107,11 +107,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 225 + 209 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 335 + 319 apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -251,7 +251,7 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html - 215 + 230 apps/client/src/app/components/admin-overview/admin-overview.html @@ -279,7 +279,7 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html - 236 + 251 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -323,7 +323,7 @@ Elimina i lavori apps/client/src/app/components/admin-jobs/admin-jobs.html - 149 + 151 @@ -331,7 +331,7 @@ Simbolo apps/client/src/app/components/admin-jobs/admin-jobs.html - 44 + 46 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -347,7 +347,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 305 + 289 @@ -355,7 +355,7 @@ Sorgente dei dati apps/client/src/app/components/admin-jobs/admin-jobs.html - 53 + 55 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -375,7 +375,7 @@ Tentativi apps/client/src/app/components/admin-jobs/admin-jobs.html - 81 + 83 @@ -383,7 +383,7 @@ Creato apps/client/src/app/components/admin-jobs/admin-jobs.html - 90 + 92 @@ -391,7 +391,7 @@ Finito apps/client/src/app/components/admin-jobs/admin-jobs.html - 99 + 101 @@ -399,7 +399,7 @@ Stato apps/client/src/app/components/admin-jobs/admin-jobs.html - 108 + 110 @@ -423,7 +423,7 @@ Visualizza i dati apps/client/src/app/components/admin-jobs/admin-jobs.html - 164 + 166 @@ -431,7 +431,7 @@ Visualizza Stacktrace apps/client/src/app/components/admin-jobs/admin-jobs.html - 171 + 173 @@ -439,7 +439,7 @@ Elimina il lavoro apps/client/src/app/components/admin-jobs/admin-jobs.html - 177 + 179 @@ -477,9 +477,13 @@ apps/client/src/app/components/admin-market-data-detail/market-data-detail-dialog/market-data-detail-dialog.html 26 + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 104 + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 114 + 98 @@ -549,6 +553,10 @@ apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.html 32 + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 21 + apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 65 @@ -567,7 +575,7 @@ Prima attività apps/client/src/app/components/admin-market-data/admin-market-data.html - 104 + 119 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -575,7 +583,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 213 + 197 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -595,7 +603,7 @@ Dati storici apps/client/src/app/components/admin-market-data/admin-market-data.html - 122 + 137 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -663,7 +671,7 @@ Raccogli dati recenti apps/client/src/app/components/admin-market-data/admin-market-data.html - 177 + 192 @@ -671,7 +679,7 @@ Raccogli tutti i dati apps/client/src/app/components/admin-market-data/admin-market-data.html - 180 + 195 @@ -679,7 +687,7 @@ Raccogli i dati del profilo apps/client/src/app/components/admin-market-data/admin-market-data.html - 183 + 198 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -767,7 +775,7 @@ Vuoi davvero eliminare questo utente? apps/client/src/app/components/admin-users/admin-users.component.ts - 125 + 126 @@ -855,7 +863,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 368 + 352 apps/client/src/app/pages/accounts/accounts-page.html @@ -1023,7 +1031,7 @@ apps/client/src/app/components/header/header.component.ts - 231 + 227 @@ -1031,11 +1039,11 @@ Ops! Token di sicurezza errato. apps/client/src/app/components/header/header.component.ts - 246 + 242 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 159 + 157 @@ -1171,7 +1179,7 @@ Investimento apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 168 + 152 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -1186,20 +1194,12 @@ 70 - - Gross Performance - Prestazioni lorde - - apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 85 - - Absolute Net Performance Prestazioni nette assolute apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 126 + 102 @@ -1207,7 +1207,7 @@ Prestazioni nette apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 141 + 117 @@ -1215,7 +1215,7 @@ Asset totali apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 167 + 143 @@ -1223,7 +1223,7 @@ Oggetti di valore apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 180 + 156 @@ -1231,7 +1231,7 @@ Fondo di emergenza apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 192 + 168 apps/client/src/app/pages/features/features-page.html @@ -1247,7 +1247,7 @@ Potere d’acquisto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 252 + 228 @@ -1255,7 +1255,7 @@ Patrimonio netto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 297 + 273 @@ -1263,7 +1263,7 @@ Prestazioni annualizzate apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 309 + 285 @@ -1271,11 +1271,11 @@ Dividendo apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 181 + 165 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 343 + 319 apps/client/src/app/pages/features/features-page.html @@ -1311,7 +1311,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 274 + 258 apps/client/src/app/pages/public/public-page.html @@ -1331,7 +1331,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 286 + 270 @@ -1343,11 +1343,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 393 + 377 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 430 + 414 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -1363,7 +1363,7 @@ Segnala un’anomalia dei dati apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 448 + 433 @@ -1385,10 +1385,6 @@ apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html 6 - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 91 - libs/ui/src/lib/holdings-table/holdings-table.component.html 142 @@ -1447,7 +1443,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 250 + 251 @@ -1459,7 +1455,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 253 + 254 @@ -1471,7 +1467,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 139 + 143 @@ -1671,7 +1667,7 @@ Vuoi davvero rimuovere questo metodo di accesso? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 252 + 246 @@ -1839,7 +1835,7 @@ Contanti apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 202 @@ -1875,7 +1871,7 @@ Saldo di cassa apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 45 + 47 apps/client/src/app/components/accounts-table/accounts-table.component.html @@ -1891,7 +1887,7 @@ Piattaforma apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 65 + 67 apps/client/src/app/components/accounts-table/accounts-table.component.html @@ -2179,7 +2175,7 @@ Partecipazioni apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 77 + 79 apps/client/src/app/components/home-holdings/home-holdings.html @@ -2239,7 +2235,7 @@ Quantità apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 156 + 140 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -2315,7 +2311,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 232 + 216 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -2339,7 +2335,7 @@ Importazione dei dati... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 120 + 124 @@ -2347,7 +2343,7 @@ L’importazione è stata completata apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 128 + 132 @@ -2539,7 +2535,7 @@ Vuoi davvero eliminare questa attività? libs/ui/src/lib/activities-table/activities-table.component.ts - 235 + 233 @@ -2615,7 +2611,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 136 + 140 @@ -2631,16 +2627,12 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 138 + 142 Change Modifica - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 65 - libs/ui/src/lib/holdings-table/holdings-table.component.html 119 @@ -2675,7 +2667,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 241 + 225 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -2687,7 +2679,7 @@ Prezzo unitario medio apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 103 + 87 @@ -2695,7 +2687,7 @@ Prezzo massimo apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 146 + 130 @@ -2731,7 +2723,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 258 + 242 @@ -2747,7 +2739,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 268 + 252 @@ -2755,7 +2747,7 @@ Prezzo minimo apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 130 + 114 @@ -2807,7 +2799,7 @@ Numero di settori apps/client/src/app/components/admin-market-data/admin-market-data.html - 131 + 146 @@ -2815,7 +2807,7 @@ Numero di paesi apps/client/src/app/components/admin-market-data/admin-market-data.html - 140 + 155 @@ -2847,7 +2839,7 @@ Filtra per... apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 328 + 329 @@ -2907,7 +2899,7 @@ Escluso dall’analisi apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 264 + 240 @@ -3255,7 +3247,7 @@ Conteggio attività apps/client/src/app/components/admin-market-data/admin-market-data.html - 113 + 128 @@ -3315,7 +3307,7 @@ Convalida dei dati... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 234 + 238 @@ -3715,11 +3707,11 @@ Commissioni apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 203 + 187 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 108 + 84 apps/client/src/app/pages/portfolio/fire/fire-page.html @@ -3907,7 +3899,7 @@ Vuoi davvero eliminare tutte le tue attività? libs/ui/src/lib/activities-table/activities-table.component.ts - 225 + 223 @@ -4031,7 +4023,7 @@ Azione ordinaria apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 56 + 58 @@ -4179,7 +4171,7 @@ Passività apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 279 + 255 apps/client/src/app/pages/features/features-page.html @@ -4591,7 +4583,7 @@ Asset apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 239 + 215 @@ -5736,7 +5728,7 @@ One-time fee, annual account fees - Commissione una tantum, commissioni annuali per l'account + Commissione una tantum, commissioni annuali per l'account apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html 33 @@ -5771,7 +5763,7 @@ Interesse apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 331 + 307 @@ -5816,7 +5808,7 @@ Ghostfolio X-ray uses static analysis to identify potential issues and risks in your portfolio. - Ghostfolio X-ray usa l'analisi statica per identificare potenziali problemi e rischi del tuo portafoglio. + Ghostfolio X-ray usa l'analisi statica per identificare potenziali problemi e rischi del tuo portafoglio. apps/client/src/app/pages/portfolio/fire/fire-page.html 111 @@ -5944,7 +5936,7 @@ Asset Profile - Profilo dell'asset + Profilo dell'asset apps/client/src/app/components/admin-jobs/admin-jobs.html 35 @@ -6091,7 +6083,7 @@ Saldi di cassa apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 122 + 124 @@ -6144,7 +6136,7 @@ The current market price is - L'attuale prezzo di mercato è + L'attuale prezzo di mercato è apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts 345 @@ -6192,7 +6184,7 @@ Oops! Could not grant access. - Ops! Impossibile abilitare l'accesso. + Ops! Impossibile abilitare l'accesso. apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts 91 @@ -6244,7 +6236,7 @@ Absolute Asset Performance - Rendimento assoluto dell'Asset + Rendimento assoluto dell'Asset apps/client/src/app/pages/portfolio/analysis/analysis-page.html 29 @@ -6252,7 +6244,7 @@ Asset Performance - Rendimento dell'Asset + Rendimento dell'Asset apps/client/src/app/pages/portfolio/analysis/analysis-page.html 50 @@ -6352,7 +6344,7 @@ If you retire today, you would be able to withdraw per year or per month, based on your total assets of and a withdrawal rate of 4%. - Se andassi in pensione oggi, saresti in grado di prelevare all'anno o al mese, calcolato sul valore totale dei tuoi asset di e un prelievo costante del 4%. + Se andassi in pensione oggi, saresti in grado di prelevare all'anno o al mese, calcolato sul valore totale dei tuoi asset di e un prelievo costante del 4%. apps/client/src/app/pages/portfolio/fire/fire-page.html 67 @@ -6379,7 +6371,7 @@ anni libs/ui/src/lib/assistant/assistant.component.ts - 250 + 251 @@ -6460,7 +6452,7 @@ Oops! It looks like you’re making too many requests. Please slow down a bit. - Ops! Sembra tu stia facendo troppe richieste. Rallenta un po' per favore. + Ops! Sembra tu stia facendo troppe richieste. Rallenta un po' per favore. apps/client/src/app/core/http-response.interceptor.ts 96 @@ -6495,7 +6487,7 @@ Attività apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 223 + 207 @@ -6503,7 +6495,7 @@ Rendimento da Dividendi apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 191 + 175 @@ -6511,7 +6503,7 @@ Esegui il lavoro apps/client/src/app/components/admin-jobs/admin-jobs.html - 174 + 176 @@ -6519,7 +6511,7 @@ Priorità apps/client/src/app/components/admin-jobs/admin-jobs.html - 62 + 64 @@ -6538,22 +6530,6 @@ 47 - - Change with currency effect - Variazione con Effetto Valutario - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 53 - - - - Performance with currency effect - Rendimento con effetto valutario - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 81 - - {VAR_PLURAL, plural, =1 {activity} other {activities}} {VAR_PLURAL, plural, =1 {activity} other {activities}} @@ -6591,7 +6567,7 @@ Confermi di voler chiudere il tuo account Ghostfolio? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 174 + 172 @@ -6604,7 +6580,7 @@ Close Account - Chiudi l'account + Chiudi l'account apps/client/src/app/components/user-account-settings/user-account-settings.html 279 @@ -6628,7 +6604,7 @@ Join now or check out the example account - Registrati adesso o prova l'account demo + Registrati adesso o prova l'account demo apps/client/src/app/pages/landing/landing-page.html 434 @@ -6636,10 +6612,10 @@ Oops! There was an error setting up biometric authentication. - Ops! C'è stato un errore impostando l'autenticazione biometrica. + Ops! C'è stato un errore impostando l'autenticazione biometrica. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 308 + 300 @@ -6663,7 +6639,7 @@ Elimina i profili apps/client/src/app/components/admin-market-data/admin-market-data.html - 190 + 205 @@ -6975,7 +6951,7 @@ Disattiva apps/client/src/app/components/rule/rule.component.html - 67 + 72 @@ -6983,7 +6959,7 @@ Attiva apps/client/src/app/components/rule/rule.component.html - 69 + 74 @@ -7018,6 +6994,70 @@ 31 + + Copy link to clipboard + Copy link to clipboard + + apps/client/src/app/components/access-table/access-table.component.html + 61 + + + + Portfolio Snapshot + Portfolio Snapshot + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 39 + + + + Change with currency effect Change + Change with currency effect Change + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 50 + + + + Performance with currency effect Performance + Performance with currency effect Performance + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 69 + + + + Threshold Min + Threshold Min + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 5 + + + + Threshold Max + Threshold Max + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 9 + + + + Close + Close + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 15 + + + + Customize + Customize + + apps/client/src/app/components/rule/rule.component.html + 67 + + diff --git a/apps/client/src/locales/messages.nl.xlf b/apps/client/src/locales/messages.nl.xlf index df8b74a08..8020c6f7a 100644 --- a/apps/client/src/locales/messages.nl.xlf +++ b/apps/client/src/locales/messages.nl.xlf @@ -66,7 +66,7 @@ Intrekken apps/client/src/app/components/access-table/access-table.component.html - 62 + 65 @@ -74,7 +74,7 @@ Wil je deze verleende toegang echt intrekken? apps/client/src/app/components/access-table/access-table.component.ts - 56 + 68 @@ -82,11 +82,11 @@ Activiteiten apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 61 + 63 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 90 + 92 apps/client/src/app/components/accounts-table/accounts-table.component.html @@ -106,11 +106,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 225 + 209 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 335 + 319 apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -250,7 +250,7 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html - 215 + 230 apps/client/src/app/components/admin-overview/admin-overview.html @@ -278,7 +278,7 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html - 236 + 251 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -322,7 +322,7 @@ Taken verwijderen apps/client/src/app/components/admin-jobs/admin-jobs.html - 149 + 151 @@ -330,7 +330,7 @@ Symbool apps/client/src/app/components/admin-jobs/admin-jobs.html - 44 + 46 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -346,7 +346,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 305 + 289 @@ -354,7 +354,7 @@ Gegevensbron apps/client/src/app/components/admin-jobs/admin-jobs.html - 53 + 55 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -374,7 +374,7 @@ Pogingen apps/client/src/app/components/admin-jobs/admin-jobs.html - 81 + 83 @@ -382,7 +382,7 @@ Aangemaakt apps/client/src/app/components/admin-jobs/admin-jobs.html - 90 + 92 @@ -390,7 +390,7 @@ Voltooid apps/client/src/app/components/admin-jobs/admin-jobs.html - 99 + 101 @@ -398,7 +398,7 @@ Status apps/client/src/app/components/admin-jobs/admin-jobs.html - 108 + 110 @@ -422,7 +422,7 @@ Bekijk gegevens apps/client/src/app/components/admin-jobs/admin-jobs.html - 164 + 166 @@ -430,7 +430,7 @@ Bekijk Stacktrace apps/client/src/app/components/admin-jobs/admin-jobs.html - 171 + 173 @@ -438,7 +438,7 @@ Taak verwijderen apps/client/src/app/components/admin-jobs/admin-jobs.html - 177 + 179 @@ -476,9 +476,13 @@ apps/client/src/app/components/admin-market-data-detail/market-data-detail-dialog/market-data-detail-dialog.html 26 + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 104 + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 114 + 98 @@ -548,6 +552,10 @@ apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.html 32 + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 21 + apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 65 @@ -566,7 +574,7 @@ Eerste activiteit apps/client/src/app/components/admin-market-data/admin-market-data.html - 104 + 119 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -574,7 +582,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 213 + 197 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -594,7 +602,7 @@ Historische gegevens apps/client/src/app/components/admin-market-data/admin-market-data.html - 122 + 137 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -662,7 +670,7 @@ Verzamel recente gegevens apps/client/src/app/components/admin-market-data/admin-market-data.html - 177 + 192 @@ -670,7 +678,7 @@ Verzamel alle gegevens apps/client/src/app/components/admin-market-data/admin-market-data.html - 180 + 195 @@ -678,7 +686,7 @@ Verzamel profielgegevens apps/client/src/app/components/admin-market-data/admin-market-data.html - 183 + 198 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -766,7 +774,7 @@ Wilt je deze gebruiker echt verwijderen? apps/client/src/app/components/admin-users/admin-users.component.ts - 125 + 126 @@ -854,7 +862,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 368 + 352 apps/client/src/app/pages/accounts/accounts-page.html @@ -1022,7 +1030,7 @@ apps/client/src/app/components/header/header.component.ts - 231 + 227 @@ -1030,11 +1038,11 @@ Oeps! Onjuiste beveiligingstoken. apps/client/src/app/components/header/header.component.ts - 246 + 242 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 159 + 157 @@ -1170,7 +1178,7 @@ Belegging apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 168 + 152 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -1185,20 +1193,12 @@ 70 - - Gross Performance - Bruto rendement - - apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 85 - - Absolute Net Performance Absoluut netto rendement apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 126 + 102 @@ -1206,7 +1206,7 @@ Netto rendement apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 141 + 117 @@ -1214,7 +1214,7 @@ Totaal Activa apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 167 + 143 @@ -1222,7 +1222,7 @@ Kostbaarheden apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 180 + 156 @@ -1230,7 +1230,7 @@ Noodfonds apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 192 + 168 apps/client/src/app/pages/features/features-page.html @@ -1246,7 +1246,7 @@ Koopkracht apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 252 + 228 @@ -1254,7 +1254,7 @@ Netto waarde apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 297 + 273 @@ -1262,7 +1262,7 @@ Rendement per jaar apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 309 + 285 @@ -1270,11 +1270,11 @@ Dividend apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 181 + 165 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 343 + 319 apps/client/src/app/pages/features/features-page.html @@ -1310,7 +1310,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 274 + 258 apps/client/src/app/pages/public/public-page.html @@ -1330,7 +1330,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 286 + 270 @@ -1342,11 +1342,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 393 + 377 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 430 + 414 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -1362,7 +1362,7 @@ Gegevensstoring melden apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 448 + 433 @@ -1384,10 +1384,6 @@ apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html 6 - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 91 - libs/ui/src/lib/holdings-table/holdings-table.component.html 142 @@ -1446,7 +1442,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 250 + 251 @@ -1458,7 +1454,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 253 + 254 @@ -1470,7 +1466,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 139 + 143 @@ -1670,7 +1666,7 @@ Wil je deze aanmeldingsmethode echt verwijderen? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 252 + 246 @@ -1838,7 +1834,7 @@ Contant geld apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 202 @@ -1874,7 +1870,7 @@ Saldo apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 45 + 47 apps/client/src/app/components/accounts-table/accounts-table.component.html @@ -1890,7 +1886,7 @@ Platform apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 65 + 67 apps/client/src/app/components/accounts-table/accounts-table.component.html @@ -2178,7 +2174,7 @@ Posities apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 77 + 79 apps/client/src/app/components/home-holdings/home-holdings.html @@ -2238,7 +2234,7 @@ Hoeveelheid apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 156 + 140 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -2314,7 +2310,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 232 + 216 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -2338,7 +2334,7 @@ Gegevens importeren... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 120 + 124 @@ -2346,7 +2342,7 @@ Importeren is voltooid apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 128 + 132 @@ -2538,7 +2534,7 @@ Wil je deze activiteit echt verwijderen? libs/ui/src/lib/activities-table/activities-table.component.ts - 235 + 233 @@ -2614,7 +2610,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 136 + 140 @@ -2630,16 +2626,12 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 138 + 142 Change Verandering - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 65 - libs/ui/src/lib/holdings-table/holdings-table.component.html 119 @@ -2674,7 +2666,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 241 + 225 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -2686,7 +2678,7 @@ Gemiddelde prijs per eenheid apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 103 + 87 @@ -2694,7 +2686,7 @@ Maximale prijs apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 146 + 130 @@ -2730,7 +2722,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 258 + 242 @@ -2746,7 +2738,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 268 + 252 @@ -2754,7 +2746,7 @@ Minimale prijs apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 130 + 114 @@ -2806,7 +2798,7 @@ Aantal sectoren apps/client/src/app/components/admin-market-data/admin-market-data.html - 131 + 146 @@ -2814,7 +2806,7 @@ Aantal landen apps/client/src/app/components/admin-market-data/admin-market-data.html - 140 + 155 @@ -2846,7 +2838,7 @@ Filter op... apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 328 + 329 @@ -2906,7 +2898,7 @@ Uitgesloten van analyse apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 264 + 240 @@ -3254,7 +3246,7 @@ Aantal activiteiten apps/client/src/app/components/admin-market-data/admin-market-data.html - 113 + 128 @@ -3314,7 +3306,7 @@ Gegevens valideren... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 234 + 238 @@ -3714,11 +3706,11 @@ Kosten apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 203 + 187 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 108 + 84 apps/client/src/app/pages/portfolio/fire/fire-page.html @@ -3906,7 +3898,7 @@ Wil je echt al je activiteiten verwijderen? libs/ui/src/lib/activities-table/activities-table.component.ts - 225 + 223 @@ -4030,7 +4022,7 @@ Equity apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 56 + 58 @@ -4178,7 +4170,7 @@ Verplichtingen apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 279 + 255 apps/client/src/app/pages/features/features-page.html @@ -4590,7 +4582,7 @@ Assets apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 239 + 215 @@ -5770,7 +5762,7 @@ Interest apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 331 + 307 @@ -6090,7 +6082,7 @@ Cash Balances apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 122 + 124 @@ -6378,7 +6370,7 @@ years libs/ui/src/lib/assistant/assistant.component.ts - 250 + 251 @@ -6494,7 +6486,7 @@ Activity apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 223 + 207 @@ -6502,7 +6494,7 @@ Dividend Yield apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 191 + 175 @@ -6510,7 +6502,7 @@ Execute Job apps/client/src/app/components/admin-jobs/admin-jobs.html - 174 + 176 @@ -6518,7 +6510,7 @@ Priority apps/client/src/app/components/admin-jobs/admin-jobs.html - 62 + 64 @@ -6537,22 +6529,6 @@ 47 - - Change with currency effect - Change with currency effect - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 53 - - - - Performance with currency effect - Performance with currency effect - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 81 - - {VAR_PLURAL, plural, =1 {activity} other {activities}} {VAR_PLURAL, plural, =1 {activity} other {activities}} @@ -6590,7 +6566,7 @@ Do you really want to close your Ghostfolio account? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 174 + 172 @@ -6638,7 +6614,7 @@ Oops! There was an error setting up biometric authentication. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 308 + 300 @@ -6662,7 +6638,7 @@ Delete Profiles apps/client/src/app/components/admin-market-data/admin-market-data.html - 190 + 205 @@ -6974,7 +6950,7 @@ Deactivate apps/client/src/app/components/rule/rule.component.html - 67 + 72 @@ -6982,7 +6958,7 @@ Activate apps/client/src/app/components/rule/rule.component.html - 69 + 74 @@ -7017,6 +6993,70 @@ 31 + + Copy link to clipboard + Copy link to clipboard + + apps/client/src/app/components/access-table/access-table.component.html + 61 + + + + Portfolio Snapshot + Portfolio Snapshot + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 39 + + + + Change with currency effect Change + Change with currency effect Change + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 50 + + + + Performance with currency effect Performance + Performance with currency effect Performance + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 69 + + + + Threshold Min + Threshold Min + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 5 + + + + Threshold Max + Threshold Max + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 9 + + + + Close + Close + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 15 + + + + Customize + Customize + + apps/client/src/app/components/rule/rule.component.html + 67 + + diff --git a/apps/client/src/locales/messages.pl.xlf b/apps/client/src/locales/messages.pl.xlf index 52dfdfba2..806497938 100644 --- a/apps/client/src/locales/messages.pl.xlf +++ b/apps/client/src/locales/messages.pl.xlf @@ -774,7 +774,7 @@ Cofnij apps/client/src/app/components/access-table/access-table.component.html - 62 + 65 @@ -782,7 +782,7 @@ Czy na pewno chcesz cofnąć przyznany dostęp? apps/client/src/app/components/access-table/access-table.component.ts - 56 + 68 @@ -790,7 +790,7 @@ Saldo Gotówkowe apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 45 + 47 apps/client/src/app/components/accounts-table/accounts-table.component.html @@ -806,7 +806,7 @@ Kapitał własny apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 56 + 58 @@ -814,11 +814,11 @@ Aktywności apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 61 + 63 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 90 + 92 apps/client/src/app/components/accounts-table/accounts-table.component.html @@ -838,11 +838,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 225 + 209 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 335 + 319 apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -854,7 +854,7 @@ Platforma apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 65 + 67 apps/client/src/app/components/accounts-table/accounts-table.component.html @@ -1038,7 +1038,7 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html - 215 + 230 apps/client/src/app/components/admin-overview/admin-overview.html @@ -1066,7 +1066,7 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html - 236 + 251 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -1126,7 +1126,7 @@ Symbol apps/client/src/app/components/admin-jobs/admin-jobs.html - 44 + 46 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -1142,7 +1142,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 305 + 289 @@ -1150,7 +1150,7 @@ Źródło Danych apps/client/src/app/components/admin-jobs/admin-jobs.html - 53 + 55 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -1170,7 +1170,7 @@ Próby apps/client/src/app/components/admin-jobs/admin-jobs.html - 81 + 83 @@ -1178,7 +1178,7 @@ Utworzono apps/client/src/app/components/admin-jobs/admin-jobs.html - 90 + 92 @@ -1186,7 +1186,7 @@ Zakończono apps/client/src/app/components/admin-jobs/admin-jobs.html - 99 + 101 @@ -1194,7 +1194,7 @@ Status apps/client/src/app/components/admin-jobs/admin-jobs.html - 108 + 110 @@ -1202,7 +1202,7 @@ Usuń Zadania apps/client/src/app/components/admin-jobs/admin-jobs.html - 149 + 151 @@ -1210,7 +1210,7 @@ Zobacz Dane apps/client/src/app/components/admin-jobs/admin-jobs.html - 164 + 166 @@ -1218,7 +1218,7 @@ Wyświetl Stos Wywołań apps/client/src/app/components/admin-jobs/admin-jobs.html - 171 + 173 @@ -1226,7 +1226,7 @@ Usuń Zadanie apps/client/src/app/components/admin-jobs/admin-jobs.html - 177 + 179 @@ -1264,9 +1264,13 @@ apps/client/src/app/components/admin-market-data-detail/market-data-detail-dialog/market-data-detail-dialog.html 26 + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 104 + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 114 + 98 @@ -1336,6 +1340,10 @@ apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.html 32 + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 21 + apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 65 @@ -1386,7 +1394,7 @@ Filtruj według... apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 328 + 329 @@ -1406,7 +1414,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 232 + 216 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -1430,7 +1438,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 241 + 225 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -1442,7 +1450,7 @@ Pierwsza Aktywność apps/client/src/app/components/admin-market-data/admin-market-data.html - 104 + 119 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -1450,7 +1458,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 213 + 197 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -1462,7 +1470,7 @@ Liczba Aktywności apps/client/src/app/components/admin-market-data/admin-market-data.html - 113 + 128 @@ -1470,7 +1478,7 @@ Dane Historyczne apps/client/src/app/components/admin-market-data/admin-market-data.html - 122 + 137 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -1482,7 +1490,7 @@ Liczba Sektorów apps/client/src/app/components/admin-market-data/admin-market-data.html - 131 + 146 @@ -1490,7 +1498,7 @@ Liczba Krajów apps/client/src/app/components/admin-market-data/admin-market-data.html - 140 + 155 @@ -1498,7 +1506,7 @@ Zbierz Najnowsze Dane apps/client/src/app/components/admin-market-data/admin-market-data.html - 177 + 192 @@ -1506,7 +1514,7 @@ Zbierz Wszystkie Dane apps/client/src/app/components/admin-market-data/admin-market-data.html - 180 + 195 @@ -1514,7 +1522,7 @@ Zbierz Dane Profilu apps/client/src/app/components/admin-market-data/admin-market-data.html - 183 + 198 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -1570,7 +1578,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 258 + 242 @@ -1586,7 +1594,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 268 + 252 @@ -1602,7 +1610,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 274 + 258 apps/client/src/app/pages/public/public-page.html @@ -1622,7 +1630,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 286 + 270 @@ -1910,7 +1918,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 368 + 352 apps/client/src/app/pages/accounts/accounts-page.html @@ -1962,11 +1970,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 393 + 377 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 430 + 414 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -2014,7 +2022,7 @@ Czy na pewno chcesz usunąć tego użytkownika? apps/client/src/app/components/admin-users/admin-users.component.ts - 125 + 126 @@ -2072,10 +2080,6 @@ apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html 6 - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 91 - libs/ui/src/lib/holdings-table/holdings-table.component.html 142 @@ -2230,7 +2234,7 @@ apps/client/src/app/components/header/header.component.ts - 231 + 227 @@ -2238,11 +2242,11 @@ Ups! Nieprawidłowy token bezpieczeństwa. apps/client/src/app/components/header/header.component.ts - 246 + 242 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 159 + 157 @@ -2490,7 +2494,7 @@ Inwestycja apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 168 + 152 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -2505,24 +2509,16 @@ 70 - - Gross Performance - Osiągi Brutto - - apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 85 - - Fees Opłaty apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 203 + 187 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 108 + 84 apps/client/src/app/pages/portfolio/fire/fire-page.html @@ -2534,7 +2530,7 @@ Bezwzględne Osiągi Netto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 126 + 102 @@ -2542,7 +2538,7 @@ Osiągi Netto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 141 + 117 @@ -2550,7 +2546,7 @@ Suma Aktywów apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 167 + 143 @@ -2558,7 +2554,7 @@ Kosztowności apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 180 + 156 @@ -2566,7 +2562,7 @@ Fundusz Rezerwowy apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 192 + 168 apps/client/src/app/pages/features/features-page.html @@ -2582,7 +2578,7 @@ Gotówka apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 202 @@ -2590,7 +2586,7 @@ Aktywa apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 239 + 215 @@ -2598,7 +2594,7 @@ Siła Nabywcza apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 252 + 228 @@ -2606,7 +2602,7 @@ Wykluczone z Analizy apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 264 + 240 @@ -2614,7 +2610,7 @@ Pasywa (Zobowiązania Finansowe) apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 279 + 255 apps/client/src/app/pages/features/features-page.html @@ -2626,7 +2622,7 @@ Wartość Netto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 297 + 273 @@ -2634,7 +2630,7 @@ Osiągi w Ujęciu Rocznym apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 309 + 285 @@ -2642,7 +2638,7 @@ Odsetki apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 331 + 307 @@ -2650,11 +2646,11 @@ Dywidenda apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 181 + 165 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 343 + 319 apps/client/src/app/pages/features/features-page.html @@ -2680,10 +2676,6 @@ Change Zmień - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 65 - libs/ui/src/lib/holdings-table/holdings-table.component.html 119 @@ -2694,7 +2686,7 @@ Średnia Cena Jednostkowa apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 103 + 87 @@ -2702,7 +2694,7 @@ Cena Minimalna apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 130 + 114 @@ -2710,7 +2702,7 @@ Cena Maksymalna apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 146 + 130 @@ -2718,7 +2710,7 @@ Ilość apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 156 + 140 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -2734,7 +2726,7 @@ Zgłoś Błąd Danych apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 448 + 433 @@ -2930,7 +2922,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 250 + 251 @@ -2942,7 +2934,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 253 + 254 @@ -3042,7 +3034,7 @@ Do you really want to remove this sign in method? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 252 + 246 @@ -3226,7 +3218,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 138 + 142 @@ -3238,7 +3230,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 136 + 140 @@ -3250,7 +3242,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 139 + 143 @@ -4130,7 +4122,7 @@ Do you really want to delete these activities? libs/ui/src/lib/activities-table/activities-table.component.ts - 225 + 223 @@ -4282,7 +4274,7 @@ Importing data... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 120 + 124 @@ -4290,7 +4282,7 @@ Import has been completed apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 128 + 132 @@ -4298,7 +4290,7 @@ Validating data... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 234 + 238 @@ -4722,7 +4714,7 @@ Holdings apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 77 + 79 apps/client/src/app/components/home-holdings/home-holdings.html @@ -5486,7 +5478,7 @@ Czy na pewno chcesz usunąć tę działalność? libs/ui/src/lib/activities-table/activities-table.component.ts - 235 + 233 @@ -6090,7 +6082,7 @@ Salda Gotówkowe apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 122 + 124 @@ -6378,7 +6370,7 @@ years libs/ui/src/lib/assistant/assistant.component.ts - 250 + 251 @@ -6494,7 +6486,7 @@ Activity apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 223 + 207 @@ -6502,7 +6494,7 @@ Dochód z Dywidendy apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 191 + 175 @@ -6510,7 +6502,7 @@ Wykonaj Zadanie apps/client/src/app/components/admin-jobs/admin-jobs.html - 174 + 176 @@ -6518,7 +6510,7 @@ Priorytet apps/client/src/app/components/admin-jobs/admin-jobs.html - 62 + 64 @@ -6537,22 +6529,6 @@ 47 - - Change with currency effect - Change with currency effect - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 53 - - - - Performance with currency effect - Performance with currency effect - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 81 - - {VAR_PLURAL, plural, =1 {activity} other {activities}} {VAR_PLURAL, plural, =1 {activity} other {activities}} @@ -6590,7 +6566,7 @@ Czy na pewno chcesz zamknąć swoje konto Ghostfolio? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 174 + 172 @@ -6638,7 +6614,7 @@ Ups! Wystąpił błąd podczas konfigurowania uwierzytelniania biometrycznego. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 308 + 300 @@ -6662,7 +6638,7 @@ Usuń Profile apps/client/src/app/components/admin-market-data/admin-market-data.html - 190 + 205 @@ -6974,7 +6950,7 @@ Dezaktywuj apps/client/src/app/components/rule/rule.component.html - 67 + 72 @@ -6982,7 +6958,7 @@ Aktywuj apps/client/src/app/components/rule/rule.component.html - 69 + 74 @@ -7017,6 +6993,70 @@ 31 + + Copy link to clipboard + Copy link to clipboard + + apps/client/src/app/components/access-table/access-table.component.html + 61 + + + + Portfolio Snapshot + Portfolio Snapshot + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 39 + + + + Change with currency effect Change + Change with currency effect Change + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 50 + + + + Performance with currency effect Performance + Performance with currency effect Performance + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 69 + + + + Threshold Min + Threshold Min + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 5 + + + + Threshold Max + Threshold Max + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 9 + + + + Close + Close + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 15 + + + + Customize + Customize + + apps/client/src/app/components/rule/rule.component.html + 67 + + diff --git a/apps/client/src/locales/messages.pt.xlf b/apps/client/src/locales/messages.pt.xlf index f8d31960f..fbf05f19a 100644 --- a/apps/client/src/locales/messages.pt.xlf +++ b/apps/client/src/locales/messages.pt.xlf @@ -62,7 +62,7 @@ Revogar apps/client/src/app/components/access-table/access-table.component.html - 62 + 65 @@ -70,7 +70,7 @@ Pretende realmente revogar este acesso concedido? apps/client/src/app/components/access-table/access-table.component.ts - 56 + 68 @@ -78,7 +78,7 @@ Plataforma apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 65 + 67 apps/client/src/app/components/accounts-table/accounts-table.component.html @@ -94,11 +94,11 @@ Atividades apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 61 + 63 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 90 + 92 apps/client/src/app/components/accounts-table/accounts-table.component.html @@ -118,11 +118,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 225 + 209 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 335 + 319 apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -222,7 +222,7 @@ Saldo disponível em dinheiro apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 45 + 47 apps/client/src/app/components/accounts-table/accounts-table.component.html @@ -306,7 +306,7 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html - 215 + 230 apps/client/src/app/components/admin-overview/admin-overview.html @@ -334,7 +334,7 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html - 236 + 251 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -378,7 +378,7 @@ Símbolo apps/client/src/app/components/admin-jobs/admin-jobs.html - 44 + 46 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -394,7 +394,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 305 + 289 @@ -402,7 +402,7 @@ Fonte de dados apps/client/src/app/components/admin-jobs/admin-jobs.html - 53 + 55 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -422,7 +422,7 @@ Tentativas apps/client/src/app/components/admin-jobs/admin-jobs.html - 81 + 83 @@ -430,7 +430,7 @@ Criado apps/client/src/app/components/admin-jobs/admin-jobs.html - 90 + 92 @@ -438,7 +438,7 @@ Terminado apps/client/src/app/components/admin-jobs/admin-jobs.html - 99 + 101 @@ -446,7 +446,7 @@ Estado apps/client/src/app/components/admin-jobs/admin-jobs.html - 108 + 110 @@ -454,7 +454,7 @@ Eliminar Tarefas apps/client/src/app/components/admin-jobs/admin-jobs.html - 149 + 151 @@ -478,7 +478,7 @@ Visualizar dados apps/client/src/app/components/admin-jobs/admin-jobs.html - 164 + 166 @@ -486,7 +486,7 @@ Ver Stacktrace apps/client/src/app/components/admin-jobs/admin-jobs.html - 171 + 173 @@ -494,7 +494,7 @@ Apagar Tarefa apps/client/src/app/components/admin-jobs/admin-jobs.html - 177 + 179 @@ -532,9 +532,13 @@ apps/client/src/app/components/admin-market-data-detail/market-data-detail-dialog/market-data-detail-dialog.html 26 + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 104 + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 114 + 98 @@ -604,6 +608,10 @@ apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.html 32 + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 21 + apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 65 @@ -622,7 +630,7 @@ Filtrar por... apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 328 + 329 @@ -642,7 +650,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 232 + 216 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -666,7 +674,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 241 + 225 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -678,7 +686,7 @@ Primeira Atividade apps/client/src/app/components/admin-market-data/admin-market-data.html - 104 + 119 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -686,7 +694,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 213 + 197 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -706,7 +714,7 @@ Dados Históricos apps/client/src/app/components/admin-market-data/admin-market-data.html - 122 + 137 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -718,7 +726,7 @@ Contagem de Países apps/client/src/app/components/admin-market-data/admin-market-data.html - 140 + 155 @@ -726,7 +734,7 @@ Contagem de Setores apps/client/src/app/components/admin-market-data/admin-market-data.html - 131 + 146 @@ -734,7 +742,7 @@ Atualizar dados mais recentes apps/client/src/app/components/admin-market-data/admin-market-data.html - 177 + 192 @@ -742,7 +750,7 @@ Recolher Todos os Dados apps/client/src/app/components/admin-market-data/admin-market-data.html - 180 + 195 @@ -750,7 +758,7 @@ Recolher Dados de Perfíl apps/client/src/app/components/admin-market-data/admin-market-data.html - 183 + 198 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -894,7 +902,7 @@ Deseja realmente excluir este utilizador? apps/client/src/app/components/admin-users/admin-users.component.ts - 125 + 126 @@ -934,7 +942,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 368 + 352 apps/client/src/app/pages/accounts/accounts-page.html @@ -968,10 +976,6 @@ apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html 6 - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 91 - libs/ui/src/lib/holdings-table/holdings-table.component.html 142 @@ -1206,7 +1210,7 @@ apps/client/src/app/components/header/header.component.ts - 231 + 227 @@ -1214,11 +1218,11 @@ Oops! Token de Segurança Incorreto. apps/client/src/app/components/header/header.component.ts - 246 + 242 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 159 + 157 @@ -1390,7 +1394,7 @@ Investimento apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 168 + 152 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -1405,20 +1409,12 @@ 70 - - Gross Performance - Desempenho Bruto - - apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 85 - - Absolute Net Performance Desempenho Líquido Absoluto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 126 + 102 @@ -1426,7 +1422,7 @@ Desempenho Líquido apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 141 + 117 @@ -1434,7 +1430,7 @@ Ativos Totais apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 167 + 143 @@ -1442,7 +1438,7 @@ Bens de valor apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 180 + 156 @@ -1450,7 +1446,7 @@ Fundo de Emergência apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 192 + 168 apps/client/src/app/pages/features/features-page.html @@ -1466,7 +1462,7 @@ Poder de Compra apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 252 + 228 @@ -1474,7 +1470,7 @@ Excluído da Análise apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 264 + 240 @@ -1482,7 +1478,7 @@ Valor Líquido apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 297 + 273 @@ -1490,7 +1486,7 @@ Desempenho Anual apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 309 + 285 @@ -1498,11 +1494,11 @@ Dividendo apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 181 + 165 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 343 + 319 apps/client/src/app/pages/features/features-page.html @@ -1528,10 +1524,6 @@ Change Alterar - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 65 - libs/ui/src/lib/holdings-table/holdings-table.component.html 119 @@ -1542,7 +1534,7 @@ Preço Médio por Unidade apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 103 + 87 @@ -1550,7 +1542,7 @@ Preço Mínimo apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 130 + 114 @@ -1558,7 +1550,7 @@ Preço Máximo apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 146 + 130 @@ -1566,7 +1558,7 @@ Quantidade apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 156 + 140 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -1586,7 +1578,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 258 + 242 @@ -1602,7 +1594,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 268 + 252 @@ -1618,7 +1610,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 274 + 258 apps/client/src/app/pages/public/public-page.html @@ -1638,7 +1630,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 286 + 270 @@ -1650,11 +1642,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 393 + 377 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 430 + 414 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -1670,7 +1662,7 @@ Dados do Relatório com Problema apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 448 + 433 @@ -1738,7 +1730,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 250 + 251 @@ -1750,7 +1742,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 253 + 254 @@ -1774,7 +1766,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 138 + 142 @@ -1786,7 +1778,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 136 + 140 @@ -1798,7 +1790,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 139 + 143 @@ -1918,7 +1910,7 @@ Deseja realmente remover este método de início de sessão? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 252 + 246 @@ -2146,7 +2138,7 @@ Dinheiro apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 202 @@ -2430,7 +2422,7 @@ A importar dados... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 120 + 124 @@ -2438,7 +2430,7 @@ A importação foi concluída apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 128 + 132 @@ -2710,7 +2702,7 @@ Posições apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 77 + 79 apps/client/src/app/components/home-holdings/home-holdings.html @@ -2934,7 +2926,7 @@ Deseja realmente eliminar esta atividade? libs/ui/src/lib/activities-table/activities-table.component.ts - 235 + 233 @@ -3218,7 +3210,7 @@ Nº de Atividades apps/client/src/app/components/admin-market-data/admin-market-data.html - 113 + 128 @@ -3322,7 +3314,7 @@ A validar dados... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 234 + 238 @@ -3714,11 +3706,11 @@ Taxas apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 203 + 187 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 108 + 84 apps/client/src/app/pages/portfolio/fire/fire-page.html @@ -3906,7 +3898,7 @@ Deseja mesmo eliminar estas atividades? libs/ui/src/lib/activities-table/activities-table.component.ts - 225 + 223 @@ -4030,7 +4022,7 @@ Ações apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 56 + 58 @@ -4178,7 +4170,7 @@ Responsabilidades apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 279 + 255 apps/client/src/app/pages/features/features-page.html @@ -4590,7 +4582,7 @@ Ativos apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 239 + 215 @@ -5770,7 +5762,7 @@ Interest apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 331 + 307 @@ -6090,7 +6082,7 @@ Cash Balances apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 122 + 124 @@ -6378,7 +6370,7 @@ years libs/ui/src/lib/assistant/assistant.component.ts - 250 + 251 @@ -6494,7 +6486,7 @@ Activity apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 223 + 207 @@ -6502,7 +6494,7 @@ Dividend Yield apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 191 + 175 @@ -6510,7 +6502,7 @@ Execute Job apps/client/src/app/components/admin-jobs/admin-jobs.html - 174 + 176 @@ -6518,7 +6510,7 @@ Priority apps/client/src/app/components/admin-jobs/admin-jobs.html - 62 + 64 @@ -6537,22 +6529,6 @@ 47 - - Change with currency effect - Change with currency effect - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 53 - - - - Performance with currency effect - Performance with currency effect - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 81 - - {VAR_PLURAL, plural, =1 {activity} other {activities}} {VAR_PLURAL, plural, =1 {activity} other {activities}} @@ -6590,7 +6566,7 @@ Do you really want to close your Ghostfolio account? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 174 + 172 @@ -6638,7 +6614,7 @@ Oops! There was an error setting up biometric authentication. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 308 + 300 @@ -6662,7 +6638,7 @@ Delete Profiles apps/client/src/app/components/admin-market-data/admin-market-data.html - 190 + 205 @@ -6974,7 +6950,7 @@ Deactivate apps/client/src/app/components/rule/rule.component.html - 67 + 72 @@ -6982,7 +6958,7 @@ Activate apps/client/src/app/components/rule/rule.component.html - 69 + 74 @@ -7017,6 +6993,70 @@ 31 + + Copy link to clipboard + Copy link to clipboard + + apps/client/src/app/components/access-table/access-table.component.html + 61 + + + + Portfolio Snapshot + Portfolio Snapshot + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 39 + + + + Change with currency effect Change + Change with currency effect Change + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 50 + + + + Performance with currency effect Performance + Performance with currency effect Performance + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 69 + + + + Threshold Min + Threshold Min + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 5 + + + + Threshold Max + Threshold Max + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 9 + + + + Close + Close + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 15 + + + + Customize + Customize + + apps/client/src/app/components/rule/rule.component.html + 67 + + diff --git a/apps/client/src/locales/messages.tr.xlf b/apps/client/src/locales/messages.tr.xlf index 5485c2ee1..a4e8eeca6 100644 --- a/apps/client/src/locales/messages.tr.xlf +++ b/apps/client/src/locales/messages.tr.xlf @@ -750,7 +750,7 @@ Geri Al apps/client/src/app/components/access-table/access-table.component.html - 62 + 65 @@ -758,7 +758,7 @@ Bu erişim iznini geri almayı gerçekten istiyor musunuz? apps/client/src/app/components/access-table/access-table.component.ts - 56 + 68 @@ -766,7 +766,7 @@ Nakit Bakiye apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 45 + 47 apps/client/src/app/components/accounts-table/accounts-table.component.html @@ -782,7 +782,7 @@ Menkul Kıymet apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 56 + 58 @@ -790,7 +790,7 @@ Platform apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 65 + 67 apps/client/src/app/components/accounts-table/accounts-table.component.html @@ -806,11 +806,11 @@ İşlemler apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 61 + 63 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 90 + 92 apps/client/src/app/components/accounts-table/accounts-table.component.html @@ -830,11 +830,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 225 + 209 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 335 + 319 apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -1002,7 +1002,7 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html - 215 + 230 apps/client/src/app/components/admin-overview/admin-overview.html @@ -1030,7 +1030,7 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html - 236 + 251 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -1074,7 +1074,7 @@ Sembol apps/client/src/app/components/admin-jobs/admin-jobs.html - 44 + 46 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -1090,7 +1090,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 305 + 289 @@ -1098,7 +1098,7 @@ Veri Kaynağı apps/client/src/app/components/admin-jobs/admin-jobs.html - 53 + 55 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -1118,7 +1118,7 @@ Deneme apps/client/src/app/components/admin-jobs/admin-jobs.html - 81 + 83 @@ -1126,7 +1126,7 @@ Oluşturuldu apps/client/src/app/components/admin-jobs/admin-jobs.html - 90 + 92 @@ -1134,7 +1134,7 @@ Tamamlandı apps/client/src/app/components/admin-jobs/admin-jobs.html - 99 + 101 @@ -1142,7 +1142,7 @@ Durum apps/client/src/app/components/admin-jobs/admin-jobs.html - 108 + 110 @@ -1150,7 +1150,7 @@ İşleri Sil apps/client/src/app/components/admin-jobs/admin-jobs.html - 149 + 151 @@ -1174,7 +1174,7 @@ Veri Gör apps/client/src/app/components/admin-jobs/admin-jobs.html - 164 + 166 @@ -1182,7 +1182,7 @@ Hata İzini Görüntüle apps/client/src/app/components/admin-jobs/admin-jobs.html - 171 + 173 @@ -1190,7 +1190,7 @@ İşleri Sil apps/client/src/app/components/admin-jobs/admin-jobs.html - 177 + 179 @@ -1228,9 +1228,13 @@ apps/client/src/app/components/admin-market-data-detail/market-data-detail-dialog/market-data-detail-dialog.html 26 + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 104 + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 114 + 98 @@ -1300,6 +1304,10 @@ apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.html 32 + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 21 + apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 65 @@ -1342,7 +1350,7 @@ Filtrele... apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 328 + 329 @@ -1362,7 +1370,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 232 + 216 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -1386,7 +1394,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 241 + 225 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -1398,7 +1406,7 @@ İlk İşlem apps/client/src/app/components/admin-market-data/admin-market-data.html - 104 + 119 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -1406,7 +1414,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 213 + 197 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -1418,7 +1426,7 @@ İşlem Sayısı apps/client/src/app/components/admin-market-data/admin-market-data.html - 113 + 128 @@ -1426,7 +1434,7 @@ Tarihsel Veri apps/client/src/app/components/admin-market-data/admin-market-data.html - 122 + 137 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -1438,7 +1446,7 @@ Sektör Sayısı apps/client/src/app/components/admin-market-data/admin-market-data.html - 131 + 146 @@ -1446,7 +1454,7 @@ Ülke Sayısı apps/client/src/app/components/admin-market-data/admin-market-data.html - 140 + 155 @@ -1454,7 +1462,7 @@ Son Veriyi Getir apps/client/src/app/components/admin-market-data/admin-market-data.html - 177 + 192 @@ -1462,7 +1470,7 @@ Tüm Veriyi Getir apps/client/src/app/components/admin-market-data/admin-market-data.html - 180 + 195 @@ -1470,7 +1478,7 @@ Profil Verisini Getir apps/client/src/app/components/admin-market-data/admin-market-data.html - 183 + 198 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -1502,7 +1510,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 258 + 242 @@ -1518,7 +1526,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 268 + 252 @@ -1534,7 +1542,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 274 + 258 apps/client/src/app/pages/public/public-page.html @@ -1554,7 +1562,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 286 + 270 @@ -1698,11 +1706,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 393 + 377 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 430 + 414 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -1826,7 +1834,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 368 + 352 apps/client/src/app/pages/accounts/accounts-page.html @@ -1874,7 +1882,7 @@ Bu kullanıcıyı silmeyi gerçekten istiyor musunu? apps/client/src/app/components/admin-users/admin-users.component.ts - 125 + 126 @@ -1932,10 +1940,6 @@ apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html 6 - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 91 - libs/ui/src/lib/holdings-table/holdings-table.component.html 142 @@ -2082,7 +2086,7 @@ apps/client/src/app/components/header/header.component.ts - 231 + 227 @@ -2090,11 +2094,11 @@ Hay Allah! Güvenlik anahtarı yanlış. apps/client/src/app/components/header/header.component.ts - 246 + 242 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 159 + 157 @@ -2342,7 +2346,7 @@ Yatırım apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 168 + 152 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -2357,20 +2361,12 @@ 70 - - Gross Performance - Brüt Performans - - apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 85 - - Absolute Net Performance Toplam Net Performans apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 126 + 102 @@ -2378,7 +2374,7 @@ Net Performans apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 141 + 117 @@ -2386,7 +2382,7 @@ Toplam Varlıklar apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 167 + 143 @@ -2394,7 +2390,7 @@ Yatırım Varlıkları apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 180 + 156 @@ -2402,7 +2398,7 @@ Acil Durum Yedeği apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 192 + 168 apps/client/src/app/pages/features/features-page.html @@ -2418,7 +2414,7 @@ Nakit apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 202 @@ -2426,7 +2422,7 @@ Varlıklar apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 239 + 215 @@ -2434,7 +2430,7 @@ Alım Limiti apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 252 + 228 @@ -2442,7 +2438,7 @@ Analize Dahil Edilmemiştir. apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 264 + 240 @@ -2450,7 +2446,7 @@ Yükümlülükler apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 279 + 255 apps/client/src/app/pages/features/features-page.html @@ -2462,7 +2458,7 @@ Toplam Varlık apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 297 + 273 @@ -2470,7 +2466,7 @@ Yıllıklandırılmış Performans apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 309 + 285 @@ -2478,11 +2474,11 @@ Temettü apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 181 + 165 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 343 + 319 apps/client/src/app/pages/features/features-page.html @@ -2508,10 +2504,6 @@ Change Para Birimi - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 65 - libs/ui/src/lib/holdings-table/holdings-table.component.html 119 @@ -2522,7 +2514,7 @@ Ortalama Birim Fiyat apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 103 + 87 @@ -2530,7 +2522,7 @@ Asgari Fiyat apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 130 + 114 @@ -2538,7 +2530,7 @@ Azami Fiyat apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 146 + 130 @@ -2546,7 +2538,7 @@ Miktar apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 156 + 140 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -2562,11 +2554,11 @@ Komisyon apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 203 + 187 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 108 + 84 apps/client/src/app/pages/portfolio/fire/fire-page.html @@ -2578,7 +2570,7 @@ Rapor Veri Sorunu apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 448 + 433 @@ -2774,7 +2766,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 250 + 251 @@ -2786,7 +2778,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 253 + 254 @@ -2810,7 +2802,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 138 + 142 @@ -2822,7 +2814,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 136 + 140 @@ -2834,7 +2826,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 139 + 143 @@ -3642,7 +3634,7 @@ Tüm işlemlerinizi silmeyi gerçekten istiyor musunuz? libs/ui/src/lib/activities-table/activities-table.component.ts - 225 + 223 @@ -3762,7 +3754,7 @@ Veri içe aktarılıyor... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 120 + 124 @@ -3770,7 +3762,7 @@ İçe aktarma tamamlandı apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 128 + 132 @@ -3778,7 +3770,7 @@ Veri doğrulanıyor... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 234 + 238 @@ -4186,7 +4178,7 @@ Varlıklar apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 77 + 79 apps/client/src/app/components/home-holdings/home-holdings.html @@ -4894,7 +4886,7 @@ Bu giriş yöntemini kaldırmayı gerçekten istiyor musunuz? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 252 + 246 @@ -5190,7 +5182,7 @@ TBu işlemi silmeyi gerçekten istiyor musunuz? libs/ui/src/lib/activities-table/activities-table.component.ts - 235 + 233 @@ -5702,7 +5694,7 @@ Faiz apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 331 + 307 @@ -6090,7 +6082,7 @@ Nakit Bakiyeleri apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 122 + 124 @@ -6378,7 +6370,7 @@ years libs/ui/src/lib/assistant/assistant.component.ts - 250 + 251 @@ -6494,7 +6486,7 @@ Activity apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 223 + 207 @@ -6502,7 +6494,7 @@ Dividend Yield apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 191 + 175 @@ -6510,7 +6502,7 @@ Execute Job apps/client/src/app/components/admin-jobs/admin-jobs.html - 174 + 176 @@ -6518,7 +6510,7 @@ Priority apps/client/src/app/components/admin-jobs/admin-jobs.html - 62 + 64 @@ -6537,22 +6529,6 @@ 47 - - Change with currency effect - Change with currency effect - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 53 - - - - Performance with currency effect - Performance with currency effect - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 81 - - {VAR_PLURAL, plural, =1 {activity} other {activities}} {VAR_PLURAL, plural, =1 {activity} other {activities}} @@ -6590,7 +6566,7 @@ Do you really want to close your Ghostfolio account? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 174 + 172 @@ -6638,7 +6614,7 @@ Oops! There was an error setting up biometric authentication. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 308 + 300 @@ -6662,7 +6638,7 @@ Delete Profiles apps/client/src/app/components/admin-market-data/admin-market-data.html - 190 + 205 @@ -6974,7 +6950,7 @@ Deactivate apps/client/src/app/components/rule/rule.component.html - 67 + 72 @@ -6982,7 +6958,7 @@ Activate apps/client/src/app/components/rule/rule.component.html - 69 + 74 @@ -7017,6 +6993,70 @@ 31 + + Copy link to clipboard + Copy link to clipboard + + apps/client/src/app/components/access-table/access-table.component.html + 61 + + + + Portfolio Snapshot + Portfolio Snapshot + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 39 + + + + Change with currency effect Change + Change with currency effect Change + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 50 + + + + Performance with currency effect Performance + Performance with currency effect Performance + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 69 + + + + Threshold Min + Threshold Min + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 5 + + + + Threshold Max + Threshold Max + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 9 + + + + Close + Close + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 15 + + + + Customize + Customize + + apps/client/src/app/components/rule/rule.component.html + 67 + + diff --git a/apps/client/src/locales/messages.xlf b/apps/client/src/locales/messages.xlf index dbd3328a4..9f1489695 100644 --- a/apps/client/src/locales/messages.xlf +++ b/apps/client/src/locales/messages.xlf @@ -746,21 +746,21 @@ Revoke apps/client/src/app/components/access-table/access-table.component.html - 62 + 65 Do you really want to revoke this granted access? apps/client/src/app/components/access-table/access-table.component.ts - 56 + 68 Cash Balance apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 45 + 47 apps/client/src/app/components/accounts-table/accounts-table.component.html @@ -775,18 +775,18 @@ Equity apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 56 + 58 Activities apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 61 + 63 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 90 + 92 apps/client/src/app/components/accounts-table/accounts-table.component.html @@ -806,11 +806,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 225 + 209 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 335 + 319 apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -821,7 +821,7 @@ Platform apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 65 + 67 apps/client/src/app/components/accounts-table/accounts-table.component.html @@ -836,7 +836,7 @@ Cash Balances apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 122 + 124 @@ -1006,7 +1006,7 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html - 215 + 230 apps/client/src/app/components/admin-overview/admin-overview.html @@ -1033,7 +1033,7 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html - 236 + 251 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -1089,7 +1089,7 @@ Symbol apps/client/src/app/components/admin-jobs/admin-jobs.html - 44 + 46 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -1105,14 +1105,14 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 305 + 289 Data Source apps/client/src/app/components/admin-jobs/admin-jobs.html - 53 + 55 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -1131,56 +1131,56 @@ Attempts apps/client/src/app/components/admin-jobs/admin-jobs.html - 81 + 83 Created apps/client/src/app/components/admin-jobs/admin-jobs.html - 90 + 92 Finished apps/client/src/app/components/admin-jobs/admin-jobs.html - 99 + 101 Status apps/client/src/app/components/admin-jobs/admin-jobs.html - 108 + 110 Delete Jobs apps/client/src/app/components/admin-jobs/admin-jobs.html - 149 + 151 View Data apps/client/src/app/components/admin-jobs/admin-jobs.html - 164 + 166 View Stacktrace apps/client/src/app/components/admin-jobs/admin-jobs.html - 171 + 173 Delete Job apps/client/src/app/components/admin-jobs/admin-jobs.html - 177 + 179 @@ -1215,9 +1215,13 @@ apps/client/src/app/components/admin-market-data-detail/market-data-detail-dialog/market-data-detail-dialog.html 26 + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 104 + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 114 + 98 @@ -1285,6 +1289,10 @@ apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.html 32 + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 21 + apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 65 @@ -1330,7 +1338,7 @@ Filter by... apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 328 + 329 @@ -1349,7 +1357,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 232 + 216 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -1372,7 +1380,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 241 + 225 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -1383,7 +1391,7 @@ First Activity apps/client/src/app/components/admin-market-data/admin-market-data.html - 104 + 119 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -1391,7 +1399,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 213 + 197 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -1402,14 +1410,14 @@ Activities Count apps/client/src/app/components/admin-market-data/admin-market-data.html - 113 + 128 Historical Data apps/client/src/app/components/admin-market-data/admin-market-data.html - 122 + 137 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -1420,35 +1428,35 @@ Sectors Count apps/client/src/app/components/admin-market-data/admin-market-data.html - 131 + 146 Countries Count apps/client/src/app/components/admin-market-data/admin-market-data.html - 140 + 155 Gather Recent Data apps/client/src/app/components/admin-market-data/admin-market-data.html - 177 + 192 Gather All Data apps/client/src/app/components/admin-market-data/admin-market-data.html - 180 + 195 Gather Profile Data apps/client/src/app/components/admin-market-data/admin-market-data.html - 183 + 198 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -1499,7 +1507,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 258 + 242 @@ -1514,7 +1522,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 268 + 252 @@ -1529,7 +1537,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 274 + 258 apps/client/src/app/pages/public/public-page.html @@ -1548,7 +1556,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 286 + 270 @@ -1812,7 +1820,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 368 + 352 apps/client/src/app/pages/accounts/accounts-page.html @@ -1859,11 +1867,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 393 + 377 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 430 + 414 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -1906,7 +1914,7 @@ Do you really want to delete this user? apps/client/src/app/components/admin-users/admin-users.component.ts - 125 + 126 @@ -1957,10 +1965,6 @@ apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html 6 - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 91 - libs/ui/src/lib/holdings-table/holdings-table.component.html 142 @@ -2100,18 +2104,18 @@ apps/client/src/app/components/header/header.component.ts - 231 + 227 Oops! Incorrect Security Token. apps/client/src/app/components/header/header.component.ts - 246 + 242 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 159 + 157 @@ -2333,7 +2337,7 @@ Investment apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 168 + 152 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -2347,22 +2351,15 @@ 70 - - Gross Performance - - apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 85 - - Fees apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 203 + 187 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 108 + 84 apps/client/src/app/pages/portfolio/fire/fire-page.html @@ -2373,35 +2370,35 @@ Absolute Net Performance apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 126 + 102 Net Performance apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 141 + 117 Total Assets apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 167 + 143 Valuables apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 180 + 156 Emergency Fund apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 192 + 168 apps/client/src/app/pages/features/features-page.html @@ -2416,35 +2413,35 @@ Cash apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 202 Assets apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 239 + 215 Buying Power apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 252 + 228 Excluded from Analysis apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 264 + 240 Liabilities apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 279 + 255 apps/client/src/app/pages/features/features-page.html @@ -2455,32 +2452,32 @@ Net Worth apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 297 + 273 Annualized Performance apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 309 + 285 Interest apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 331 + 307 Dividend apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 181 + 165 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 343 + 319 apps/client/src/app/pages/features/features-page.html @@ -2504,10 +2501,6 @@ Change - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 65 - libs/ui/src/lib/holdings-table/holdings-table.component.html 119 @@ -2517,28 +2510,28 @@ Average Unit Price apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 103 + 87 Minimum Price apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 130 + 114 Maximum Price apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 146 + 130 Quantity apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 156 + 140 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -2553,7 +2546,7 @@ Report Data Glitch apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 448 + 433 @@ -2734,7 +2727,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 250 + 251 @@ -2745,7 +2738,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 253 + 254 @@ -2833,7 +2826,7 @@ Do you really want to remove this sign in method? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 252 + 246 @@ -2996,7 +2989,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 138 + 142 @@ -3007,7 +3000,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 136 + 140 @@ -3018,7 +3011,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 139 + 143 @@ -3803,7 +3796,7 @@ Do you really want to delete these activities? libs/ui/src/lib/activities-table/activities-table.component.ts - 225 + 223 @@ -3939,21 +3932,21 @@ Importing data... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 120 + 124 Import has been completed apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 128 + 132 Validating data... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 234 + 238 @@ -4329,7 +4322,7 @@ Holdings apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 77 + 79 apps/client/src/app/components/home-holdings/home-holdings.html @@ -5045,7 +5038,7 @@ Do you really want to delete this activity? libs/ui/src/lib/activities-table/activities-table.component.ts - 235 + 233 @@ -5789,7 +5782,7 @@ years libs/ui/src/lib/assistant/assistant.component.ts - 250 + 251 @@ -5892,21 +5885,21 @@ Activity apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 223 + 207 Dividend Yield apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 191 + 175 Execute Job apps/client/src/app/components/admin-jobs/admin-jobs.html - 174 + 176 @@ -5920,7 +5913,7 @@ Priority apps/client/src/app/components/admin-jobs/admin-jobs.html - 62 + 64 @@ -5930,20 +5923,6 @@ 47 - - Change with currency effect - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 53 - - - - Performance with currency effect - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 81 - - Buy and sell @@ -5983,7 +5962,7 @@ Do you really want to close your Ghostfolio account? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 174 + 172 @@ -6018,7 +5997,7 @@ Oops! There was an error setting up biometric authentication. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 308 + 300 @@ -6039,7 +6018,7 @@ Delete Profiles apps/client/src/app/components/admin-market-data/admin-market-data.html - 190 + 205 @@ -6340,16 +6319,72 @@ Activate apps/client/src/app/components/rule/rule.component.html - 69 + 74 Deactivate + + apps/client/src/app/components/rule/rule.component.html + 72 + + + + Threshold Max + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 9 + + + + Customize apps/client/src/app/components/rule/rule.component.html 67 + + Portfolio Snapshot + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 39 + + + + Threshold Min + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 5 + + + + Performance with currency effect Performance + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 69 + + + + Copy link to clipboard + + apps/client/src/app/components/access-table/access-table.component.html + 61 + + + + Change with currency effect Change + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 50 + + + + Close + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 15 + + diff --git a/apps/client/src/locales/messages.zh.xlf b/apps/client/src/locales/messages.zh.xlf index 96bffe2d8..670c37892 100644 --- a/apps/client/src/locales/messages.zh.xlf +++ b/apps/client/src/locales/messages.zh.xlf @@ -775,7 +775,7 @@ 撤销 apps/client/src/app/components/access-table/access-table.component.html - 62 + 65 @@ -783,7 +783,7 @@ 您真的要撤销此授予的访问权限吗? apps/client/src/app/components/access-table/access-table.component.ts - 56 + 68 @@ -791,7 +791,7 @@ 现金余额 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 45 + 47 apps/client/src/app/components/accounts-table/accounts-table.component.html @@ -807,7 +807,7 @@ 公平 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 56 + 58 @@ -815,11 +815,11 @@ 活动 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 61 + 63 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 90 + 92 apps/client/src/app/components/accounts-table/accounts-table.component.html @@ -839,11 +839,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 225 + 209 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 335 + 319 apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -855,7 +855,7 @@ 平台 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 65 + 67 apps/client/src/app/components/accounts-table/accounts-table.component.html @@ -871,7 +871,7 @@ 现金余额 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 122 + 124 @@ -1047,7 +1047,7 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html - 215 + 230 apps/client/src/app/components/admin-overview/admin-overview.html @@ -1075,7 +1075,7 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html - 236 + 251 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -1135,7 +1135,7 @@ 符号 apps/client/src/app/components/admin-jobs/admin-jobs.html - 44 + 46 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -1151,7 +1151,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 305 + 289 @@ -1159,7 +1159,7 @@ 数据源 apps/client/src/app/components/admin-jobs/admin-jobs.html - 53 + 55 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -1179,7 +1179,7 @@ 尝试 apps/client/src/app/components/admin-jobs/admin-jobs.html - 81 + 83 @@ -1187,7 +1187,7 @@ 创建 apps/client/src/app/components/admin-jobs/admin-jobs.html - 90 + 92 @@ -1195,7 +1195,7 @@ 完成的 apps/client/src/app/components/admin-jobs/admin-jobs.html - 99 + 101 @@ -1203,7 +1203,7 @@ 状况 apps/client/src/app/components/admin-jobs/admin-jobs.html - 108 + 110 @@ -1211,7 +1211,7 @@ 删除作业 apps/client/src/app/components/admin-jobs/admin-jobs.html - 149 + 151 @@ -1219,7 +1219,7 @@ 查看数据 apps/client/src/app/components/admin-jobs/admin-jobs.html - 164 + 166 @@ -1227,7 +1227,7 @@ 查看堆栈跟踪 apps/client/src/app/components/admin-jobs/admin-jobs.html - 171 + 173 @@ -1235,7 +1235,7 @@ 删除作业 apps/client/src/app/components/admin-jobs/admin-jobs.html - 177 + 179 @@ -1273,9 +1273,13 @@ apps/client/src/app/components/admin-market-data-detail/market-data-detail-dialog/market-data-detail-dialog.html 26 + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 104 + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 114 + 98 @@ -1345,6 +1349,10 @@ apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.html 32 + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 21 + apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 65 @@ -1395,7 +1403,7 @@ 过滤... apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 328 + 329 @@ -1415,7 +1423,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 232 + 216 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -1439,7 +1447,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 241 + 225 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -1451,7 +1459,7 @@ 第一个活动 apps/client/src/app/components/admin-market-data/admin-market-data.html - 104 + 119 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -1459,7 +1467,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 213 + 197 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -1471,7 +1479,7 @@ 活动计数 apps/client/src/app/components/admin-market-data/admin-market-data.html - 113 + 128 @@ -1479,7 +1487,7 @@ 历史数据 apps/client/src/app/components/admin-market-data/admin-market-data.html - 122 + 137 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -1491,7 +1499,7 @@ 行业数 apps/client/src/app/components/admin-market-data/admin-market-data.html - 131 + 146 @@ -1499,7 +1507,7 @@ 国家数 apps/client/src/app/components/admin-market-data/admin-market-data.html - 140 + 155 @@ -1507,7 +1515,7 @@ 收集最近的数据 apps/client/src/app/components/admin-market-data/admin-market-data.html - 177 + 192 @@ -1515,7 +1523,7 @@ 收集所有数据 apps/client/src/app/components/admin-market-data/admin-market-data.html - 180 + 195 @@ -1523,7 +1531,7 @@ 收集个人资料数据 apps/client/src/app/components/admin-market-data/admin-market-data.html - 183 + 198 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -1579,7 +1587,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 258 + 242 @@ -1595,7 +1603,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 268 + 252 @@ -1611,7 +1619,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 274 + 258 apps/client/src/app/pages/public/public-page.html @@ -1631,7 +1639,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 286 + 270 @@ -1927,7 +1935,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 368 + 352 apps/client/src/app/pages/accounts/accounts-page.html @@ -1979,11 +1987,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 393 + 377 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 430 + 414 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -2031,7 +2039,7 @@ 您真的要删除该用户吗? apps/client/src/app/components/admin-users/admin-users.component.ts - 125 + 126 @@ -2089,10 +2097,6 @@ apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html 6 - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 91 - libs/ui/src/lib/holdings-table/holdings-table.component.html 142 @@ -2247,7 +2251,7 @@ apps/client/src/app/components/header/header.component.ts - 231 + 227 @@ -2255,11 +2259,11 @@ 哎呀!安全令牌不正确。 apps/client/src/app/components/header/header.component.ts - 246 + 242 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 159 + 157 @@ -2507,7 +2511,7 @@ 投资 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 168 + 152 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -2522,24 +2526,16 @@ 70 - - Gross Performance - 总表现 - - apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 85 - - Fees 费用 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 203 + 187 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 108 + 84 apps/client/src/app/pages/portfolio/fire/fire-page.html @@ -2551,7 +2547,7 @@ 绝对净绩效 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 126 + 102 @@ -2559,7 +2555,7 @@ 净绩效 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 141 + 117 @@ -2567,7 +2563,7 @@ 总资产 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 167 + 143 @@ -2575,7 +2571,7 @@ 贵重物品 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 180 + 156 @@ -2583,7 +2579,7 @@ 应急基金 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 192 + 168 apps/client/src/app/pages/features/features-page.html @@ -2599,7 +2595,7 @@ 现金 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 202 @@ -2607,7 +2603,7 @@ 资产 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 239 + 215 @@ -2615,7 +2611,7 @@ 购买力 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 252 + 228 @@ -2623,7 +2619,7 @@ 从分析中排除 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 264 + 240 @@ -2631,7 +2627,7 @@ 负债 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 279 + 255 apps/client/src/app/pages/features/features-page.html @@ -2643,7 +2639,7 @@ 净值 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 297 + 273 @@ -2651,7 +2647,7 @@ 年化业绩 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 309 + 285 @@ -2659,7 +2655,7 @@ 利息 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 331 + 307 @@ -2667,11 +2663,11 @@ 股息 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 181 + 165 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 343 + 319 apps/client/src/app/pages/features/features-page.html @@ -2697,10 +2693,6 @@ Change 修改 - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 65 - libs/ui/src/lib/holdings-table/holdings-table.component.html 119 @@ -2711,7 +2703,7 @@ 平均单价 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 103 + 87 @@ -2719,7 +2711,7 @@ 最低价格 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 130 + 114 @@ -2727,7 +2719,7 @@ 最高价格 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 146 + 130 @@ -2735,7 +2727,7 @@ 数量 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 156 + 140 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -2751,7 +2743,7 @@ 报告数据故障 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 448 + 433 @@ -2947,7 +2939,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 250 + 251 @@ -2959,7 +2951,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 253 + 254 @@ -3059,7 +3051,7 @@ 您确实要删除此登录方法吗? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 252 + 246 @@ -3243,7 +3235,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 138 + 142 @@ -3255,7 +3247,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 136 + 140 @@ -3267,7 +3259,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 139 + 143 @@ -4147,7 +4139,7 @@ 您真的要删除所有活动吗? libs/ui/src/lib/activities-table/activities-table.component.ts - 225 + 223 @@ -4299,7 +4291,7 @@ 正在导入数据... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 120 + 124 @@ -4307,7 +4299,7 @@ 导入已完成 apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 128 + 132 @@ -4315,7 +4307,7 @@ 验证数据... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 234 + 238 @@ -4739,7 +4731,7 @@ 控股 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 77 + 79 apps/client/src/app/components/home-holdings/home-holdings.html @@ -5535,7 +5527,7 @@ 您确实要删除此活动吗? libs/ui/src/lib/activities-table/activities-table.component.ts - 235 + 233 @@ -6379,7 +6371,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 250 + 251 @@ -6495,7 +6487,7 @@ 活动 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 223 + 207 @@ -6503,7 +6495,7 @@ Dividend Yield apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 191 + 175 @@ -6511,7 +6503,7 @@ Execute Job apps/client/src/app/components/admin-jobs/admin-jobs.html - 174 + 176 @@ -6519,7 +6511,7 @@ Priority apps/client/src/app/components/admin-jobs/admin-jobs.html - 62 + 64 @@ -6538,22 +6530,6 @@ 47 - - Change with currency effect - Change with currency effect - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 53 - - - - Performance with currency effect - Performance with currency effect - - apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 81 - - {VAR_PLURAL, plural, =1 {activity} other {activities}} {VAR_PLURAL, plural, =1 {activity} other {activities}} @@ -6591,7 +6567,7 @@ Do you really want to close your Ghostfolio account? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 174 + 172 @@ -6639,7 +6615,7 @@ Oops! There was an error setting up biometric authentication. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 308 + 300 @@ -6663,7 +6639,7 @@ Delete Profiles apps/client/src/app/components/admin-market-data/admin-market-data.html - 190 + 205 @@ -6975,7 +6951,7 @@ Deactivate apps/client/src/app/components/rule/rule.component.html - 67 + 72 @@ -6983,7 +6959,7 @@ Activate apps/client/src/app/components/rule/rule.component.html - 69 + 74 @@ -7018,6 +6994,70 @@ 31 + + Copy link to clipboard + Copy link to clipboard + + apps/client/src/app/components/access-table/access-table.component.html + 61 + + + + Portfolio Snapshot + Portfolio Snapshot + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 39 + + + + Change with currency effect Change + Change with currency effect Change + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 50 + + + + Performance with currency effect Performance + Performance with currency effect Performance + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 69 + + + + Threshold Min + Threshold Min + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 5 + + + + Threshold Max + Threshold Max + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 9 + + + + Close + Close + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 15 + + + + Customize + Customize + + apps/client/src/app/components/rule/rule.component.html + 67 + + From d1f6601c5e9e7be42513caf5a9fed1ae46fe6da5 Mon Sep 17 00:00:00 2001 From: karolsol <37480306+karolsol@users.noreply.github.com> Date: Thu, 19 Sep 2024 18:11:27 +0000 Subject: [PATCH 52/78] Feature/Improve language localization for pl (#3780) * Update translations * Update changelog --- CHANGELOG.md | 1 + apps/client/src/locales/messages.pl.xlf | 114 ++++++++++++------------ 2 files changed, 58 insertions(+), 57 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c8f722116..f3eccf8cb 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 language localization for German (`de`) +- Improved the language localization for Polish (`pl`) ## 2.108.0 - 2024-09-17 diff --git a/apps/client/src/locales/messages.pl.xlf b/apps/client/src/locales/messages.pl.xlf index 806497938..717699a09 100644 --- a/apps/client/src/locales/messages.pl.xlf +++ b/apps/client/src/locales/messages.pl.xlf @@ -2763,7 +2763,7 @@ Portfolio Allocations - Portfolio Allocations + Alokacja portfela apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 26 @@ -2783,7 +2783,7 @@ Performance Benchmarks - Performance Benchmarks + Wskaźniki wydajności apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 30 @@ -2799,7 +2799,7 @@ FIRE Calculator - FIRE Kalkulator + Kalkulator FIRE apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 34 @@ -2815,7 +2815,7 @@ Professional Data Provider - Professional Data Provider + Profesjonalne źródło danych apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 38 @@ -2859,7 +2859,7 @@ Upgrade Plan - Upgrade Plan + Ulepsz Plan apps/client/src/app/components/header/header.component.html 178 @@ -2879,7 +2879,7 @@ Today - Today + Dziś apps/client/src/app/components/toggle/toggle.component.ts 22 @@ -2939,7 +2939,7 @@ Grant access - Grant access + Przyznaj dostęp apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 7 @@ -2947,7 +2947,7 @@ Public - Public + Publiczny apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 25 @@ -2955,7 +2955,7 @@ Granted Access - Granted Access + Przyznano dostęp apps/client/src/app/components/user-account-access/user-account-access.html 5 @@ -2963,7 +2963,7 @@ Please enter your coupon code: - Please enter your coupon code: + Wpisz kod kuponu: apps/client/src/app/components/user-account-membership/user-account-membership.component.ts 118 @@ -2979,7 +2979,7 @@ Coupon code has been redeemed - Coupon code has been redeemed + Kupon został zrealizowany apps/client/src/app/components/user-account-membership/user-account-membership.component.ts 140 @@ -2987,7 +2987,7 @@ Reload - Reload + Odśwież apps/client/src/app/components/user-account-membership/user-account-membership.component.ts 141 @@ -2995,7 +2995,7 @@ per year - per year + rocznie apps/client/src/app/components/user-account-membership/user-account-membership.html 33 @@ -3007,7 +3007,7 @@ Try Premium - Try Premium + Wypróbuj Premium apps/client/src/app/components/user-account-membership/user-account-membership.html 40 @@ -3015,7 +3015,7 @@ Redeem Coupon - Redeem Coupon + Wykorzystaj kupon apps/client/src/app/components/user-account-membership/user-account-membership.html 54 @@ -3031,7 +3031,7 @@ Do you really want to remove this sign in method? - Do you really want to remove this sign in method? + Czy na pewno chcesz usunąć tą metode logowania? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts 246 @@ -3055,7 +3055,7 @@ Protection for sensitive information like absolute performances and quantity values - Protection for sensitive information like absolute performances and quantity values + Ochrona dla wrażliwych informacji takich jak wyniki i wartości ilościowe apps/client/src/app/components/user-account-settings/user-account-settings.html 8 @@ -3087,7 +3087,7 @@ Date and number format - Date and number format + Format daty i liczb apps/client/src/app/components/user-account-settings/user-account-settings.html 125 @@ -3235,7 +3235,7 @@ Okay - Okay + Okej apps/client/src/app/core/http-response.interceptor.ts 81 @@ -3263,7 +3263,7 @@ Changelog - Changelog + Changelog apps/client/src/app/pages/about/about-page.component.ts 49 @@ -3275,7 +3275,7 @@ License - License + Licencja apps/client/src/app/pages/about/about-page.component.ts 54 @@ -3299,7 +3299,7 @@ Our - Our + Nasi apps/client/src/app/pages/about/oss-friends/oss-friends-page.html 6 @@ -3307,7 +3307,7 @@ Discover other exciting Open Source Software projects - Discover other exciting Open Source Software projects + Odkryj inne fascynujące projekty Open Source apps/client/src/app/pages/about/oss-friends/oss-friends-page.html 9 @@ -3315,7 +3315,7 @@ Visit - Visit + Odwiedz apps/client/src/app/pages/about/oss-friends/oss-friends-page.html 28 @@ -3331,7 +3331,7 @@ Oops, cash balance transfer has failed. - Oops, cash balance transfer has failed. + Ups, transfer salda nie powiódł się. apps/client/src/app/pages/accounts/accounts-page.component.ts 311 @@ -3339,7 +3339,7 @@ Update account - Update account + Uaktualnij konto apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html 8 @@ -3347,7 +3347,7 @@ Add account - Add account + Dodaj konto apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html 10 @@ -3355,7 +3355,7 @@ Account ID - Account ID + ID konta apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html 96 @@ -3363,7 +3363,7 @@ From - From + Z apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.html 11 @@ -3371,7 +3371,7 @@ To - To + Do apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.html 32 @@ -3379,7 +3379,7 @@ Transfer - Transfer + Transfer apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.html 72 @@ -3387,7 +3387,7 @@ Admin Control - Admin Control + Panel Administratora apps/client/src/app/pages/admin/admin-page-routing.module.ts 20 @@ -3395,7 +3395,7 @@ Market Data - Market Data + Dane Rynkowe apps/client/src/app/pages/admin/admin-page-routing.module.ts 30 @@ -3407,7 +3407,7 @@ Settings - Settings + Ustawienia apps/client/src/app/pages/admin/admin-page-routing.module.ts 35 @@ -3427,7 +3427,7 @@ Users - Users + Użytkownicy apps/client/src/app/pages/admin/admin-page-routing.module.ts 40 @@ -3439,7 +3439,7 @@ Overview - Overview + Przegląd apps/client/src/app/pages/admin/admin-page.component.ts 27 @@ -3459,7 +3459,7 @@ Blog - Blog + Blog apps/client/src/app/pages/blog/blog-page-routing.module.ts 13 @@ -3467,7 +3467,7 @@ Discover the latest Ghostfolio updates and insights on personal finance - Discover the latest Ghostfolio updates and insights on personal finance + Odkryj najnowsze aktualizacje Ghostfolio oraz spostrzeżenia na temat finansów osobistych apps/client/src/app/pages/blog/blog-page.html 7 @@ -3475,7 +3475,7 @@ As you are already logged in, you cannot access the demo account. - As you are already logged in, you cannot access the demo account. + Ponieważ jesteś już zalogowany, nie możesz uzyskać dostępu do konta demo. apps/client/src/app/pages/demo/demo-page.component.ts 35 @@ -3483,7 +3483,7 @@ Frequently Asked Questions (FAQ) - Frequently Asked Questions (FAQ) + Często zadawane pytania (FAQ) apps/client/src/app/pages/faq/faq-page-routing.module.ts 34 @@ -3495,7 +3495,7 @@ Frequently Asked Questions (FAQ) - Frequently Asked Questions (FAQ) + Często zadawane pytania (FAQ) apps/client/src/app/pages/faq/overview/faq-overview-page.html 4 @@ -3511,7 +3511,7 @@ Features - Features + Funkcje apps/client/src/app/app-routing.module.ts 65 @@ -3519,7 +3519,7 @@ Check out the numerous features of Ghostfolio to manage your wealth - Check out the numerous features of Ghostfolio to manage your wealth + Przetestuj liczne funkcje Ghostfolio służące zarządzaniu twoim majątkiem apps/client/src/app/pages/features/features-page.html 6 @@ -3527,7 +3527,7 @@ Stocks - Stocks + Akcje apps/client/src/app/pages/features/features-page.html 15 @@ -3535,7 +3535,7 @@ ETFs - ETFs + ETFy apps/client/src/app/pages/features/features-page.html 25 @@ -3543,7 +3543,7 @@ Bonds - Bonds + Obligacje apps/client/src/app/pages/features/features-page.html 38 @@ -3551,7 +3551,7 @@ Cryptocurrencies - Cryptocurrencies + Kryptowaluty apps/client/src/app/pages/features/features-page.html 51 @@ -3559,7 +3559,7 @@ Wealth Items - Wealth Items + Cenne przedmioty apps/client/src/app/pages/features/features-page.html 76 @@ -3567,7 +3567,7 @@ Import and Export - Import and Export + Import i Export apps/client/src/app/pages/features/features-page.html 115 @@ -3575,7 +3575,7 @@ Multi-Accounts - Multi-Accounts + Wiele kont apps/client/src/app/pages/features/features-page.html 127 @@ -3583,7 +3583,7 @@ Portfolio Calculations - Portfolio Calculations + Kalkulacje portfela apps/client/src/app/pages/features/features-page.html 141 @@ -3591,7 +3591,7 @@ Dark Mode - Dark Mode + Ciemny motyw apps/client/src/app/pages/features/features-page.html 178 @@ -3599,7 +3599,7 @@ Market Mood - Market Mood + Nastrój rynku apps/client/src/app/pages/features/features-page.html 206 @@ -3607,7 +3607,7 @@ Static Analysis - Static Analysis + Analiza statyczna apps/client/src/app/pages/features/features-page.html 225 @@ -3615,7 +3615,7 @@ Multi-Language - Multi-Language + Wielo-językowość apps/client/src/app/pages/features/features-page.html 242 @@ -3623,7 +3623,7 @@ Open Source Software - Open Source Software + Oprogramowanie Open Source apps/client/src/app/pages/features/features-page.html 278 @@ -3631,7 +3631,7 @@ Get Started - Get Started + Rozpocznij apps/client/src/app/pages/features/features-page.html 303 From cb472c088464d03ee7e23250ae9497f58dd2a174 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Thu, 19 Sep 2024 20:28:09 +0200 Subject: [PATCH 53/78] Feature/improve ghostfolio po polsku (#3782) * Improve Ghostfolio po polsku --- apps/api/src/assets/sitemap.xml | 36 ++++++++++++++++++++++++- apps/client/src/app/app.component.html | 8 +++--- apps/client/src/locales/messages.pl.xlf | 4 +-- 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/apps/api/src/assets/sitemap.xml b/apps/api/src/assets/sitemap.xml index 860024c61..1a033a93e 100644 --- a/apps/api/src/assets/sitemap.xml +++ b/apps/api/src/assets/sitemap.xml @@ -446,12 +446,46 @@ https://ghostfol.io/nl/veelgestelde-vragen ${currentDate}T00:00:00+00:00 + + https://ghostfol.io/pl + ${currentDate}T00:00:00+00:00 + + + https://ghostfol.io/pl/blog + ${currentDate}T00:00:00+00:00 + + + https://ghostfol.io/pl/cennik + ${currentDate}T00:00:00+00:00 + + + + https://ghostfol.io/pl/funkcje + ${currentDate}T00:00:00+00:00 + + + https://ghostfol.io/pl/o-ghostfolio + ${currentDate}T00:00:00+00:00 + + + https://ghostfol.io/pl/rynki + ${currentDate}T00:00:00+00:00 + + + https://ghostfol.io/pl/zarejestruj + ${currentDate}T00:00:00+00:00 + https://ghostfol.io/pt ${currentDate}T00:00:00+00:00 diff --git a/apps/client/src/app/app.component.html b/apps/client/src/app/app.component.html index 806360c0f..db6a00e7b 100644 --- a/apps/client/src/app/app.component.html +++ b/apps/client/src/app/app.component.html @@ -168,11 +168,9 @@
  • Nederlands
  • - +
  • + Polski +
  • Português
  • diff --git a/apps/client/src/locales/messages.pl.xlf b/apps/client/src/locales/messages.pl.xlf index 717699a09..9290a4cb7 100644 --- a/apps/client/src/locales/messages.pl.xlf +++ b/apps/client/src/locales/messages.pl.xlf @@ -3,7 +3,7 @@ about - o Ghostfolio + o-ghostfolio apps/client/src/app/app.component.ts 60 @@ -119,7 +119,7 @@ features - Funkcje + funkcje apps/client/src/app/app.component.ts 68 From f0df8a5254025f8759bfb33fb80f11ee4b07be57 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Thu, 19 Sep 2024 20:54:00 +0200 Subject: [PATCH 54/78] Feature/add snake-case hint to localized routes (#3783) * Add snake-case hint to localized routes --- apps/client/src/app/app.component.ts | 28 +++++++++++-------- .../app/components/header/header.component.ts | 22 +++++++-------- ...scription-interstitial-dialog.component.ts | 2 +- .../user-account-membership.component.ts | 2 +- .../overview/about-overview-page.component.ts | 4 +-- .../hallo-ghostfolio-page.component.ts | 4 +-- .../hello-ghostfolio-page.component.ts | 4 +-- ...st-months-in-open-source-page.component.ts | 2 +- ...get-my-finances-in-order-page.component.ts | 2 +- .../500-stars-on-github-page.component.ts | 4 +-- .../black-friday-2022-page.component.ts | 4 +-- .../1000-stars-on-github-page.component.ts | 4 +-- ...otential-with-ghostfolio-page.component.ts | 4 +-- ...ploring-the-path-to-fire-page.component.ts | 2 +- ...tfolio-joins-oss-friends-page.component.ts | 5 +++- .../ghostfolio-2-page.component.ts | 11 +++++--- .../hacktoberfest-2023-page.component.ts | 2 +- .../black-week-2023-page.component.ts | 4 +-- ...oberfest-2023-debriefing-page.component.ts | 4 +-- .../overview/faq-overview-page.component.ts | 2 +- .../app/pages/faq/saas/saas-page.component.ts | 6 ++-- .../pages/features/features-page.component.ts | 4 +-- .../pages/landing/landing-page.component.ts | 4 +-- .../pages/pricing/pricing-page.component.ts | 4 +-- .../personal-finance-tools-page.component.ts | 2 +- .../product-page.component.ts | 6 ++-- .../resources/resources-page.component.ts | 4 +-- .../membership-card.component.ts | 2 +- 28 files changed, 80 insertions(+), 68 deletions(-) diff --git a/apps/client/src/app/app.component.ts b/apps/client/src/app/app.component.ts index fbc358590..44a554173 100644 --- a/apps/client/src/app/app.component.ts +++ b/apps/client/src/app/app.component.ts @@ -57,19 +57,25 @@ export class AppComponent implements OnDestroy, OnInit { public hasTabs = false; public info: InfoItem; public pageTitle: string; - public routerLinkAbout = ['/' + $localize`about`]; - public routerLinkAboutChangelog = ['/' + $localize`about`, 'changelog']; - public routerLinkAboutLicense = ['/' + $localize`about`, $localize`license`]; + public routerLinkAbout = ['/' + $localize`:snake-case:about`]; + public routerLinkAboutChangelog = [ + '/' + $localize`:snake-case:about`, + 'changelog' + ]; + public routerLinkAboutLicense = [ + '/' + $localize`:snake-case:about`, + $localize`:snake-case:license` + ]; public routerLinkAboutPrivacyPolicy = [ - '/' + $localize`about`, - $localize`privacy-policy` + '/' + $localize`:snake-case:about`, + $localize`:snake-case:privacy-policy` ]; - public routerLinkFaq = ['/' + $localize`faq`]; - public routerLinkFeatures = ['/' + $localize`features`]; - public routerLinkMarkets = ['/' + $localize`markets`]; - public routerLinkPricing = ['/' + $localize`pricing`]; - public routerLinkRegister = ['/' + $localize`register`]; - public routerLinkResources = ['/' + $localize`resources`]; + public routerLinkFaq = ['/' + $localize`:snake-case:faq`]; + public routerLinkFeatures = ['/' + $localize`:snake-case:features`]; + public routerLinkMarkets = ['/' + $localize`:snake-case:markets`]; + public routerLinkPricing = ['/' + $localize`:snake-case:pricing`]; + public routerLinkRegister = ['/' + $localize`:snake-case:register`]; + public routerLinkResources = ['/' + $localize`:snake-case:resources`]; public showFooter = false; public user: User; diff --git a/apps/client/src/app/components/header/header.component.ts b/apps/client/src/app/components/header/header.component.ts index ff126da14..8909c15a4 100644 --- a/apps/client/src/app/components/header/header.component.ts +++ b/apps/client/src/app/components/header/header.component.ts @@ -75,17 +75,17 @@ export class HeaderComponent implements OnChanges { public hasPermissionToCreateUser: boolean; public impersonationId: string; public isMenuOpen: boolean; - public routeAbout = $localize`about`; - public routeFeatures = $localize`features`; - public routeMarkets = $localize`markets`; - public routePricing = $localize`pricing`; - public routeResources = $localize`resources`; - public routerLinkAbout = ['/' + $localize`about`]; - public routerLinkFeatures = ['/' + $localize`features`]; - public routerLinkMarkets = ['/' + $localize`markets`]; - public routerLinkPricing = ['/' + $localize`pricing`]; - public routerLinkRegister = ['/' + $localize`register`]; - public routerLinkResources = ['/' + $localize`resources`]; + public routeAbout = $localize`:snake-case:about`; + public routeFeatures = $localize`:snake-case:features`; + public routeMarkets = $localize`:snake-case:markets`; + public routePricing = $localize`:snake-case:pricing`; + public routeResources = $localize`:snake-case:resources`; + public routerLinkAbout = ['/' + $localize`:snake-case:about`]; + public routerLinkFeatures = ['/' + $localize`:snake-case:features`]; + public routerLinkMarkets = ['/' + $localize`:snake-case:markets`]; + public routerLinkPricing = ['/' + $localize`:snake-case:pricing`]; + public routerLinkRegister = ['/' + $localize`:snake-case:register`]; + public routerLinkResources = ['/' + $localize`:snake-case:resources`]; private unsubscribeSubject = new Subject(); diff --git a/apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.component.ts b/apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.component.ts index b33ce30a7..fb852c920 100644 --- a/apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.component.ts +++ b/apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.component.ts @@ -11,7 +11,7 @@ import { SubscriptionInterstitialDialogParams } from './interfaces/interfaces'; templateUrl: 'subscription-interstitial-dialog.html' }) export class SubscriptionInterstitialDialog { - public routerLinkPricing = ['/' + $localize`pricing`]; + public routerLinkPricing = ['/' + $localize`:snake-case:pricing`]; public constructor( @Inject(MAT_DIALOG_DATA) public data: SubscriptionInterstitialDialogParams, diff --git a/apps/client/src/app/components/user-account-membership/user-account-membership.component.ts b/apps/client/src/app/components/user-account-membership/user-account-membership.component.ts index e21a85418..c66f555b4 100644 --- a/apps/client/src/app/components/user-account-membership/user-account-membership.component.ts +++ b/apps/client/src/app/components/user-account-membership/user-account-membership.component.ts @@ -36,7 +36,7 @@ export class UserAccountMembershipComponent implements OnDestroy, OnInit { public hasPermissionToUpdateUserSettings: boolean; public price: number; public priceId: string; - public routerLinkPricing = ['/' + $localize`pricing`]; + public routerLinkPricing = ['/' + $localize`:snake-case:pricing`]; public snackBarRef: MatSnackBarRef; public trySubscriptionMail = 'mailto:hi@ghostfol.io?Subject=Ghostfolio Premium Trial&body=Hello%0D%0DI am interested in Ghostfolio Premium. Can you please send me a coupon code to try it for some time?%0D%0DKind regards'; diff --git a/apps/client/src/app/pages/about/overview/about-overview-page.component.ts b/apps/client/src/app/pages/about/overview/about-overview-page.component.ts index c07db433a..027eb132c 100644 --- a/apps/client/src/app/pages/about/overview/about-overview-page.component.ts +++ b/apps/client/src/app/pages/about/overview/about-overview-page.component.ts @@ -16,8 +16,8 @@ export class AboutOverviewPageComponent implements OnDestroy, OnInit { public hasPermissionForStatistics: boolean; public hasPermissionForSubscription: boolean; public isLoggedIn: boolean; - public routerLinkFaq = ['/' + $localize`faq`]; - public routerLinkFeatures = ['/' + $localize`features`]; + public routerLinkFaq = ['/' + $localize`:snake-case:faq`]; + public routerLinkFeatures = ['/' + $localize`:snake-case:features`]; public user: User; private unsubscribeSubject = new Subject(); diff --git a/apps/client/src/app/pages/blog/2021/07/hallo-ghostfolio/hallo-ghostfolio-page.component.ts b/apps/client/src/app/pages/blog/2021/07/hallo-ghostfolio/hallo-ghostfolio-page.component.ts index 7947d90b1..cc37ae805 100644 --- a/apps/client/src/app/pages/blog/2021/07/hallo-ghostfolio/hallo-ghostfolio-page.component.ts +++ b/apps/client/src/app/pages/blog/2021/07/hallo-ghostfolio/hallo-ghostfolio-page.component.ts @@ -10,6 +10,6 @@ import { RouterModule } from '@angular/router'; templateUrl: './hallo-ghostfolio-page.html' }) export class HalloGhostfolioPageComponent { - public routerLinkPricing = ['/' + $localize`pricing`]; - public routerLinkResources = ['/' + $localize`resources`]; + public routerLinkPricing = ['/' + $localize`:snake-case:pricing`]; + public routerLinkResources = ['/' + $localize`:snake-case:resources`]; } diff --git a/apps/client/src/app/pages/blog/2021/07/hello-ghostfolio/hello-ghostfolio-page.component.ts b/apps/client/src/app/pages/blog/2021/07/hello-ghostfolio/hello-ghostfolio-page.component.ts index 18aceabe9..4e9943a27 100644 --- a/apps/client/src/app/pages/blog/2021/07/hello-ghostfolio/hello-ghostfolio-page.component.ts +++ b/apps/client/src/app/pages/blog/2021/07/hello-ghostfolio/hello-ghostfolio-page.component.ts @@ -10,6 +10,6 @@ import { RouterModule } from '@angular/router'; templateUrl: './hello-ghostfolio-page.html' }) export class HelloGhostfolioPageComponent { - public routerLinkPricing = ['/' + $localize`pricing`]; - public routerLinkResources = ['/' + $localize`resources`]; + public routerLinkPricing = ['/' + $localize`:snake-case:pricing`]; + public routerLinkResources = ['/' + $localize`:snake-case:resources`]; } diff --git a/apps/client/src/app/pages/blog/2022/01/first-months-in-open-source/first-months-in-open-source-page.component.ts b/apps/client/src/app/pages/blog/2022/01/first-months-in-open-source/first-months-in-open-source-page.component.ts index e6ad7e41b..b543e04f2 100644 --- a/apps/client/src/app/pages/blog/2022/01/first-months-in-open-source/first-months-in-open-source-page.component.ts +++ b/apps/client/src/app/pages/blog/2022/01/first-months-in-open-source/first-months-in-open-source-page.component.ts @@ -10,5 +10,5 @@ import { RouterModule } from '@angular/router'; templateUrl: './first-months-in-open-source-page.html' }) export class FirstMonthsInOpenSourcePageComponent { - public routerLinkPricing = ['/' + $localize`pricing`]; + public routerLinkPricing = ['/' + $localize`:snake-case:pricing`]; } 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.component.ts 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.component.ts index ccca0f27c..abbfe8e37 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.component.ts +++ 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.component.ts @@ -10,5 +10,5 @@ import { RouterModule } from '@angular/router'; templateUrl: './how-do-i-get-my-finances-in-order-page.html' }) export class HowDoIGetMyFinancesInOrderPageComponent { - public routerLinkResources = ['/' + $localize`resources`]; + public routerLinkResources = ['/' + $localize`:snake-case:resources`]; } diff --git a/apps/client/src/app/pages/blog/2022/08/500-stars-on-github/500-stars-on-github-page.component.ts b/apps/client/src/app/pages/blog/2022/08/500-stars-on-github/500-stars-on-github-page.component.ts index eec7ce255..10150cf39 100644 --- a/apps/client/src/app/pages/blog/2022/08/500-stars-on-github/500-stars-on-github-page.component.ts +++ b/apps/client/src/app/pages/blog/2022/08/500-stars-on-github/500-stars-on-github-page.component.ts @@ -10,6 +10,6 @@ import { RouterModule } from '@angular/router'; templateUrl: './500-stars-on-github-page.html' }) export class FiveHundredStarsOnGitHubPageComponent { - public routerLinkMarkets = ['/' + $localize`markets`]; - public routerLinkPricing = ['/' + $localize`pricing`]; + public routerLinkMarkets = ['/' + $localize`:snake-case:markets`]; + public routerLinkPricing = ['/' + $localize`:snake-case:pricing`]; } diff --git a/apps/client/src/app/pages/blog/2022/11/black-friday-2022/black-friday-2022-page.component.ts b/apps/client/src/app/pages/blog/2022/11/black-friday-2022/black-friday-2022-page.component.ts index 5820104d9..c31605a65 100644 --- a/apps/client/src/app/pages/blog/2022/11/black-friday-2022/black-friday-2022-page.component.ts +++ b/apps/client/src/app/pages/blog/2022/11/black-friday-2022/black-friday-2022-page.component.ts @@ -12,6 +12,6 @@ import { RouterModule } from '@angular/router'; templateUrl: './black-friday-2022-page.html' }) export class BlackFriday2022PageComponent { - public routerLinkFeatures = ['/' + $localize`features`]; - public routerLinkPricing = ['/' + $localize`pricing`]; + public routerLinkFeatures = ['/' + $localize`:snake-case:features`]; + public routerLinkPricing = ['/' + $localize`:snake-case:pricing`]; } diff --git a/apps/client/src/app/pages/blog/2023/03/1000-stars-on-github/1000-stars-on-github-page.component.ts b/apps/client/src/app/pages/blog/2023/03/1000-stars-on-github/1000-stars-on-github-page.component.ts index 55813dc29..2cb473cb9 100644 --- a/apps/client/src/app/pages/blog/2023/03/1000-stars-on-github/1000-stars-on-github-page.component.ts +++ b/apps/client/src/app/pages/blog/2023/03/1000-stars-on-github/1000-stars-on-github-page.component.ts @@ -10,6 +10,6 @@ import { RouterModule } from '@angular/router'; templateUrl: './1000-stars-on-github-page.html' }) export class ThousandStarsOnGitHubPageComponent { - public routerLinkFeatures = ['/' + $localize`features`]; - public routerLinkPricing = ['/' + $localize`pricing`]; + public routerLinkFeatures = ['/' + $localize`:snake-case:features`]; + public routerLinkPricing = ['/' + $localize`:snake-case:pricing`]; } 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 index 4e7e602a2..478312648 100644 --- 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 @@ -10,6 +10,6 @@ import { RouterModule } from '@angular/router'; templateUrl: './unlock-your-financial-potential-with-ghostfolio-page.html' }) export class UnlockYourFinancialPotentialWithGhostfolioPageComponent { - public routerLinkFeatures = ['/' + $localize`features`]; - public routerLinkResources = ['/' + $localize`resources`]; + public routerLinkFeatures = ['/' + $localize`:snake-case:features`]; + public routerLinkResources = ['/' + $localize`:snake-case:resources`]; } diff --git a/apps/client/src/app/pages/blog/2023/07/exploring-the-path-to-fire/exploring-the-path-to-fire-page.component.ts b/apps/client/src/app/pages/blog/2023/07/exploring-the-path-to-fire/exploring-the-path-to-fire-page.component.ts index aaafcfc94..a51612e47 100644 --- a/apps/client/src/app/pages/blog/2023/07/exploring-the-path-to-fire/exploring-the-path-to-fire-page.component.ts +++ b/apps/client/src/app/pages/blog/2023/07/exploring-the-path-to-fire/exploring-the-path-to-fire-page.component.ts @@ -10,5 +10,5 @@ import { RouterModule } from '@angular/router'; templateUrl: './exploring-the-path-to-fire-page.html' }) export class ExploringThePathToFirePageComponent { - public routerLinkFeatures = ['/' + $localize`features`]; + public routerLinkFeatures = ['/' + $localize`:snake-case:features`]; } diff --git a/apps/client/src/app/pages/blog/2023/08/ghostfolio-joins-oss-friends/ghostfolio-joins-oss-friends-page.component.ts b/apps/client/src/app/pages/blog/2023/08/ghostfolio-joins-oss-friends/ghostfolio-joins-oss-friends-page.component.ts index 682a1fdd8..945385eaa 100644 --- a/apps/client/src/app/pages/blog/2023/08/ghostfolio-joins-oss-friends/ghostfolio-joins-oss-friends-page.component.ts +++ b/apps/client/src/app/pages/blog/2023/08/ghostfolio-joins-oss-friends/ghostfolio-joins-oss-friends-page.component.ts @@ -10,5 +10,8 @@ import { RouterModule } from '@angular/router'; templateUrl: './ghostfolio-joins-oss-friends-page.html' }) export class GhostfolioJoinsOssFriendsPageComponent { - public routerLinkAboutOssFriends = ['/' + $localize`about`, 'oss-friends']; + public routerLinkAboutOssFriends = [ + '/' + $localize`:snake-case:about`, + 'oss-friends' + ]; } diff --git a/apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts b/apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts index 34d94857e..e6bf1a17c 100644 --- a/apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts +++ b/apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts @@ -10,8 +10,11 @@ import { RouterModule } from '@angular/router'; templateUrl: './ghostfolio-2-page.html' }) export class Ghostfolio2PageComponent { - public routerLinkAbout = ['/' + $localize`about`]; - public routerLinkAboutChangelog = ['/' + $localize`about`, 'changelog']; - public routerLinkFeatures = ['/' + $localize`features`]; - public routerLinkMarkets = ['/' + $localize`markets`]; + public routerLinkAbout = ['/' + $localize`:snake-case:about`]; + public routerLinkAboutChangelog = [ + '/' + $localize`:snake-case:about`, + 'changelog' + ]; + public routerLinkFeatures = ['/' + $localize`:snake-case:features`]; + public routerLinkMarkets = ['/' + $localize`:snake-case:markets`]; } diff --git a/apps/client/src/app/pages/blog/2023/09/hacktoberfest-2023/hacktoberfest-2023-page.component.ts b/apps/client/src/app/pages/blog/2023/09/hacktoberfest-2023/hacktoberfest-2023-page.component.ts index 614c681e8..719394fde 100644 --- a/apps/client/src/app/pages/blog/2023/09/hacktoberfest-2023/hacktoberfest-2023-page.component.ts +++ b/apps/client/src/app/pages/blog/2023/09/hacktoberfest-2023/hacktoberfest-2023-page.component.ts @@ -10,5 +10,5 @@ import { RouterModule } from '@angular/router'; templateUrl: './hacktoberfest-2023-page.html' }) export class Hacktoberfest2023PageComponent { - public routerLinkAbout = ['/' + $localize`about`]; + public routerLinkAbout = ['/' + $localize`:snake-case:about`]; } diff --git a/apps/client/src/app/pages/blog/2023/11/black-week-2023/black-week-2023-page.component.ts b/apps/client/src/app/pages/blog/2023/11/black-week-2023/black-week-2023-page.component.ts index f0c88cfd4..0c7334642 100644 --- a/apps/client/src/app/pages/blog/2023/11/black-week-2023/black-week-2023-page.component.ts +++ b/apps/client/src/app/pages/blog/2023/11/black-week-2023/black-week-2023-page.component.ts @@ -12,6 +12,6 @@ import { RouterModule } from '@angular/router'; templateUrl: './black-week-2023-page.html' }) export class BlackWeek2023PageComponent { - public routerLinkFeatures = ['/' + $localize`features`]; - public routerLinkPricing = ['/' + $localize`pricing`]; + public routerLinkFeatures = ['/' + $localize`:snake-case:features`]; + public routerLinkPricing = ['/' + $localize`:snake-case:pricing`]; } diff --git a/apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.component.ts b/apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.component.ts index a2a6ebf0b..e825ff59a 100644 --- a/apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.component.ts +++ b/apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.component.ts @@ -10,6 +10,6 @@ import { RouterModule } from '@angular/router'; templateUrl: './hacktoberfest-2023-debriefing-page.html' }) export class Hacktoberfest2023DebriefingPageComponent { - public routerLinkAbout = ['/' + $localize`about`]; - public routerLinkFeatures = ['/' + $localize`features`]; + public routerLinkAbout = ['/' + $localize`:snake-case:about`]; + public routerLinkFeatures = ['/' + $localize`:snake-case:features`]; } diff --git a/apps/client/src/app/pages/faq/overview/faq-overview-page.component.ts b/apps/client/src/app/pages/faq/overview/faq-overview-page.component.ts index f9abb8824..cb548c13b 100644 --- a/apps/client/src/app/pages/faq/overview/faq-overview-page.component.ts +++ b/apps/client/src/app/pages/faq/overview/faq-overview-page.component.ts @@ -11,7 +11,7 @@ import { Subject, takeUntil } from 'rxjs'; templateUrl: './faq-overview-page.html' }) export class FaqOverviewPageComponent implements OnDestroy { - public routerLinkFeatures = ['/' + $localize`features`]; + public routerLinkFeatures = ['/' + $localize`:snake-case:features`]; public user: User; private unsubscribeSubject = new Subject(); diff --git a/apps/client/src/app/pages/faq/saas/saas-page.component.ts b/apps/client/src/app/pages/faq/saas/saas-page.component.ts index b06a7dbd1..1d1a6dd61 100644 --- a/apps/client/src/app/pages/faq/saas/saas-page.component.ts +++ b/apps/client/src/app/pages/faq/saas/saas-page.component.ts @@ -11,9 +11,9 @@ import { Subject, takeUntil } from 'rxjs'; templateUrl: './saas-page.html' }) export class SaasPageComponent implements OnDestroy { - public routerLinkMarkets = ['/' + $localize`markets`]; - public routerLinkPricing = ['/' + $localize`pricing`]; - public routerLinkRegister = ['/' + $localize`register`]; + public routerLinkMarkets = ['/' + $localize`:snake-case:markets`]; + public routerLinkPricing = ['/' + $localize`:snake-case:pricing`]; + public routerLinkRegister = ['/' + $localize`:snake-case:register`]; public user: User; private unsubscribeSubject = new Subject(); diff --git a/apps/client/src/app/pages/features/features-page.component.ts b/apps/client/src/app/pages/features/features-page.component.ts index 39ed6d38e..df2e5e520 100644 --- a/apps/client/src/app/pages/features/features-page.component.ts +++ b/apps/client/src/app/pages/features/features-page.component.ts @@ -26,8 +26,8 @@ import { Subject, takeUntil } from 'rxjs'; export class GfFeaturesPageComponent implements OnDestroy { public hasPermissionForSubscription: boolean; public info: InfoItem; - public routerLinkRegister = ['/' + $localize`register`]; - public routerLinkResources = ['/' + $localize`resources`]; + public routerLinkRegister = ['/' + $localize`:snake-case:register`]; + public routerLinkResources = ['/' + $localize`:snake-case:resources`]; public user: User; private unsubscribeSubject = new Subject(); 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 ca8c0b420..3f9e45b94 100644 --- a/apps/client/src/app/pages/landing/landing-page.component.ts +++ b/apps/client/src/app/pages/landing/landing-page.component.ts @@ -23,8 +23,8 @@ export class LandingPageComponent implements OnDestroy, OnInit { public hasPermissionForStatistics: boolean; public hasPermissionForSubscription: boolean; public hasPermissionToCreateUser: boolean; - public routerLinkAbout = ['/' + $localize`about`]; - public routerLinkRegister = ['/' + $localize`register`]; + public routerLinkAbout = ['/' + $localize`:snake-case:about`]; + public routerLinkRegister = ['/' + $localize`:snake-case:register`]; public statistics: Statistics; public testimonials = [ { diff --git a/apps/client/src/app/pages/pricing/pricing-page.component.ts b/apps/client/src/app/pages/pricing/pricing-page.component.ts index b366f3d63..9eb0cf491 100644 --- a/apps/client/src/app/pages/pricing/pricing-page.component.ts +++ b/apps/client/src/app/pages/pricing/pricing-page.component.ts @@ -33,8 +33,8 @@ export class PricingPageComponent implements OnDestroy, OnInit { public isLoggedIn: boolean; public price: number; public priceId: string; - public routerLinkFeatures = ['/' + $localize`features`]; - public routerLinkRegister = ['/' + $localize`register`]; + public routerLinkFeatures = ['/' + $localize`:snake-case:features`]; + public routerLinkRegister = ['/' + $localize`:snake-case:register`]; public user: User; private unsubscribeSubject = new Subject(); diff --git a/apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.component.ts b/apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.component.ts index 596ac310e..6dfbe8a88 100644 --- a/apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.component.ts +++ b/apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.component.ts @@ -15,7 +15,7 @@ export class PersonalFinanceToolsPageComponent implements OnDestroy { public personalFinanceTools = personalFinanceTools.sort((a, b) => { return a.name.localeCompare(b.name, undefined, { sensitivity: 'base' }); }); - public routerLinkAbout = ['/' + $localize`about`]; + public routerLinkAbout = ['/' + $localize`:snake-case:about`]; private unsubscribeSubject = new Subject(); diff --git a/apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts b/apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts index 76fe7eb97..ea14bbc6b 100644 --- a/apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts +++ b/apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -21,10 +21,10 @@ export class GfProductPageComponent implements OnInit { public price: number; public product1: Product; public product2: Product; - public routerLinkAbout = ['/' + $localize`about`]; - public routerLinkFeatures = ['/' + $localize`features`]; + public routerLinkAbout = ['/' + $localize`:snake-case:about`]; + public routerLinkFeatures = ['/' + $localize`:snake-case:features`]; public routerLinkResourcesPersonalFinanceTools = [ - '/' + $localize`resources`, + '/' + $localize`:snake-case:resources`, 'personal-finance-tools' ]; public tags: string[]; diff --git a/apps/client/src/app/pages/resources/resources-page.component.ts b/apps/client/src/app/pages/resources/resources-page.component.ts index 23c5bf5eb..51172c0de 100644 --- a/apps/client/src/app/pages/resources/resources-page.component.ts +++ b/apps/client/src/app/pages/resources/resources-page.component.ts @@ -14,9 +14,9 @@ import { Subject } from 'rxjs'; export class ResourcesPageComponent implements OnInit { public hasPermissionForSubscription: boolean; public info: InfoItem; - public routerLinkFaq = ['/' + $localize`faq`]; + public routerLinkFaq = ['/' + $localize`:snake-case:faq`]; public routerLinkResourcesPersonalFinanceTools = [ - '/' + $localize`resources`, + '/' + $localize`:snake-case:resources`, 'personal-finance-tools' ]; diff --git a/libs/ui/src/lib/membership-card/membership-card.component.ts b/libs/ui/src/lib/membership-card/membership-card.component.ts index f82dee3f1..b19072946 100644 --- a/libs/ui/src/lib/membership-card/membership-card.component.ts +++ b/libs/ui/src/lib/membership-card/membership-card.component.ts @@ -22,5 +22,5 @@ export class GfMembershipCardComponent { @Input() public expiresAt: string; @Input() public name: string; - public routerLinkPricing = ['/' + $localize`pricing`]; + public routerLinkPricing = ['/' + $localize`:snake-case:pricing`]; } From 2bd14b135c5889ba5cbe1b0873da06a2795b44ca Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Thu, 19 Sep 2024 21:30:49 +0200 Subject: [PATCH 55/78] Feature/extract locales 20240919 (#3785) --- apps/client/src/locales/messages.ca.xlf | 41 +++++++++++++++---------- apps/client/src/locales/messages.de.xlf | 41 +++++++++++++++---------- apps/client/src/locales/messages.es.xlf | 41 +++++++++++++++---------- apps/client/src/locales/messages.fr.xlf | 41 +++++++++++++++---------- apps/client/src/locales/messages.it.xlf | 41 +++++++++++++++---------- apps/client/src/locales/messages.nl.xlf | 41 +++++++++++++++---------- apps/client/src/locales/messages.pl.xlf | 41 +++++++++++++++---------- apps/client/src/locales/messages.pt.xlf | 41 +++++++++++++++---------- apps/client/src/locales/messages.tr.xlf | 41 +++++++++++++++---------- apps/client/src/locales/messages.xlf | 41 +++++++++++++++---------- apps/client/src/locales/messages.zh.xlf | 41 +++++++++++++++---------- 11 files changed, 275 insertions(+), 176 deletions(-) diff --git a/apps/client/src/locales/messages.ca.xlf b/apps/client/src/locales/messages.ca.xlf index eb370f7e5..7646af290 100644 --- a/apps/client/src/locales/messages.ca.xlf +++ b/apps/client/src/locales/messages.ca.xlf @@ -346,27 +346,28 @@ El risc d’assumir pèrdues en les inversions és substancial. No és recomanable invertir diners que pugui necessitar a curt termini. apps/client/src/app/app.component.html - 199 + 197 about sobre + snake-case apps/client/src/app/app.component.ts 60 apps/client/src/app/app.component.ts - 61 + 62 apps/client/src/app/app.component.ts - 62 + 66 apps/client/src/app/app.component.ts - 64 + 70 apps/client/src/app/components/header/header.component.ts @@ -402,7 +403,7 @@ apps/client/src/app/pages/blog/2023/08/ghostfolio-joins-oss-friends/ghostfolio-joins-oss-friends-page.component.ts - 13 + 14 apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts @@ -410,7 +411,7 @@ apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts - 14 + 15 apps/client/src/app/pages/blog/2023/09/hacktoberfest-2023/hacktoberfest-2023-page.component.ts @@ -436,9 +437,10 @@ license llicències + snake-case apps/client/src/app/app.component.ts - 62 + 67 apps/client/src/app/core/paths.ts @@ -452,9 +454,10 @@ privacy-policy política de privacitat + snake-case apps/client/src/app/app.component.ts - 65 + 71 apps/client/src/app/core/paths.ts @@ -468,9 +471,10 @@ faq faq + snake-case apps/client/src/app/app.component.ts - 67 + 73 apps/client/src/app/core/paths.ts @@ -500,9 +504,10 @@ features característiques + snake-case apps/client/src/app/app.component.ts - 68 + 74 apps/client/src/app/components/header/header.component.ts @@ -538,7 +543,7 @@ apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts - 15 + 18 apps/client/src/app/pages/blog/2023/11/black-week-2023/black-week-2023-page.component.ts @@ -564,9 +569,10 @@ markets mercats + snake-case apps/client/src/app/app.component.ts - 69 + 75 apps/client/src/app/components/header/header.component.ts @@ -586,7 +592,7 @@ apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts - 16 + 19 apps/client/src/app/pages/faq/saas/saas-page.component.ts @@ -596,9 +602,10 @@ pricing preu + snake-case apps/client/src/app/app.component.ts - 70 + 76 apps/client/src/app/components/header/header.component.ts @@ -664,9 +671,10 @@ register registrar-se + snake-case apps/client/src/app/app.component.ts - 71 + 77 apps/client/src/app/components/header/header.component.ts @@ -700,9 +708,10 @@ resources recursos + snake-case apps/client/src/app/app.component.ts - 72 + 78 apps/client/src/app/components/header/header.component.ts diff --git a/apps/client/src/locales/messages.de.xlf b/apps/client/src/locales/messages.de.xlf index 745e7fe84..e758fcf1d 100644 --- a/apps/client/src/locales/messages.de.xlf +++ b/apps/client/src/locales/messages.de.xlf @@ -22,7 +22,7 @@ Das Ausfallrisiko beim Börsenhandel kann erheblich sein. Es ist nicht ratsam, Geld zu investieren, welches du kurzfristig benötigst. apps/client/src/app/app.component.html - 199 + 197 @@ -5160,9 +5160,10 @@ faq haeufig-gestellte-fragen + snake-case apps/client/src/app/app.component.ts - 67 + 73 apps/client/src/app/core/paths.ts @@ -5192,9 +5193,10 @@ features features + snake-case apps/client/src/app/app.component.ts - 68 + 74 apps/client/src/app/components/header/header.component.ts @@ -5230,7 +5232,7 @@ apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts - 15 + 18 apps/client/src/app/pages/blog/2023/11/black-week-2023/black-week-2023-page.component.ts @@ -5256,21 +5258,22 @@ about ueber-uns + snake-case apps/client/src/app/app.component.ts 60 apps/client/src/app/app.component.ts - 61 + 62 apps/client/src/app/app.component.ts - 62 + 66 apps/client/src/app/app.component.ts - 64 + 70 apps/client/src/app/components/header/header.component.ts @@ -5306,7 +5309,7 @@ apps/client/src/app/pages/blog/2023/08/ghostfolio-joins-oss-friends/ghostfolio-joins-oss-friends-page.component.ts - 13 + 14 apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts @@ -5314,7 +5317,7 @@ apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts - 14 + 15 apps/client/src/app/pages/blog/2023/09/hacktoberfest-2023/hacktoberfest-2023-page.component.ts @@ -5340,9 +5343,10 @@ privacy-policy datenschutzbestimmungen + snake-case apps/client/src/app/app.component.ts - 65 + 71 apps/client/src/app/core/paths.ts @@ -5356,9 +5360,10 @@ license lizenz + snake-case apps/client/src/app/app.component.ts - 62 + 67 apps/client/src/app/core/paths.ts @@ -5372,9 +5377,10 @@ markets maerkte + snake-case apps/client/src/app/app.component.ts - 69 + 75 apps/client/src/app/components/header/header.component.ts @@ -5394,7 +5400,7 @@ apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts - 16 + 19 apps/client/src/app/pages/faq/saas/saas-page.component.ts @@ -5404,9 +5410,10 @@ pricing preise + snake-case apps/client/src/app/app.component.ts - 70 + 76 apps/client/src/app/components/header/header.component.ts @@ -5472,9 +5479,10 @@ register registrierung + snake-case apps/client/src/app/app.component.ts - 71 + 77 apps/client/src/app/components/header/header.component.ts @@ -5508,9 +5516,10 @@ resources ressourcen + snake-case apps/client/src/app/app.component.ts - 72 + 78 apps/client/src/app/components/header/header.component.ts diff --git a/apps/client/src/locales/messages.es.xlf b/apps/client/src/locales/messages.es.xlf index 60619a1ea..0be9acdd3 100644 --- a/apps/client/src/locales/messages.es.xlf +++ b/apps/client/src/locales/messages.es.xlf @@ -23,7 +23,7 @@ El riesgo de pérdida en trading puede ser sustancial. No es aconsejable invertir dinero que puedas necesitar a corto plazo. apps/client/src/app/app.component.html - 199 + 197 @@ -5161,9 +5161,10 @@ faq preguntas-mas-frecuentes + snake-case apps/client/src/app/app.component.ts - 67 + 73 apps/client/src/app/core/paths.ts @@ -5193,9 +5194,10 @@ features funcionalidades + snake-case apps/client/src/app/app.component.ts - 68 + 74 apps/client/src/app/components/header/header.component.ts @@ -5231,7 +5233,7 @@ apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts - 15 + 18 apps/client/src/app/pages/blog/2023/11/black-week-2023/black-week-2023-page.component.ts @@ -5257,21 +5259,22 @@ about sobre + snake-case apps/client/src/app/app.component.ts 60 apps/client/src/app/app.component.ts - 61 + 62 apps/client/src/app/app.component.ts - 62 + 66 apps/client/src/app/app.component.ts - 64 + 70 apps/client/src/app/components/header/header.component.ts @@ -5307,7 +5310,7 @@ apps/client/src/app/pages/blog/2023/08/ghostfolio-joins-oss-friends/ghostfolio-joins-oss-friends-page.component.ts - 13 + 14 apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts @@ -5315,7 +5318,7 @@ apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts - 14 + 15 apps/client/src/app/pages/blog/2023/09/hacktoberfest-2023/hacktoberfest-2023-page.component.ts @@ -5341,9 +5344,10 @@ privacy-policy politica-de-privacidad + snake-case apps/client/src/app/app.component.ts - 65 + 71 apps/client/src/app/core/paths.ts @@ -5357,9 +5361,10 @@ license licencia + snake-case apps/client/src/app/app.component.ts - 62 + 67 apps/client/src/app/core/paths.ts @@ -5373,9 +5378,10 @@ markets mercados + snake-case apps/client/src/app/app.component.ts - 69 + 75 apps/client/src/app/components/header/header.component.ts @@ -5395,7 +5401,7 @@ apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts - 16 + 19 apps/client/src/app/pages/faq/saas/saas-page.component.ts @@ -5405,9 +5411,10 @@ pricing precios + snake-case apps/client/src/app/app.component.ts - 70 + 76 apps/client/src/app/components/header/header.component.ts @@ -5473,9 +5480,10 @@ register registro + snake-case apps/client/src/app/app.component.ts - 71 + 77 apps/client/src/app/components/header/header.component.ts @@ -5509,9 +5517,10 @@ resources recursos + snake-case apps/client/src/app/app.component.ts - 72 + 78 apps/client/src/app/components/header/header.component.ts diff --git a/apps/client/src/locales/messages.fr.xlf b/apps/client/src/locales/messages.fr.xlf index 047e9845b..149d940df 100644 --- a/apps/client/src/locales/messages.fr.xlf +++ b/apps/client/src/locales/messages.fr.xlf @@ -6,7 +6,7 @@ Le risque de perte en investissant peut être important. Il est déconseillé d’investir de l’argent dont vous pourriez avoir besoin à court terme. apps/client/src/app/app.component.html - 199 + 197 @@ -5160,9 +5160,10 @@ faq foire-aux-questions + snake-case apps/client/src/app/app.component.ts - 67 + 73 apps/client/src/app/core/paths.ts @@ -5192,9 +5193,10 @@ features fonctionnalites + snake-case apps/client/src/app/app.component.ts - 68 + 74 apps/client/src/app/components/header/header.component.ts @@ -5230,7 +5232,7 @@ apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts - 15 + 18 apps/client/src/app/pages/blog/2023/11/black-week-2023/black-week-2023-page.component.ts @@ -5256,21 +5258,22 @@ about a-propos + snake-case apps/client/src/app/app.component.ts 60 apps/client/src/app/app.component.ts - 61 + 62 apps/client/src/app/app.component.ts - 62 + 66 apps/client/src/app/app.component.ts - 64 + 70 apps/client/src/app/components/header/header.component.ts @@ -5306,7 +5309,7 @@ apps/client/src/app/pages/blog/2023/08/ghostfolio-joins-oss-friends/ghostfolio-joins-oss-friends-page.component.ts - 13 + 14 apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts @@ -5314,7 +5317,7 @@ apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts - 14 + 15 apps/client/src/app/pages/blog/2023/09/hacktoberfest-2023/hacktoberfest-2023-page.component.ts @@ -5340,9 +5343,10 @@ privacy-policy politique-de-confidentialite + snake-case apps/client/src/app/app.component.ts - 65 + 71 apps/client/src/app/core/paths.ts @@ -5356,9 +5360,10 @@ license licence + snake-case apps/client/src/app/app.component.ts - 62 + 67 apps/client/src/app/core/paths.ts @@ -5372,9 +5377,10 @@ markets marches + snake-case apps/client/src/app/app.component.ts - 69 + 75 apps/client/src/app/components/header/header.component.ts @@ -5394,7 +5400,7 @@ apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts - 16 + 19 apps/client/src/app/pages/faq/saas/saas-page.component.ts @@ -5404,9 +5410,10 @@ pricing prix + snake-case apps/client/src/app/app.component.ts - 70 + 76 apps/client/src/app/components/header/header.component.ts @@ -5472,9 +5479,10 @@ register enregistrement + snake-case apps/client/src/app/app.component.ts - 71 + 77 apps/client/src/app/components/header/header.component.ts @@ -5508,9 +5516,10 @@ resources ressources + snake-case apps/client/src/app/app.component.ts - 72 + 78 apps/client/src/app/components/header/header.component.ts diff --git a/apps/client/src/locales/messages.it.xlf b/apps/client/src/locales/messages.it.xlf index a7b92ec50..23a2ea362 100644 --- a/apps/client/src/locales/messages.it.xlf +++ b/apps/client/src/locales/messages.it.xlf @@ -23,7 +23,7 @@ Il rischio di perdita nel trading può essere notevole. Non è consigliabile investire denaro di cui potresti avere bisogno a breve termine. apps/client/src/app/app.component.html - 199 + 197 @@ -5161,9 +5161,10 @@ faq domande-piu-frequenti + snake-case apps/client/src/app/app.component.ts - 67 + 73 apps/client/src/app/core/paths.ts @@ -5193,9 +5194,10 @@ features funzionalita + snake-case apps/client/src/app/app.component.ts - 68 + 74 apps/client/src/app/components/header/header.component.ts @@ -5231,7 +5233,7 @@ apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts - 15 + 18 apps/client/src/app/pages/blog/2023/11/black-week-2023/black-week-2023-page.component.ts @@ -5257,21 +5259,22 @@ about informazioni-su + snake-case apps/client/src/app/app.component.ts 60 apps/client/src/app/app.component.ts - 61 + 62 apps/client/src/app/app.component.ts - 62 + 66 apps/client/src/app/app.component.ts - 64 + 70 apps/client/src/app/components/header/header.component.ts @@ -5307,7 +5310,7 @@ apps/client/src/app/pages/blog/2023/08/ghostfolio-joins-oss-friends/ghostfolio-joins-oss-friends-page.component.ts - 13 + 14 apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts @@ -5315,7 +5318,7 @@ apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts - 14 + 15 apps/client/src/app/pages/blog/2023/09/hacktoberfest-2023/hacktoberfest-2023-page.component.ts @@ -5341,9 +5344,10 @@ privacy-policy informativa-sulla-privacy + snake-case apps/client/src/app/app.component.ts - 65 + 71 apps/client/src/app/core/paths.ts @@ -5357,9 +5361,10 @@ license licenza + snake-case apps/client/src/app/app.component.ts - 62 + 67 apps/client/src/app/core/paths.ts @@ -5373,9 +5378,10 @@ markets mercati + snake-case apps/client/src/app/app.component.ts - 69 + 75 apps/client/src/app/components/header/header.component.ts @@ -5395,7 +5401,7 @@ apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts - 16 + 19 apps/client/src/app/pages/faq/saas/saas-page.component.ts @@ -5405,9 +5411,10 @@ pricing prezzi + snake-case apps/client/src/app/app.component.ts - 70 + 76 apps/client/src/app/components/header/header.component.ts @@ -5473,9 +5480,10 @@ register iscrizione + snake-case apps/client/src/app/app.component.ts - 71 + 77 apps/client/src/app/components/header/header.component.ts @@ -5509,9 +5517,10 @@ resources risorse + snake-case apps/client/src/app/app.component.ts - 72 + 78 apps/client/src/app/components/header/header.component.ts diff --git a/apps/client/src/locales/messages.nl.xlf b/apps/client/src/locales/messages.nl.xlf index 8020c6f7a..a324f53e8 100644 --- a/apps/client/src/locales/messages.nl.xlf +++ b/apps/client/src/locales/messages.nl.xlf @@ -22,7 +22,7 @@ Het risico op verlies bij handelen kan aanzienlijk zijn. Het is niet aan te raden om geld te investeren dat je misschien op korte termijn nodig heeft. apps/client/src/app/app.component.html - 199 + 197 @@ -5160,9 +5160,10 @@ faq veelgestelde-vragen + snake-case apps/client/src/app/app.component.ts - 67 + 73 apps/client/src/app/core/paths.ts @@ -5192,9 +5193,10 @@ features functionaliteiten + snake-case apps/client/src/app/app.component.ts - 68 + 74 apps/client/src/app/components/header/header.component.ts @@ -5230,7 +5232,7 @@ apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts - 15 + 18 apps/client/src/app/pages/blog/2023/11/black-week-2023/black-week-2023-page.component.ts @@ -5256,21 +5258,22 @@ about over + snake-case apps/client/src/app/app.component.ts 60 apps/client/src/app/app.component.ts - 61 + 62 apps/client/src/app/app.component.ts - 62 + 66 apps/client/src/app/app.component.ts - 64 + 70 apps/client/src/app/components/header/header.component.ts @@ -5306,7 +5309,7 @@ apps/client/src/app/pages/blog/2023/08/ghostfolio-joins-oss-friends/ghostfolio-joins-oss-friends-page.component.ts - 13 + 14 apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts @@ -5314,7 +5317,7 @@ apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts - 14 + 15 apps/client/src/app/pages/blog/2023/09/hacktoberfest-2023/hacktoberfest-2023-page.component.ts @@ -5340,9 +5343,10 @@ privacy-policy privacybeleid + snake-case apps/client/src/app/app.component.ts - 65 + 71 apps/client/src/app/core/paths.ts @@ -5356,9 +5360,10 @@ license licentie + snake-case apps/client/src/app/app.component.ts - 62 + 67 apps/client/src/app/core/paths.ts @@ -5372,9 +5377,10 @@ markets markten + snake-case apps/client/src/app/app.component.ts - 69 + 75 apps/client/src/app/components/header/header.component.ts @@ -5394,7 +5400,7 @@ apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts - 16 + 19 apps/client/src/app/pages/faq/saas/saas-page.component.ts @@ -5404,9 +5410,10 @@ pricing prijzen + snake-case apps/client/src/app/app.component.ts - 70 + 76 apps/client/src/app/components/header/header.component.ts @@ -5472,9 +5479,10 @@ register registratie + snake-case apps/client/src/app/app.component.ts - 71 + 77 apps/client/src/app/components/header/header.component.ts @@ -5508,9 +5516,10 @@ resources bronnen + snake-case apps/client/src/app/app.component.ts - 72 + 78 apps/client/src/app/components/header/header.component.ts diff --git a/apps/client/src/locales/messages.pl.xlf b/apps/client/src/locales/messages.pl.xlf index 9290a4cb7..103140890 100644 --- a/apps/client/src/locales/messages.pl.xlf +++ b/apps/client/src/locales/messages.pl.xlf @@ -4,21 +4,22 @@ about o-ghostfolio + snake-case apps/client/src/app/app.component.ts 60 apps/client/src/app/app.component.ts - 61 + 62 apps/client/src/app/app.component.ts - 62 + 66 apps/client/src/app/app.component.ts - 64 + 70 apps/client/src/app/components/header/header.component.ts @@ -54,7 +55,7 @@ apps/client/src/app/pages/blog/2023/08/ghostfolio-joins-oss-friends/ghostfolio-joins-oss-friends-page.component.ts - 13 + 14 apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts @@ -62,7 +63,7 @@ apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts - 14 + 15 apps/client/src/app/pages/blog/2023/09/hacktoberfest-2023/hacktoberfest-2023-page.component.ts @@ -88,9 +89,10 @@ faq faq + snake-case apps/client/src/app/app.component.ts - 67 + 73 apps/client/src/app/core/paths.ts @@ -120,9 +122,10 @@ features funkcje + snake-case apps/client/src/app/app.component.ts - 68 + 74 apps/client/src/app/components/header/header.component.ts @@ -158,7 +161,7 @@ apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts - 15 + 18 apps/client/src/app/pages/blog/2023/11/black-week-2023/black-week-2023-page.component.ts @@ -184,9 +187,10 @@ license licencja + snake-case apps/client/src/app/app.component.ts - 62 + 67 apps/client/src/app/core/paths.ts @@ -200,9 +204,10 @@ markets rynki + snake-case apps/client/src/app/app.component.ts - 69 + 75 apps/client/src/app/components/header/header.component.ts @@ -222,7 +227,7 @@ apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts - 16 + 19 apps/client/src/app/pages/faq/saas/saas-page.component.ts @@ -232,9 +237,10 @@ pricing cennik + snake-case apps/client/src/app/app.component.ts - 70 + 76 apps/client/src/app/components/header/header.component.ts @@ -300,9 +306,10 @@ privacy-policy polityka-prywatnosci + snake-case apps/client/src/app/app.component.ts - 65 + 71 apps/client/src/app/core/paths.ts @@ -316,9 +323,10 @@ register zarejestruj + snake-case apps/client/src/app/app.component.ts - 71 + 77 apps/client/src/app/components/header/header.component.ts @@ -352,9 +360,10 @@ resources zasoby + snake-case apps/client/src/app/app.component.ts - 72 + 78 apps/client/src/app/components/header/header.component.ts @@ -718,7 +727,7 @@ Ryzyko strat na rynku może być znaczne. Nie jest zalecane inwestowanie pieniędzy, które mogą być potrzebne w krótkim okresie. apps/client/src/app/app.component.html - 199 + 197 diff --git a/apps/client/src/locales/messages.pt.xlf b/apps/client/src/locales/messages.pt.xlf index fbf05f19a..7ad18e060 100644 --- a/apps/client/src/locales/messages.pt.xlf +++ b/apps/client/src/locales/messages.pt.xlf @@ -6,7 +6,7 @@ O risco de perda em investimentos pode ser substancial. Não é aconselhável investir dinheiro que possa vir a precisar a curto prazo. apps/client/src/app/app.component.html - 199 + 197 @@ -5160,9 +5160,10 @@ faq perguntas-mais-frequentes + snake-case apps/client/src/app/app.component.ts - 67 + 73 apps/client/src/app/core/paths.ts @@ -5192,9 +5193,10 @@ features funcionalidades + snake-case apps/client/src/app/app.component.ts - 68 + 74 apps/client/src/app/components/header/header.component.ts @@ -5230,7 +5232,7 @@ apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts - 15 + 18 apps/client/src/app/pages/blog/2023/11/black-week-2023/black-week-2023-page.component.ts @@ -5256,21 +5258,22 @@ about sobre + snake-case apps/client/src/app/app.component.ts 60 apps/client/src/app/app.component.ts - 61 + 62 apps/client/src/app/app.component.ts - 62 + 66 apps/client/src/app/app.component.ts - 64 + 70 apps/client/src/app/components/header/header.component.ts @@ -5306,7 +5309,7 @@ apps/client/src/app/pages/blog/2023/08/ghostfolio-joins-oss-friends/ghostfolio-joins-oss-friends-page.component.ts - 13 + 14 apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts @@ -5314,7 +5317,7 @@ apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts - 14 + 15 apps/client/src/app/pages/blog/2023/09/hacktoberfest-2023/hacktoberfest-2023-page.component.ts @@ -5340,9 +5343,10 @@ privacy-policy politica-de-privacidade + snake-case apps/client/src/app/app.component.ts - 65 + 71 apps/client/src/app/core/paths.ts @@ -5356,9 +5360,10 @@ license licenca + snake-case apps/client/src/app/app.component.ts - 62 + 67 apps/client/src/app/core/paths.ts @@ -5372,9 +5377,10 @@ markets mercados + snake-case apps/client/src/app/app.component.ts - 69 + 75 apps/client/src/app/components/header/header.component.ts @@ -5394,7 +5400,7 @@ apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts - 16 + 19 apps/client/src/app/pages/faq/saas/saas-page.component.ts @@ -5404,9 +5410,10 @@ pricing precos + snake-case apps/client/src/app/app.component.ts - 70 + 76 apps/client/src/app/components/header/header.component.ts @@ -5472,9 +5479,10 @@ register registo + snake-case apps/client/src/app/app.component.ts - 71 + 77 apps/client/src/app/components/header/header.component.ts @@ -5508,9 +5516,10 @@ resources recursos + snake-case apps/client/src/app/app.component.ts - 72 + 78 apps/client/src/app/components/header/header.component.ts diff --git a/apps/client/src/locales/messages.tr.xlf b/apps/client/src/locales/messages.tr.xlf index a4e8eeca6..3eed053a7 100644 --- a/apps/client/src/locales/messages.tr.xlf +++ b/apps/client/src/locales/messages.tr.xlf @@ -4,21 +4,22 @@ about hakkinda + snake-case apps/client/src/app/app.component.ts 60 apps/client/src/app/app.component.ts - 61 + 62 apps/client/src/app/app.component.ts - 62 + 66 apps/client/src/app/app.component.ts - 64 + 70 apps/client/src/app/components/header/header.component.ts @@ -54,7 +55,7 @@ apps/client/src/app/pages/blog/2023/08/ghostfolio-joins-oss-friends/ghostfolio-joins-oss-friends-page.component.ts - 13 + 14 apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts @@ -62,7 +63,7 @@ apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts - 14 + 15 apps/client/src/app/pages/blog/2023/09/hacktoberfest-2023/hacktoberfest-2023-page.component.ts @@ -88,9 +89,10 @@ faq sss + snake-case apps/client/src/app/app.component.ts - 67 + 73 apps/client/src/app/core/paths.ts @@ -120,9 +122,10 @@ features oezellikler + snake-case apps/client/src/app/app.component.ts - 68 + 74 apps/client/src/app/components/header/header.component.ts @@ -158,7 +161,7 @@ apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts - 15 + 18 apps/client/src/app/pages/blog/2023/11/black-week-2023/black-week-2023-page.component.ts @@ -184,9 +187,10 @@ license lisans + snake-case apps/client/src/app/app.component.ts - 62 + 67 apps/client/src/app/core/paths.ts @@ -200,9 +204,10 @@ markets piyasalar + snake-case apps/client/src/app/app.component.ts - 69 + 75 apps/client/src/app/components/header/header.component.ts @@ -222,7 +227,7 @@ apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts - 16 + 19 apps/client/src/app/pages/faq/saas/saas-page.component.ts @@ -232,9 +237,10 @@ pricing fiyatlandirma + snake-case apps/client/src/app/app.component.ts - 70 + 76 apps/client/src/app/components/header/header.component.ts @@ -300,9 +306,10 @@ privacy-policy gizlilik-politikasi + snake-case apps/client/src/app/app.component.ts - 65 + 71 apps/client/src/app/core/paths.ts @@ -316,9 +323,10 @@ register kayit-ol + snake-case apps/client/src/app/app.component.ts - 71 + 77 apps/client/src/app/components/header/header.component.ts @@ -352,9 +360,10 @@ resources kaynaklar + snake-case apps/client/src/app/app.component.ts - 72 + 78 apps/client/src/app/components/header/header.component.ts @@ -694,7 +703,7 @@ Alım satımda kayıp riski büyük boyutta olabilir. Kısa vadede ihtiyaç duyabileceğiniz parayla yatırım yapmak tavsiye edilmez. apps/client/src/app/app.component.html - 199 + 197 diff --git a/apps/client/src/locales/messages.xlf b/apps/client/src/locales/messages.xlf index 9f1489695..10f332052 100644 --- a/apps/client/src/locales/messages.xlf +++ b/apps/client/src/locales/messages.xlf @@ -4,21 +4,22 @@ about + snake-case apps/client/src/app/app.component.ts 60 apps/client/src/app/app.component.ts - 61 + 62 apps/client/src/app/app.component.ts - 62 + 66 apps/client/src/app/app.component.ts - 64 + 70 apps/client/src/app/components/header/header.component.ts @@ -54,7 +55,7 @@ apps/client/src/app/pages/blog/2023/08/ghostfolio-joins-oss-friends/ghostfolio-joins-oss-friends-page.component.ts - 13 + 14 apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts @@ -62,7 +63,7 @@ apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts - 14 + 15 apps/client/src/app/pages/blog/2023/09/hacktoberfest-2023/hacktoberfest-2023-page.component.ts @@ -87,9 +88,10 @@ faq + snake-case apps/client/src/app/app.component.ts - 67 + 73 apps/client/src/app/core/paths.ts @@ -118,9 +120,10 @@ features + snake-case apps/client/src/app/app.component.ts - 68 + 74 apps/client/src/app/components/header/header.component.ts @@ -156,7 +159,7 @@ apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts - 15 + 18 apps/client/src/app/pages/blog/2023/11/black-week-2023/black-week-2023-page.component.ts @@ -181,9 +184,10 @@ license + snake-case apps/client/src/app/app.component.ts - 62 + 67 apps/client/src/app/core/paths.ts @@ -196,9 +200,10 @@ markets + snake-case apps/client/src/app/app.component.ts - 69 + 75 apps/client/src/app/components/header/header.component.ts @@ -218,7 +223,7 @@ apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts - 16 + 19 apps/client/src/app/pages/faq/saas/saas-page.component.ts @@ -227,9 +232,10 @@ pricing + snake-case apps/client/src/app/app.component.ts - 70 + 76 apps/client/src/app/components/header/header.component.ts @@ -294,9 +300,10 @@ privacy-policy + snake-case apps/client/src/app/app.component.ts - 65 + 71 apps/client/src/app/core/paths.ts @@ -309,9 +316,10 @@ register + snake-case apps/client/src/app/app.component.ts - 71 + 77 apps/client/src/app/components/header/header.component.ts @@ -344,9 +352,10 @@ resources + snake-case apps/client/src/app/app.component.ts - 72 + 78 apps/client/src/app/components/header/header.component.ts @@ -695,7 +704,7 @@ The risk of loss in trading can be substantial. It is not advisable to invest money you may need in the short term. apps/client/src/app/app.component.html - 199 + 197 diff --git a/apps/client/src/locales/messages.zh.xlf b/apps/client/src/locales/messages.zh.xlf index 670c37892..3a804b376 100644 --- a/apps/client/src/locales/messages.zh.xlf +++ b/apps/client/src/locales/messages.zh.xlf @@ -5,21 +5,22 @@ about 关于 + snake-case apps/client/src/app/app.component.ts 60 apps/client/src/app/app.component.ts - 61 + 62 apps/client/src/app/app.component.ts - 62 + 66 apps/client/src/app/app.component.ts - 64 + 70 apps/client/src/app/components/header/header.component.ts @@ -55,7 +56,7 @@ apps/client/src/app/pages/blog/2023/08/ghostfolio-joins-oss-friends/ghostfolio-joins-oss-friends-page.component.ts - 13 + 14 apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts @@ -63,7 +64,7 @@ apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts - 14 + 15 apps/client/src/app/pages/blog/2023/09/hacktoberfest-2023/hacktoberfest-2023-page.component.ts @@ -89,9 +90,10 @@ faq 常见问题 + snake-case apps/client/src/app/app.component.ts - 67 + 73 apps/client/src/app/core/paths.ts @@ -121,9 +123,10 @@ features 功能 + snake-case apps/client/src/app/app.component.ts - 68 + 74 apps/client/src/app/components/header/header.component.ts @@ -159,7 +162,7 @@ apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts - 15 + 18 apps/client/src/app/pages/blog/2023/11/black-week-2023/black-week-2023-page.component.ts @@ -185,9 +188,10 @@ license 许可 + snake-case apps/client/src/app/app.component.ts - 62 + 67 apps/client/src/app/core/paths.ts @@ -201,9 +205,10 @@ markets 市场 + snake-case apps/client/src/app/app.component.ts - 69 + 75 apps/client/src/app/components/header/header.component.ts @@ -223,7 +228,7 @@ apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.component.ts - 16 + 19 apps/client/src/app/pages/faq/saas/saas-page.component.ts @@ -233,9 +238,10 @@ pricing 价钱 + snake-case apps/client/src/app/app.component.ts - 70 + 76 apps/client/src/app/components/header/header.component.ts @@ -301,9 +307,10 @@ privacy-policy 隐私政策 + snake-case apps/client/src/app/app.component.ts - 65 + 71 apps/client/src/app/core/paths.ts @@ -317,9 +324,10 @@ register 注册 + snake-case apps/client/src/app/app.component.ts - 71 + 77 apps/client/src/app/components/header/header.component.ts @@ -353,9 +361,10 @@ resources 资源 + snake-case apps/client/src/app/app.component.ts - 72 + 78 apps/client/src/app/components/header/header.component.ts @@ -719,7 +728,7 @@ 交易损失的风险可能很大。不建议将短期内可能需要的资金进行投资。 apps/client/src/app/app.component.html - 199 + 197 From 3cd77523a1f777650eacf1995883200f98bbe34a Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Fri, 20 Sep 2024 11:10:19 +0200 Subject: [PATCH 56/78] Feature/improve loading indicator of accounts table (#3761) * Improve loading indicator * Update changelog --- CHANGELOG.md | 1 + .../accounts-table.component.ts | 8 +-- .../pages/accounts/accounts-page.component.ts | 67 ++++++++++++------- 3 files changed, 46 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3eccf8cb..b5a589ac6 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 +- Improved the loading indicator of the accounts table - Improved the language localization for German (`de`) - Improved the language localization for Polish (`pl`) diff --git a/apps/client/src/app/components/accounts-table/accounts-table.component.ts b/apps/client/src/app/components/accounts-table/accounts-table.component.ts index ff0358baa..afa0f1bf3 100644 --- a/apps/client/src/app/components/accounts-table/accounts-table.component.ts +++ b/apps/client/src/app/components/accounts-table/accounts-table.component.ts @@ -92,11 +92,11 @@ export class AccountsTableComponent implements OnChanges, OnDestroy, OnInit { this.isLoading = true; - if (this.accounts) { - this.dataSource = new MatTableDataSource(this.accounts); - this.dataSource.sort = this.sort; - this.dataSource.sortingDataAccessor = get; + this.dataSource = new MatTableDataSource(this.accounts); + this.dataSource.sort = this.sort; + this.dataSource.sortingDataAccessor = get; + if (this.accounts) { this.isLoading = false; } } diff --git a/apps/client/src/app/pages/accounts/accounts-page.component.ts b/apps/client/src/app/pages/accounts/accounts-page.component.ts index 3f1ed9efe..6a9ee14a4 100644 --- a/apps/client/src/app/pages/accounts/accounts-page.component.ts +++ b/apps/client/src/app/pages/accounts/accounts-page.component.ts @@ -136,18 +136,18 @@ export class AccountsPageComponent implements OnDestroy, OnInit { } public onDeleteAccount(aId: string) { + this.reset(); + this.dataService .deleteAccount(aId) .pipe(takeUntil(this.unsubscribeSubject)) - .subscribe({ - next: () => { - this.userService - .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) - .subscribe(); + .subscribe(() => { + this.userService + .get(true) + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe(); - this.fetchAccounts(); - } + this.fetchAccounts(); }); } @@ -193,19 +193,21 @@ export class AccountsPageComponent implements OnDestroy, OnInit { .pipe(takeUntil(this.unsubscribeSubject)) .subscribe((account: UpdateAccountDto | null) => { if (account) { + this.reset(); + this.dataService .putAccount(account) .pipe(takeUntil(this.unsubscribeSubject)) - .subscribe({ - next: () => { - this.userService - .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) - .subscribe(); - - this.fetchAccounts(); - } + .subscribe(() => { + this.userService + .get(true) + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe(); + + this.fetchAccounts(); }); + + this.changeDetectorRef.markForCheck(); } this.router.navigate(['.'], { relativeTo: this.route }); @@ -264,19 +266,21 @@ export class AccountsPageComponent implements OnDestroy, OnInit { .pipe(takeUntil(this.unsubscribeSubject)) .subscribe((account: CreateAccountDto | null) => { if (account) { + this.reset(); + this.dataService .postAccount(account) .pipe(takeUntil(this.unsubscribeSubject)) - .subscribe({ - next: () => { - this.userService - .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) - .subscribe(); - - this.fetchAccounts(); - } + .subscribe(() => { + this.userService + .get(true) + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe(); + + this.fetchAccounts(); }); + + this.changeDetectorRef.markForCheck(); } this.router.navigate(['.'], { relativeTo: this.route }); @@ -296,6 +300,8 @@ export class AccountsPageComponent implements OnDestroy, OnInit { .pipe(takeUntil(this.unsubscribeSubject)) .subscribe((data: any) => { if (data) { + this.reset(); + const { accountIdFrom, accountIdTo, balance }: TransferBalanceDto = data?.account; @@ -318,9 +324,18 @@ export class AccountsPageComponent implements OnDestroy, OnInit { .subscribe(() => { this.fetchAccounts(); }); + + this.changeDetectorRef.markForCheck(); } this.router.navigate(['.'], { relativeTo: this.route }); }); } + + private reset() { + this.accounts = undefined; + this.totalBalanceInBaseCurrency = 0; + this.totalValueInBaseCurrency = 0; + this.transactionCount = 0; + } } From 7761e4d7122b08bdd560a7b03b8792be515a7c63 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 21 Sep 2024 10:05:52 +0200 Subject: [PATCH 57/78] Feature/add hacktoberfest 2024 blog post (#3790) * Add blog post: Hacktoberfest 2024 * Update changelog --- CHANGELOG.md | 4 + apps/api/src/assets/sitemap.xml | 4 + .../hacktoberfest-2024-page.component.ts | 14 ++ .../hacktoberfest-2024-page.html | 200 ++++++++++++++++++ .../pages/blog/blog-page-routing.module.ts | 9 + apps/client/src/app/pages/blog/blog-page.html | 24 +++ .../assets/images/blog/hacktoberfest-2024.png | Bin 0 -> 36206 bytes 7 files changed, 255 insertions(+) create mode 100644 apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.component.ts create mode 100644 apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.html create mode 100644 apps/client/src/assets/images/blog/hacktoberfest-2024.png diff --git a/CHANGELOG.md b/CHANGELOG.md index b5a589ac6..1ae53a5fc 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 a blog post: _Hacktoberfest 2024_ + ### Changed - Improved the loading indicator of the accounts table diff --git a/apps/api/src/assets/sitemap.xml b/apps/api/src/assets/sitemap.xml index 1a033a93e..93d6b38d3 100644 --- a/apps/api/src/assets/sitemap.xml +++ b/apps/api/src/assets/sitemap.xml @@ -172,6 +172,10 @@ https://ghostfol.io/en/blog/2023/11/hacktoberfest-2023-debriefing ${currentDate}T00:00:00+00:00
    + + https://ghostfol.io/en/blog/2024/09/hacktoberfest-2024 + ${currentDate}T00:00:00+00:00 + https://ghostfol.io/en/faq ${currentDate}T00:00:00+00:00 diff --git a/apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.component.ts b/apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.component.ts new file mode 100644 index 000000000..426f32da8 --- /dev/null +++ b/apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.component.ts @@ -0,0 +1,14 @@ +import { Component } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { RouterModule } from '@angular/router'; + +@Component({ + host: { class: 'page' }, + imports: [MatButtonModule, RouterModule], + selector: 'gf-hacktoberfest-2024-page', + standalone: true, + templateUrl: './hacktoberfest-2024-page.html' +}) +export class Hacktoberfest2024PageComponent { + public routerLinkAbout = ['/' + $localize`:snake-case:about`]; +} diff --git a/apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.html b/apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.html new file mode 100644 index 000000000..5b4a0353b --- /dev/null +++ b/apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.html @@ -0,0 +1,200 @@ +
    +
    +
    +
    +
    +

    Hacktoberfest 2024

    +
    2024-09-21
    + Hacktoberfest 2024 with Ghostfolio Teaser +
    +
    +

    + At Ghostfolio, we are very + excited to join + Hacktoberfest for the + third time + and look forward to connecting with new, enthusiastic open-source + contributors. Hacktoberfest is a a month-long celebration of all + things open-source: projects, their maintainers, and the entire + community of contributors. Every October, open source maintainers + around the globe dedicate extra time to support new contributors + while guiding them through their first pull requests on + GitHub. +

    +
    +
    +

    Introducing Ghostfolio: Personal Finance Dashboard

    +

    + Ghostfolio is a modern web + application for managing personal finances. It aggregates your + assets and helps you make informed decisions to balance your + portfolio or plan future investments. +

    +

    + The software is fully written in + TypeScript and + organized as an Nx workspace, utilizing + the latest framework releases. The backend is based on + NestJS in combination with + PostgreSQL as a database + together with Prisma and + Redis for caching. The frontend is + built with Angular. +

    +

    + The OSS project counting more than 100 contributors is used daily by + its growing global community. With over + 4’000 stars on GitHub and + 800’000+ pulls on Docker Hub, + Ghostfolio has gained widespread recognition for its user-friendly + experience and simplicity. +

    +
    +
    +

    How you can make an impact

    +

    + Every contribution can make a difference. Whether it involves + implementing new features, resolving bugs, refactoring code, + enhancing documentation, adding unit tests, or translating content + into another language, you can actively shape our project. +

    +

    + Not familiar with our codebase yet? No problem! We have labeled a + few + issues + with hacktoberfest that are well suited for newcomers. +

    +

    + The official Hacktoberfest website provides some valuable + resources for beginners + to start contributing in open source. +

    +
    +
    +

    Connect with us

    +

    + If you have further questions or ideas, please join our + Slack + community or get in touch on X + @ghostfolio_. +

    +

    + We look forward to collaborating.
    + Thomas from Ghostfolio +

    +
    +
    +
      +
    • + Angular +
    • +
    • + Community +
    • +
    • + Docker +
    • +
    • + Finance +
    • +
    • + Fintech +
    • +
    • + Ghostfolio +
    • +
    • + GitHub +
    • +
    • + Hacktoberfest +
    • +
    • + Hacktoberfest 2024 +
    • +
    • + Investment +
    • +
    • + NestJS +
    • +
    • + Nx +
    • +
    • + October +
    • +
    • + Open Source +
    • +
    • + OSS +
    • +
    • + Personal Finance +
    • +
    • + Portfolio +
    • +
    • + Portfolio Tracker +
    • +
    • + Prisma +
    • +
    • + Software +
    • +
    • + TypeScript +
    • +
    • + UX +
    • +
    • + Wealth +
    • +
    • + Wealth Management +
    • +
    • + Web3 +
    • +
    • + Web 3.0 +
    • +
    +
    + +
    +
    +
    +
    diff --git a/apps/client/src/app/pages/blog/blog-page-routing.module.ts b/apps/client/src/app/pages/blog/blog-page-routing.module.ts index 47bf7cafc..3c28543ea 100644 --- a/apps/client/src/app/pages/blog/blog-page-routing.module.ts +++ b/apps/client/src/app/pages/blog/blog-page-routing.module.ts @@ -182,6 +182,15 @@ const routes: Routes = [ (c) => c.BlackWeek2023PageComponent ), title: 'Black Week 2023' + }, + { + canActivate: [AuthGuard], + path: '2024/09/hacktoberfest-2024', + loadComponent: () => + import( + './2024/09/hacktoberfest-2024/hacktoberfest-2024-page.component' + ).then((c) => c.Hacktoberfest2024PageComponent), + title: 'Hacktoberfest 2024' } ]; diff --git a/apps/client/src/app/pages/blog/blog-page.html b/apps/client/src/app/pages/blog/blog-page.html index aa139f68e..f5a4b22fd 100644 --- a/apps/client/src/app/pages/blog/blog-page.html +++ b/apps/client/src/app/pages/blog/blog-page.html @@ -8,6 +8,30 @@ finance + + + + + @if (hasPermissionForSubscription) { diff --git a/apps/client/src/assets/images/blog/hacktoberfest-2024.png b/apps/client/src/assets/images/blog/hacktoberfest-2024.png new file mode 100644 index 0000000000000000000000000000000000000000..db943e7cae56762054c45da009e1960d708d9d3e GIT binary patch literal 36206 zcmeFZcT`i`+BeGH?kx%eDpI8CRzNyPZ^4ZP>Ag4Uz4s8v_FzCjKt*~x^cs3KK!gZL z@11~vgc@3a5JHk~arSxd7@q&`KX<%m+>bFB!Iik?nsYw$nZNSP#OP|P($TQdP*G9Q zsl9xrPen!DMn!dn=Gw2om2~&YSm5Ose|=SzU*`IRpuj(_`@A&sr=p@|y!`!zDkF=P ziYlH_?b)A(Az8cV(DxoQ;oPSk&3Mly8Jw}lZ@=8Ucm4Lg&Ttk-y-yzI`49W+>}wqq zeC2$f`|=o7smmGpCLigLUuLOyinv+{SM}xcLt7bW~J-socMnapm%_FXDM} zm#$Iz`TJDWT)!3OSf8 zx?$7{Nh^i8#>m5!GXf|}Q(v7eScWZl`V<*)b55_<*~EiI!Dj1N1YeNhb|-bIK};@d z7vkkDpE10wYhH>hT>^*JQ#_y)_v|gP{4$k1(vymy+Ryl8ZRNe)aktNBy3=|@8-=$X zt=4{@?j&K_u`OZGR_qDQ+4g4+j&Ub5wBL4JnT0*y9PG&XjugAaO3`&;|FDi-nzPCFWMXI9Xk zx_)C55D1v@ac{v>XD=C)ICjay)M<;7n}uPmPCNDswjnWY6n2k$hXo zfVXuy+8j;T^)mgvyMb}oYh6dEWXgfKrtpE2Nx*+SdmvJf)GoT0c&an-*>S}P+oN<6 zsfr-lEG3#h{80kV^TSvPCPnsPRGXtSaU+jcc2(%!To;`D;`QV9=CYBYsop*WEK{7_ z@KL0r$*R4G%|@?rp?tvGN}UGgPVo!pX!g2p5hby2x(7njUQy9h$Qxm?X&w#n_1quG z9&VT&Ue5fRnAf)wj| zU2}nW`ks*sn~`owrqd7&Z_69(d3zG1(GBq!i?hA?YPaZE8tm5}G3!%DbNEW*;ZJ-? zuA8`;{#-RgvVD8qP2Z6Izpm~vpESR zJKT%%kRJz<4=1N+lSeo5=23H=5e|X@Gq~_)>7#mB>aHRgrI14QShu~P@(sZOZyOqm zxh)?sNk;nfGIkhk=-3E3WD$Aulm=z^C^GFmk7~s}XyP;SZq=&Tg%`xfeJ_?~W?&m( zvK{OsV^DpORPo{dz!0`8SFZUur5lJcm$1q3aw6IWyiEY*PwZTbJr!DQzV5u}u4vd6_K=G@y86Z{TWVO_dJknzf8E=Ko)O(@+bqC-Ts=8NvQ?icdg?{Z1&1JQ}Y%JdsN z@WNE`IBa?#a|L(W8{9P`6Krs@;O-3dgZt`)w?PAf5{IBcLkRX}QsZ0|MS(KGC|<8A z+h{=^?=Jkf3k{{r*(8`ZFOp}xJQuUI=ss{7d9a}F!-_wu98E5Rd3i&Wi;yn}-7}(Z7}$}4=2!i{!?a!Kf9y63;WpGvVq_s45R4BO=UZF%wZ%!)6h&<9A>9Msw5-vR2L%N`8nSZQL!$;ZKwd=g1gXS0VVDx&-27Xy?eAGI47Gn0CNIS}BBb?Xd=BG} z$Kg`{Jb^f3AAO-?Cl4`r26o6%;$wBQSfFH;($bo`Wikn!)(~)FC1`f{PH_QN?*|6A z8#coxS`{5Te}3k*v6KC6IrK+&nVD`&Mu*+c|{PEW^N+15M@1_c5D<91u_RI+!AiuLk;`z?FP1{Xv ze~4_vUTSq#l+E^?ovm)9&q@foj?y?>55*rXYQf63FGjLyH4?UbZW~_{XE2qtnQy}) zTLUf#2;}jPMH$h0RU)@rbcLu|5~`Oz_uOJ+IQ(TNCk5qs!ZOtrjTYU5#byv|_m2Fw zfaXFLCnca8t!W8v=;eMDoc`nayGlg7NHCIkL0K%B6|z33Wy!!h?WAOn>{$_dO)eu+ zs3T})l{msucd~N~v}riFB;av(nEb>1ObnrSxOgEWuy?laU9oIN8&{UCgS94<;6x9o zI#hv}^f(NpwM|y$)R6&koc!iB+bh!X84V7_9ULx^O%zaYVDHT3Z?>6pTQXQC>O1cX z5Ze3YLn(cRiwjJid(`>F6CI_tK8Sgm4M;9!(7h=vk|1>uxjY%{vQ~=9hA40l^ zv3j(!o3dPI>QS60`!st5`VywHR&_qk&a9d}1|)#!1ymQ#1_Nuz5oz}o=P=zY8lF)o z`LS^^H1@~4v-M`y_GyuOS6Mnbna*uiwPcP3&C_XRM{UT^s*ZdR zZjTV>XOe~nm*6#@`MhV&5OoET*-q&Rv_4dQi8DaHanCzDbi)su;6^#RM{Jzt)9EHn zPVi4|0BM~$vwH{GI!4&;40yb6l;m*z1eU9yuz1&sz&E4ax34&E4n7>otzOo%pnS*d zITtJqjD`4;fQX@!P%%x0$q8ag=NX!ep$?8UQuE~5;T8K4sG^mux`qjKSCce+-q}nq z9pUW07seN=PJ>Nt9wtw2H{_D8@nh)2Pm2*IjV2K;t@wcb`Rb~~pg)|_EAxkqhE2Ni z&*!Tx6U$0#N#_iVr^J?#1sFEAH?qEA8jrh?Ie3EMgyuX_*P;F&Os!d*!APrEy zZ##%lgbd6@vcvYx*PfqXM|Qo!1H#6YerGf;Ev25{i13r*7;LmzkPSIAypWZ;vq8vJ zVn2Os`#P93BV#8}?$_jZ%4aNCv5p?uk4CEw&djvb2knJ#jGOxrxUJ(MwM_qwSoND3 zcG?YlYJOIOFCwW0KZZV4%ZqS_M>xari~po}cyo*y)|yqKjo~@f9H4ou&0S5t2|}jZ z9Sc!!-sD2OLp9z5x);bKe~a>uqbllpSENX(K`TAHEAq~+*&d@fUN2;-O*2@s@G0ralCbUJ+K$UL+`W*f40@6+ZY_ThSAgepA99eXfV zd7~HwtZ&hjZPD`Nlz|m+46s1-;6#hOxGp2bS=M2+w!XSR#X68bS5C!_35Ci~U*7JA zmZC)x>*RV8su%HLMuT)}?g;0w(M$GE#wf-2`S=}RQDei8%F7znTO8_Q&(HrHJh?4U z9vWN#t{q1#GK6y(=*iJIj$xY*x3#m&j ztlRz+4PuF7N?9@1q^YasW)Dv6L9ZlJPic{iP}KbZJPv{81B;tzJvv!$7Kv|)QpiQK za}O@-<$+L_fwzQ||CaLP7Naq%b;?qMX}d0(wCIH|v%YV)EhwBk3~W!jG!=E)c!XX! zmvL|$LnCp9+SZA?azr`gsx9dfAn}f3mzU$y9aWygm{d$dPjj}M!$EI1aej42r$zb| z4LCwO*ry|=`Ix2G?g6cOnNx?gEc&n0(5 zBQ@=p`!|9Ch_7A&0Q4r*#|M~Fs)Xx9ud}j=Ta9-0te{=WpUwb(Xm zi@{Ynfkq8?=(%QTY3GUUY%l%v#`0~^w(==(s9?aPk9z|-lU-c3@i+?BgEsSPCbp9H z7;*dZD!*ir`ld#4wg&AdVGH7&?&}^rmfZkYoae+w1XV)=$q6*<yyf#5*N67{8eUv8WI;?adk*vVTnlcBx}_Jf zS$b}D(vbBgVg4c;4vdfSQmZAxkS;vpEF>5&5$4}}a|PV@_^rm&R>0?z57@NFrPkjB z1mJ~vR861`i56+7LFjd>_Os&ddC#fB_W`-Po=`h-ERD)tp|)ZxM3M9?>uJue5-vCg zKzv8)u3JMIan)`*yc6-u^EVzC4ZdD40-)9faatWd{>uOCm_qQ-G^kJxaypd4R)UZd z2y(@a|1!U(df$AmC7nc={v(fY555~yqrV`~we^EnRi+3dyjz(*$<&@B~x zO~f)biZ+y7!7E(ZK`bp$2?s5;UnEvv!V#Equn6LVbVfi&XbYL0-GAh9o~$=XF!iIl zd75S}G0eoyDZMBA#D8BQb9%zp8G<#ba+YDmFoF5+7~R*R?+EoF*;MOb+WAtAC;XKg zQ?yKNU*oBXGth8ydV5fqCl>82z#@=@I-K$e(iwyXohZ1mEJHzqkCP6M(~%_0L7}9A zIHXUWZ||7Dw9O)tY{BlYO0Y%y?X|nx?$JtxVz10FbSP2GYkl#0&yB{%P7k)LEAgVL zXi(qtNBcfO@nH!9+qkeDWc%HTc`PzS!?j3qPcullnMJ}D7B~r04y)4DEJpPiP>A*7 z&FlcltU0er9yK)8wjm~;q!BeYmV=uJbxvnBI3gkw$=>+eud=+7)P6yyN)_GRcBZq~ z2q)1n2S4i~W8bZzxb?=PA3nF4C&bzF&a+Qo)E3<@d~3uP2|u(4BbjXDTh7kAYZ|#c z=w$v#fp@=PlQx8>HrBnx#S!%q88Ib?`CwD`l$5wN(&33s9F5NcUdE!@1%?Gv(#Zh4 zx8v&aR2~HY;GhalXa6~fCpEQ3$%1$&;VMjLK_V&7CWbaOkot{@OmJ7*dF12Sb2I^! z@%?PCD*%B0z&_&Ndsj`)jMl{WffD@?F?D0P{Zp!jhPRo3sM9ZVODsSGiGU)3ZfVX* z8AtJbwk?sNJm^ugJ(Qx2Pn|@~1?KKzA#TBYPX$DiyJk!fjna3uP{R^V?pAK8#!v{) z?szY{4-?(=f_RJRLWAIbqr2A(#|U%4-nl(qWWc&+j2H7HZv z4Ov`@kQ%}V_{wyfiI%x3A+NHu*!F8!L)d!m2=HX{I+acP-dfQ~r0RfwVY0XN4Z5Gt z$o}ieerY8+q;)~@VB~i2hS93kih)>_iNV!b zAESLx!82{u9|~dFI(uF(gkFz>*@C!-h#9sVEfx_=Y{S# z4mIMluA{8>{V3&2rj&{TZr556ob$3~8n zn551I+{v&jVFe=W+16s+s(U>=;s9Ryrl`%*4ViEBh%XNnc1uQ)Ms-Yw*cmk2;iTNE z#OZDSh{LgEU7|?$3YsrWoXN;sKv;2Bps;V{L3FL?glUDO%~DzbUv@R;*N&X^^`V*) z8ZGSCuM?_?K2H0!awgaanJ}Z5gCkjq)^GGhr8Tm>IiGSyY+fIE$|2KQupe?29vx-S&L^k<9qp;Ftye88l)#A;yeHdZ3Z$))Isbx2X5jRe0_ zp2Ls*&Wa6zypdjF0a|odmFxq$<1E|T+1S~MiZ1yPjmwi=sCLtehV7#Nyv4*c=~Wh0 zyxlxQ%^uk<8fdpy5_Mj=q;CZ#sg#ajb)J#F3aGkDS%Fb1*y(xljQocpu5&ja0lD&^ z$zQcK6~h-Nj}}t-(1$(IO?LUY4Ov2ML3t5jo-Gpd1P71Y>UQVGHp6-1c*GC7M6tB$ zHhZ~B`L1#yj9yfiUe0Bj^0~hcEn<|jZRGyu#mdke&CZ>roFl@4M$tRotm>>8pCv6W zEha{@BzUt@`Xq{iTz3lelxqbzj3)aTM0JQ001xe{WP1ACF)_T&DG$mMw)1jOfuY{U z@S$VHgz7{}RlYnv&y@UEjU0bgjv{ZLz`Z~H7F?ah> zzO26?vY_drsi>x6o-pa4 zwzCeCcQ1zo1g*JxX=Nuc5o#d{0zwviksQN&$3cc%=~gY)bvBwCrdea0$=O!?K)7gj z5cV_sEAstzacxzrh3``)DhvJ~7r!ynkjt^M4vz>3f^|uzR>+QYwq-daGUetU-qXO* zCaHLZ=QwqzTYVebVEx>F6HJ<1^b+Do3@L(ibovCTnZG3n>X1>zT}B*G8)*fE-|hK6 zTMiK(SGm6R-MX!oG}T-_0LToN7&E&2E&WJk2dJ%XP;7 z2ne!OOx(vU7WUd3-pAnIE+;uZ=Nx%lvf8w(X{;BiMxSaO!DRHUdgQ4ib1cEKJCqJX z)%(BR1$f=Y11n4e_*B=!#Gd}X07+p@oNW2%=235VW{Hz2oBuFN6Nl6W2OL-$X zM3AG}XA;%LKr~p=10d*(FSoc~&1YU-z#=)`pEVk{TY8bv-z@9zx)C5>#AKw++dg5W zxAMNO`-OI7sEBi_l(B-qut5-0w6cHMqrd(EXw+7u1andq*i;z{@sn{nNh(xZs{)gT z!4x;jfdbmsSuxn4+o{&q84fNBI-9k{$5?B&F)?Rocw67#?z(@Hvp0m+)-@LrRve|T z_}pH-+nZ%I3Ro22GI^|4vvMnAz2*()nGm%CaL4W8D&jL4%zJg(?&&LV{eoG-`Jel( z5rzhFMcp$ZcY0QK^98m81g7KSye+SVrJ=kzUj!LC!pGZ?W~`d09pim@`G9VY?z_Y) z0s_Io>T9=j|pJQ7VkMUHRTZ~|Jkt~I}Cn>^x}z9Wz|DiuJ} z&MYD+7!7t5TyMjIIuBu&P)>Rx*f1Sl4m~*dQ&VBRTYoJF>{=FZ(@Jj&2S7$Oo;l(L z*~guA#*ioLyH9uvv51rw^wDp;18F2@vZb`3d^Y{3gKv~Z^`ubLj^j-;J@@rfL5n`g zEl9xxl6lGytKUf4Hcn$ZH@Ry2HI6?@EPC3jqN>eb&JY76&OeZyQ`}b9C5Ye856+R+ ziLLKZGA&1^>pgMq3%T=j^-l-y!yaE#HF8Up1~uHpRHhZHG*^?#rutm`*12smj~`46 zuk0>0-H|WHJ3xtR3u`UnwkK$36;)620u~^-_VZ;~g1Mv#_dG6u9WctZN$$A`A;VqU zWG<83kAu3i`Jl8pgwDw{)L#NHOEPi*8)6h}iG}V3j!bQ>yw3f>vpnfa%=ZIJIkXErN}=;m zPsSo9=YHW}%(x<_fE!-lUHPiAa)4+@^P9#Y*7y~MNMG)2ipr?_DVe}4wP&$*LV9&kcevP67I_Z7SsJeOb z*>J=&70!;%xP7FLMBFV!vr81|tWkk;mrmbt|DG`)A{y47uOGl!su5U9tG#)uEdafyjmwA_xczf6AS*S%Ij>*R)_) zrJ)Mj+j>DmXD<4R>0R$XkcD#f}#@40lL<^Jey3}*nVW^&1CF2;B9uJV9Lii4ZVs^ zgE}eWJL;$E*AHwd?9>a~nNTt6Gp;uVR24ZT1p>W*X9NBJ+XlItrrB38L z&5518Rs;h~V4ihJq2hW~-Uq*yZNt>phQVyi6KLPrB0yMIjoa$6idT8e>Gkduxs*=P z%Pt&+s1*cR2tx*QR^MIo(J84}@m`#`#{EK}06n7mJS*>;dvjE5MpXRh_j#W^)xeK_ zbr;h`Ys<}hy+($vwRcWc=Bk4kda{AsmlH_mcvB=@=u1238ef{mbGj=8p1!>JTLMb`}E@=?{9RcG^*#J+cdHKVQ_6>YB4E=Phz*kz0%lt3&|87b_#p zgv!33@-bo2_k}ECbR*f{>~S4&3!MfJblob=FQ3yHz$2%xn+z>#C7YlIzLk`)*i2Z5lyYwS*MN2bA%wic?k{5mxEO$MYcKe&!~)su zfAH-BUlVt7+y(Uo4c*S{nqsI_MW4!sU4(?xLc@KqSM+|_8_#5UD*lEcub}IC&tk^V z5kA#n?cg#eR%INe`vnDQ6bXGH`569XVJ(nNk=XcXmq#=d)$GMBzto`7@HW3OxPz&PSb8XGFN5ks}D+gmJc;YYx(JppT1<0GeI!X}G+3CtOGFy4|#>~KKCbK(> z;KbfTNbm<8!CaL~*Unc}nsYzAwH`NzCOD_7pGHR39AzcY0>X_F?-o63e;Z-kpF&(-8xhvWN?OK&tOOGBT->MaO)MLlsSRw*>8YiVzz!08mH?BC?q#KF5-L%#0b z*1Aw;U7kaV0Ti%ygY_fjHa48bD5iZVxjEX=`TlXx^u{fTu$DI{7zd{Ok}8Rm|MD++ zl8N2bl^@Z^&FDXp;l>2m2{munxZl}ZUt|}W85FG_eV@Na7LEYi@P}GgGg04)yMk)L zRku$GE5ALkakn=AHtf|V!{#-D993inRz49(fQPn=b49QtbDmxMuvB8LH@7zJ+=HG- zwI3RC+VK8X_1PS{X?sBd$=ew;@o!e&L68o{dK&9}E3&-Ta-^n2Qj8M>$`xWla|2tf z`{Rll^ln_y_>ozVq_5v@ntj|;kUjRWN;Z)QS-k5U*4FY^R5+!7peTa1VAXo-W>spx zx*WX7?0GjSMcHFgaHD_1H>lu`R1kOY3-PVl+Hw7|HbWYFt3ljZZ=FVU%4zOE0RXS+ z63n@uk%Gk37PkvMfA7CTTXj?U?nQhU zZK>cg{*!t+wz{+-)Z6}c6pkSfy>cTnkvalay8cT6%`na*gnrUH+}S? zBel}!Q)YBUH9kPJuAqz62qCN);d-{W>U;{=4Jx%hXD&1DL$59WdkUYvndxheyFJck z=0&S{7!-{f%HP#2E^xJFn;1p9mj_QyYHghD7NcA@D`o*gVXnqU+DuTVaTV4YcYw$y zobM%M2uzPx=7VdUgV|sS<;5%I*JlO-ZciDgWk@9l8bWW+ZS*>daq4&vgEokaRm%-2 zZzx>BxRzMOhkb{vQtvni6Ghu0!&NEFA0KAg{ZYLt_Ii5U?tvy`;;>WJ zkAof#3h=S56n!MZN4aOYUc)Jl1NEq$Pjij;DN8kfZb&Vpi z)$UwQQJ111@f)H9!%6irG5#OA8|#IWA~0Kl2)%F`*t)xG9_!VSm1(gcw7xn3MZ`Q3 z9w-RB+c>eCf7zSudvUw8;U>LcwD=|Wm}oG&5zb|irFMT1U}gj7ir^2r)*>+FXoZ5= zbk6T@0m5X4O>r}Q5XFEl0o&e}3RbWsSO88Eds@u}rzQJWNh6OtfUIWwyW;%alj<8? zJt2F=+9iO9-H;O%Z?=g`F_Gh(9p@R1XSp)gmOAcR0s68R z!?qB~K3ae<-HsL5bt0NjqlQ)h=dHUCQfw(_A@YufI#Jcg&|D35CrNtZklaGCgx;Po zl!7noWyb5V>)9JRN@ZE`?34;d3Z2K?EH1y))#BWM(g*yZ7r>VQNTOX6WYOpw94;@k zOX(!Pda(T^W%;wAwTRZ$By8foQ?tqj6DIZa3VhTMzZJ3Jo}Koz+`7EUW{zem5b)>3 z^qrOlh*Rl68QcQwXf}g4oZkZ;V!tGFedc?w4ZK53fP1*GKB103xo< zI2FM^&FvMs4PcuEKp1B*d#=RZ_~Dm-De@`8#^bxFSK+hJD&=5>Zm>C`fVqjZ;_t%O zARTM~K;!Lh^)s<8tvXWzhQ>O{ZX6scq4p6F%AsEGc_wk?SrvxH1GeGZL15c3W`9G# ze_fyQI}-z?9joMykgh@WOP8$$g&mu1FS#NEqrYK^F1E=$lt%%v^@@%0JyXKRz1_0$ zU2xw=M5{M_QL^L$mTzw308Q7d1SVV&Ff=T)%Fr$;Xx|l?U$j`2yn#tA?>08hy0j`8 za4F2{fb}tVM?wU!gc43S65j*7t_OPptOV4Y(nO{Ll;MGoY~k*BCi9DIU;H8AO5Ht6 zFkpWIg zzPSJ|?4hQ(LheE)@x}An4^be|+`g1-pq4}V9cwh|C=ih4VFkiZfdVwN>e}9USH=9w zQ_9gRynooC@>M0HF5naKw7oWSK>1kD;+X4FrWR!7Y0${p1fn3Dz;fN0{M9d%M=(-M z2Q~-Px&2+eQVA{tUktSDG5YFcuq4&^35z%(iR_k~FO*!Dgp5Uv>q_o7McJ-{>y=z{ z?f}ZX25omu$G#HhiBQmN;2TftG9$LVgwwX%S;obPa94 zb)kBM~- zN4S2wZn}2K+?7f35&jZbzuWX=p|Tv{&|@5bcjbXEnF9%RjZ|7lY$@xB+fn1$Qkogb zDM$<*hrlg?3?`u=z1XcZYSpgmxoF_sQFzO#0&x4Yt4E-?$MAI5Z>{zW&$^T?LS%4Lewv~*59V^7L_Mk=ntS5z` z;+nm-nyg-lT}BWbFv7sPx)D5wZW+PCiUt<39Ka=)_R7!zT2E0YIBUuTZME4o_Vmui zl|8_5is&$NV=;*ckrO&NMM4a(%FJLM?7}ZAIY9#RNc`+9R-pkUF_w@}K#V5Om2fMyqEx+5H*0q6s$Juqj6KPYkhZc4y z<+(7tS5L5Hw5QP~P7QjSpr246Bj*$j0=*0W)Am#Z?F7_*6_E6P5S8joteZ4oTLG+A zdL??`W8U8Ju}qG&9F_hh$h?4-YTgYyn@Wxj#O}#vf$Q11SJ&ls8dTF=py54vx7WH` zwR)W{-hqi}N>};??3On~HYS`URR3D^r+7U%K&jYN!_BUUzzd6DcCKZ2dT=Y#k1$?` zhs&wDawa+Sw2?cJ-~1~pQ&6wt!;;ABEv$d=e@Y!FDq8iizXJx97y0QcS*Z1IeK%J= z8nVhO01BM*M%EN!S*jim6$rqS;7T34&O?MI~suBpkf<*RyTg3-6UTW+0P zbZ!M)7=P&+tDpU#@y}gCT7B|Z=c6M!jXC0Gszyqmd81_I zV+_Y$?1`N|Kn-LoTQo!^4Mep|Ce%cm$`l>>(u|D-ZN<1fZj=<1UJ z8-KCwHZT_`o?3N~y}KW;(`R=cAW)q$;dk3O{X^eNbG10ET?&$+IC97~L6x;&Rw#v8 z0}$j}n2hvF3~F3nv~xz&DNU?FD~@C^Smgp?5vWG#x-wJhS{#iBA!CPKj{}zvs4Pd|17X1J;_N9sTG`WTd3wVS{yBI$QC}MK5Z5#j?aASla zXK-(JHTOH6p@Wa9Jys_^|H$j5M~2TL7M1B3UVLJX1?r}{&E;p=01uhff205?#Az$f zHk!0YFG<{D3al3tO*I#FhpB~zENFYu#ljoYyAAY$@S~I6AfaE zoLZk{7UF5NO<4zlow4DgHtJP}L~P%^adWn-Zz}5&Gh;)7s!eq?H1dW^lE?uKGEj2P zLp9gd07!+bWU^9vi2SGd?(?`EThnW~h{Rxo&QR_mll#^xJ9AfA)Cl#m{M&TSe&>Eb zef_A0CsTXlQ4E zI`7`prC0W|F)ea;s!}lkJq?LUSGq%ZMQXSq8fpd^QmN%+4(a=Te(#;|gn`d3lj;7I z9a@wXtG-HZ@1hq_SbzoutEjviTsg>mFEDWIARbYdKtnq`EF)j=c4%#NhdFi#fT8l6 zkez!-``;pbE-RxPJKcrpXqU&xkKA6TIWX`Q=at#o2HZS(wxU(t@LmaQb}hVv{bUDS zn01F8*r?uxB~38uluSw9G1C9`>tbg04Ha(|7ImOT-}wH~@Tjk2Bcy0wEC+vSHPxa4j4l-P72av`qu12dpd5Y*3{ z7w-mg?`P+%@Q4DKcq(p6#TIl*{4u~X6xZ9xaF9hOX=PJY~9Td!}O&pP5eUetG)(F z|H!qX+&bDReW*pVH5MG4@mWy;p~A%!DB$Rv`eS0FUPF`&?mHBSQt7Za1TX->QnVLk z#nrs3y~UdB@Qd!|=~*TAtXlJ0IMcGBx%Nl(3>0xWaacs{;~BF1mxQ9^hx|oyhLe@D zv}<0wHhoE?MiHQB{VmBtN4rGqnzQ}np-p6f+r#yTboKyeR#y07tS5u0EQsxM5R1=! z5f{G}`+06p?3WRi|DL@rR3m|GkfvP{Dw*0Ys6m zTRE*?a2;TMX&?B|YWrJDg~}AtKxC%dn)#Ju_Dm8)g!9k=3Q132Gz*9KcGq_LX^Py(#4 zS%T{8d@z^J4tT9#i=|=Di)Jdo0YPS`TPzVsYK7n#&kgnbn`v3Kg|NjpUF#c~piFuEkA^iCD z2Jz;1Ui>lTaQDP!Iiw>II5*qUcYWxWd)zAiEn}B)_2v4_j4Mw-Z!kUuz;&v>81G3^ z{{@8n$_u~>rlR6|0-Q=E+{{451BI1TRN8+5XHk#tOGdM6U7l9Wq5?AQkEbs5G8va= zRAqkwj;?--9_8?oyv)EpzXA=sXULOVbh$jz`u#UR@cq9H|9?2td^a<^FAsd#quEK6 zUvX;veXY527G{FWEtG%J!M`Uck@4CPHziZY3kunIK|y|5Oj&LU*nx&`^{iulnm52L z-G~5Vfm2J%|2&2L6gwUSPmSh_R2G2qwl)j>6e;^=5G`VpO&bq>(ekI5q2vMS9ucwi zoPhbcowLNOu>E-$K3B9cE>!B#Pj{odG}oAk*d3h1S7A=tT7QZBB*P2ONFAlme;P`tWurw!Gi6m6Yto1up|t-r z1{hrr=Kb@`U`XzNJdrJkw%Tp^G_Dy?(8=HaV|H+t%q$sB3q9TCCgd>xw4T47MJ)YC zw_iekEYk}7G!h}uGu+P;`>mV%2>*|tI)0x8`t3jeBL`DvHw)=xfvkMG_q%%4k=Oym z!~{9XP&TDsQN;X_?RCgCvDp~Dgc&ow1f?7?U&Wp8XK&VS^j130iskt1+RF4^r*%*0 ztz?W60tsoUPNFO6(W zf|vIM8Y7SesLpV2^!fIZ1H5xMPXG&C1#{tQT!udcksP~Bu0Yr82$EKh3e3!D#ex-T&!k(y&> zS%Niq7SsQ=a~ULdYO?lpnS=k-6!B;Z|!0VN=U|_k(q@0GlA2S7n7;Rr#Wk+1UGcpzQ)~r}6a7w}nwG7%;|3-q~5+ zDNad~>Mwm@TAwIN|0yY2&5zuE-Q=m<7)Z*ov$EPAYXb*QY3XoUBeAMsyz|QCj-cdt zrXlXdbnmUz-PJi|?o1`6=6p{tXz*G}QwBr>xTVQqf>%pXL?E&X_zD5=u4u2x;g_1& zbB7%$vSbS#&omIeo@Dk-lQVOV=?F;#CK$7v@6{YnOjnHek{B+((Djwa~9#+X>gj+^lyj;lF$&9^|7by!Y|ohrE1 zR)Jrv^{yr5;<$FpsBI~bP5()NdLn7+v3JF^LQwUgnZ7-3J!d^G9Ou5sNA+ao-@zP^ zADZUE)l>w>MDbM*G)vBVmw=WVJvb3hj-zNMr#7)1oFAAx#r(b}5i^u)?28g(HFMMC zz%z$Niee>4{a>4cz1%wjd#9UaDmP!J2RJp^2OY4Z)sn(3NrrpW{jI9>MduDV#3gKN9VN=<;++qVz7wFd)+MTSMHHdl7U3*&&X zoFr^+9mtE5H~tI=$d?&D!!gz?`A_r~(<(oq`l9~tWU%=RCpM}jMh19dJB0iXfAAM>@W~7@g+o zV;;+U=bvW7diOZ@z0HFjr~FE%q_9Yw`~rdIrDpZs9%Af!HsCpAvN*+N4c{4?kjsqV zSH*4Kmx2*34=56Z?U9~mi+@GQ#%WhB_P09VRq`aGp6>&)^)Z!RguEdv-KkVmZ zW3#NbL_MjfZ2z4b<;N5?B^eM8^9g&2yXMj-SC19v7I4XABW1<&w{Nf3Y@DV%gEZ3) z7fK{4=j?{Ny}E$Ks7xpFWO&Q9@W@L_5mj(0&w9^Kh&t<8|&d`+57|5ljct|dXZRDgZWEAKevF6Ix zzrRcBG~G8jchZIh?e^T+uEU|*@B`uDIt)Sz*?7m>Lj&Z~%#s-pnrq;P2Gy6_KRsk} zgrv?i&+>V%%(}&ASp=)6uvFIPZF1ALpr6fCrIYRB9fqJm{0IxV(7RNrVSQe;%6i}- z#x@)(JBp(YkMkc`-1WtdLFQO)WBYP&X41|rRlfauON-N%WMCXZsVis5 zEb2qC4@@>JNme7OPQQm!ms>n#9IhPO;sc)}rPKCj z?npn*P|Yuxz!AeEp^rICH~iu-TV(+=EZPjvuz)K$v{WM0KLwm1$t9xO3XV{&6I>n# z*7-9F4V~gEaIvIeA;-q+XrqgDn2*Lz zHlpB4!=UkFM_eQh03E<0hQ;{LJV-U+6$myo-Y+Znf@>QJ`TJ~8V-}Pb(!KjL=n^m+ zJrZg1e#EgabAGLtlR*5jY1JG4?aC9OpYp8n>X@S5hnAxW>Wl~x{Pbhm^bh;lRvFcb zkowV%66$k`i@TDFUZ(9GvyUV zoOV%u<{To6aMn*xRSpuG*M5}^^sEQS$cSK@=k`kwZfyI9{dX^@<;DK08;`>%c%y6g zXDm<>8(EpB=ieqbbK|wRGjl-Vq@Fk5$ChT#o1%*Gk}oJXbfUOCR|ZqTxFPfU!!gC9 zajfbF@n~2o;O-0DOX7xnfqw`phn`AW{O4E?k*uCKV)BIVozG`!7(6W_E3;YBWLPXu z`wXE>))$6y)S+s00QV+emJH;qxn0r<55zFy&!RIM3E*>^5Z$ktc^FtP>mFy%}&5> z(9+Q{-HN%)5qfN|H|*&5IhltaW3rK>4U`fp z#&&V=`x(`f*Z;YQFTN<5NN$M!Rg$|IigTDSA!EqEp4{K;7r@Iw`Ek_er?$h1C{TXQ zl&}~PAVO&yXQ8!u%pG%z`<9#F#O&uhH}xEM@cL0)nT?G{dqHR&=x%!hT>1aB_wMmf zuI>Bql&96Rvd~J>s?c6#p)#dxdx}&Rn=xZEdHS|NNQLZcgbZs-E@zyr176@B7F5dG5c=J@;Jqbzj$co#$~L=W*S_xXq(7 za)VnseJ5GW%m2K+CE8%XP`y&sRV2RH+G5aYz67Sxqgn#+67+X2i*@*8w zx>mH6aC(nNLr?rCt*ZdA6fv^}YBXM?=ZG-Un`0Rff7HfrB1l!{>e0y;2|p_lem2~J zJA?5cn$HE}d;g&T^T0G)%AtRH5r{47>ZMrmT9z(8bj&14Q(+{;=H{UIGaQ=SWF{x~ zNO`H7@XWuq#`Oy>RvlB-aGrI^k(oLE|TE!0o}FQd z^5p(VOgy7-WQIfA%ecpF*m{$uO&EAwDRV~(^+A6=4b)eRz6J0nX&wE(M_CMwaA-o3 zPI(imb7ix3xL+618C-S_FB#h^jaD%?nO%_iKL3_`8{Kb%uW#6-hV&u7Nr_|JGMMq$QrohyL%_8?*Oc;IhNe&$jK1aqx%<4*YI$hsVlJZ=9r|Jr*m72ly?3$5v4jgrBg>6 z0#7hx!S(?wOvaeoCWi#+^EWrE@ggc;Rk{0iR=hRLV}4KyWQ89OcjAt;Ooe>1JMVre zwB4hycz=_bJ=oAIMX7e&dM0`09pROY8n3JGEAe+fD%|ZlT9or%D{iLMHX*@l?sdp0 z?iW`GP#rPYfxc4{i#c)y^fmN`F0L->TF`gU_}PO*UVLcI5Y^43DCs(L^@z_CK3zAU zyimx3^6g zKrPUDz%^U+CRL;0#zPW*+9hdBc58ED)vJJ39tN`edPwmR5@Nw>wyZ_KQH$^uv6P?F zYyNmJOHH=YJZ_uAY`@b|w&q>3tVtodNe~rM+qYY>WGbP_b5xL1D7#zs$~#wMU@Tl_ z$0vCaH*p@FNNQR*6_)NG)f3P5E_39zrry$sq-OM_W#G_K%;Y^9N+dUHnHUMmG$1er zUb8_>w(+0^LrY7h>;t#*@GVuQwzX;tR%c@9N@+FRrvsR89Wh&c#C41Cg1_6$5>nU|s zynZp6V43}9eO|fVeNCNp!JXB?tX}6N{sHqj3A{^^_e?-Mppi2>bx`YNzYp<_Xfo}w zO0#iKWvg^h)vJVpAzTjsO}U@antMwXuq}WfVnaXve#uz7cK#%xbJz0#Ay1-{2~<=*3-Z{E@9|oHJ?THGB^JebJLHT>fE!yZf%}@qWW)XIioC zbB$2~ala*xcXnbiA1tP_^f-M(Z5&3#P4lZ(w(;@D6nNQYVhY%pJ<;lgNjd}vGv_K; zhuw|ZisMvY)U`L?8#Fo*PuiW;<$K(}oLZ%$UN2~>eAo0YNcM(ZvdX2A5RX8X!^tCP zCOm`Eh`oeK#fo9deQwE?Ui;LrQ$pgJA->7u!Boihba65DOPkj)qquuBl=91Vpq76h z7_XqKp6oU)O*Y-6RM2nJ)|sEiDwNffT@jb~lGL-QVDT`S-S1yxGSO{OI}tyO*fQIn zQI4M+X?RoRSEkRw9sw@I<5rHIx6bo0-s@VhRz-{jw`v(fE2Zy7@7yC5lT(h`vh=FC zhyx=RFgg1Q8abEPpC|^h?++%}cJ8Whuc-9AY5Q>d+Yj8TRpXIY!IaNM-oc!NK*sTn zybBr9Y=VhXae%~M^xAwLb|aBT*tS`t!P2ULO>8tLnzsLA-NX94k^JUC1=?1oSfW~I zsRDkBbZl(*y&x8&yzGfuz(>8Jm`Ig?!}7zF)2(mZlk_-~J7=gbA)H37ja3z|eD*Ta z`s^PaJp;&;zhXifew^*F%tuOgnktRDko0{xj%N74YNxan=rV64g+)5+YB1Fk+)hqB zrRcbsP83yg8_n2$%CS1Cc|aP%&?w>LTdrNiY>h5e*6=)3B`Lcv<73hada1zn;z-2} z?q;t;cpDNa>teZo^Z>Q4(=N&f5B@9P)}*&>CF=Rc?{gG7Rz5y*wzclFg5Q?=mENz1 zJwoM|StPYjHb(h(1aDNgLYtT*Rr#diJhtOy^f66|ApnHy)lkN;Y`LT&=Ro z5FPq%_CnemasQs*wm>-{U_PruGy^ML=ph&YBEVsCX>*rGy-(o(lGwW@q z=|@r88CAjxVzpUmsZ9)hcyD2gJm7}=AAk3KPM&ybxs~CQ_W@;m$WIy5&-YEox67$u6fi zs5Bd@`gVuEdy}bRm9nebbONhWv#W)BO4vkO&3w-GM|F&g7&bl57w~t7)v1Y3PN|NQ z!iD}rS9-uDEvUUV{CFOF-98*4ldC%=49yW5QyhyixE?Ni1ojYfp+4dd{Lf z*hoGq@cms?ic=95<0)7+*Oj2L-*+SX33}HGdRO>So2{5wN8;0$cdN3>H$D?ZgOQ#Ens zU2&W1Y^^JB%W&h@W*_h$jxc-Nhp4q_xEXKJu9_%i_ z9aitiLv>sgIb5K7nWzRqdmTW0a?Se&&1g1oux$!Wr?WM2Z-4hC;m_`iHsBA}_7=Ps z*!$?W{Gv|3;_f_?_g+cYcm2t*f?41iE8QzpDwT<+FTdFPn;e&Ng#t;+WuEhz&W#o~)&&r8;Bh{a;#>n+YO9ZmejS7Xd_5f|u*~bc*p$@)*Y5 zXSBzelh)qjarsfFwh}J4g(jSvT)nLDh}NpL()3M?rL{l-x>UF=Do*~Z@Swjr`d0XP zG*g6=Y70pz=5b}4Od=YK1mI?|X~Bc5XjQ`pd*)`RuG2i$@4WLa>K#MKc7$xO+H`PF9^N&P zw*Zm@={FO3jt!3Pt#-yYlD7bZXRtI&a5MipSMG!Q(UaURJ6OEA`MWI6GklJ|P{{+X zBN1nFAuiIdC!F_qa&GQtRIbsN`V&L^of~jZg{H2ZMP>b7MI@=m=U$DHV$$=8oi-N@n!s)o)~K$+rkz*I$=< zwT1Ga*QYkE>S^;Kb4guSr=q0Z5!ac5Hftia9xLB8b6>*DZ{|SHRABLiWRr?@!rC&A z{6<*YyiBP*Y~kB>AH!Qk`>V&Um^FRu9cbidX?y!Ay96a@?Vg;uF30$Dnd62`1gJ^2 zGjrzbu9}!A=!gNHSztAnoPjdhdX=w5G>jfBpriU6pijANaq2hUJCBCmDk!=#^I6Gr z@UL7}VGl$K$m3%+dHAnk<_!;2VW70)$hGJd)@zR?wz_o7=yS#g#(in+&9jF1^8R}O zeGqnqxuo173$g``0!her!YX_zjaf8#7om{>!IoF>4)bVOoy+zinieH73f615$l4u> z308`ZT*A}?Y?Y|C(`r-u1E5ng5M=lT+8#u!Ze(aZgGvbgIKD-gOY83)*V*X_l#KqS zqn2oytCR6*eOqcV_r2{Wjdr*VxW#Q!5}vT9TH_`l&M*}2OwRhb6m5TLwh~AM$Qb*G z+GmM}MtIs0Pi~sV(Qq?EZr0@zKJUOl0Hz8cU*xGIB@D-Fs`I?~6@fYD>i+NmuFs>P zSEn!NWe~zr5GLHcHbI^SLvWo-*&~>!k2Tcih!V8_>@^fG_maaXf^JhCr3 z=ufOz(;ki6oW3nIAW*M`%J-Ztfiy?T&pMYa#qTA!-J*pb=6nFWsy*GZ^o{h}P(jmK z{&l&i8xK|YT7gp-4ut#mv}^!^mT#wNMyRe=$kd!ZV1C+d#7gyuL=rHS&jFB*9{wE2 zk_qmuD%K)8+-Aul{MHY~(67f~S+!>I&CJudj;&DuJXZ&AE=@Olklj{5>{acSXm!(e zBm2N6=j0Ia+97g)XL*DY=O#O|wDK3C+dk%#jp?^pVSvb;@-p@_(ObieG!P1zD$LT| zHzi}v#)9wEnm*7{PubIL{%6PFb%wx#vDaL;`9*I?8*i#^!l5QbXvv-ym+lOHD?=Z2 z(a`_~crS%=th&F3=$l(r)@!JXs>#E@b;5x+8C4AjB6I37c{5<{ly&v^i z83t@o1XaS?7zl>isTe*-nf_$A?o3BmY^OJq*4Q%snDt^dd;k5)JG#1zITvpz=3X@x z2hTK+Np2$;&Vf5KL$j#O+ST*UH@9O>B0Yp<)9Z2|A1YK=)D?(-e(p|bku@W1Aj$(* zxT!&#uua2hvC{8GPnIV9HXxk2P(&fVP&tRQ9F`FlW+T+GC#j1+UK-LyFQ04CC6meZ%ToxGjge6Hz=q3^WTxoW`XVQe6M@*Q(S2UUamx)ZcCWX}Ez ze7RxRk0w?Kg<%nNg!lc;8VMVIGDF|lQjWPdJJ3cxE*DcY-P_`4?|^<1c=J;*debJR zoZQ^&#@XW8*#q{jp01bg-5-x0|M)%-Dy4l?Q=FyKzOx3#?YIH(H~up9E9jJUtydxH zn@iUIPZ8>fO$c%PQm+3hXKNARHE%|tHNBicJGr+0~0ANwUz(d^Feiu zkx;xh)c5n-fqTyQ<2>_(yzO^0_zCiTex%;d31;ZcWZ(>;Ot&G{rX2p$f%~718`jcg zUor|Wn(G6%f8kh!dWC0&Jay1(dIuY51neyE$Bgk#%g&f*A#*)mz^$Z)wNfH2!T|7j zG}Pw!IdWg9<=8>R|2L=zG7QTx%JKVf!FUhDx;&=iSyp2NT`C#jC&n(0NHqqBvdSyR z5Iu{-LaqXO4iRR7kZY117H>qGE>|T_t2`nO&Xkf<3o`dItNZo{rc21(g%Y;IkCnaI ztuGxTEQ4x~q`~5TNzAK|#~7lmUUX4gTKwFI9pcxpQV_XD-80!zXY8#>_@=e8j9#Xi z1CC`#g(6~if#JYU1{@%fw1tn=eR2Sw6rcYAqyRz>4?wb62v9}0?#%XM`Ls%H-NPFs zeXd#oO#8=~eKTWSHF)Ri=Ma`N)WY(^lCE^M(aF~}Rs)t(&LoFWR!?|9x`IaTq?3fd zN407HRF!Au#1$*Y5)!Xke}Yf6rV0|;x*4hW6P%@5{X91Tp~%dKxIJVQa;s_;kU(d} z7nq=haJiC%Z_CbZAdW>B|71lILNVz^@~mXbm>^k+!xTrapuX?4z+o+3aORHl*?Aj3 zO_(V+Qw^MTqcNEeBj5cBkT&InJ2rw^*WJwTg2LsNPL5L@DKrG(IAYlXiM7AcmkO}Y z`2q2|SxiQ)=$xRmqro zn3;L+7EFmTC{2Q@`pY&vo050QdfDXXp^FppT9bK|qi?xu_dnSU=$pbdcaVv*(WB{SW6upCNm9ZuvM*k@R=vn#6b|{QBXw&)uc19b z!2z<0n(`y@gXfYTMmimNjES`zLSA>Zwq%LlZNNT1T9|$)3ltB);HB%va#bFQRsDk0 z(9R=Ydkk5?3e?GrtBT(p|e(j9$CvgMFEEl^K{lyqw0y8T8iy0 zAv5f;ONgHLqr11BSv|%W*(8UW7`Q|{*8NT8(&7Y()zwS>X8uVA9H{?zIe!J2xenv|k1u3Xv8u^PEb(DF(ML z>r2II?e>_es*Ilt8f&Uinoe6kbucden8Bu~!MGS78^U-`UF?p(iFW$d`s=fjQflmk zK81JjJK7!jRePQH-=&OJx>tty3EAz8x{SKxx-Adc)g2WVx1Pt>MQYI=1D!UrcHrJ5 zUTv&T>b-5V-Lj@r8>5~&XQVY*)lAozuXRoheXnp9!s8Rg>KaAc_X2{?I57OG{qT-_9V~f>yD>B<-cDQugxwU~TH!6p*l>NEYo`ip)(gc-5K+Q+%gmte^JLVkd z+0$d*Y(J2h(Ka)66Nb6dO8jiBWvp{Tl!k`(IF-?dHt#nYfy(NM;H^9R7!g_|F`7wU%f1T_AO~EzPo47jbVpmcfELr4Ffcmf zWQE8Xzusm;^isGCg-ZHs2*pId{$qhzhKE`ty6g789tII}q8_dM(mn}~XhKmZmVF%% zEocpHvgGTK$*+%g3)n$6IyI7(=A3%0K0Gp9F~V=3?t?(%9KZ{%o>{piVyJ833ry7p zJr0Udm+HBG z;aAkPdw($vi%57^r_1Sion?c2I|B0MwY5hpPF%PFI)Xg@rh+t2vdh*G9U~IwPZ_CJ zFlj_4k(-*yI&ger6eZkh{r!)St=%_B`H8kmYw~05#T}*{VlZ=L!Xu{^6DP}eC(M)y zFQK?w7VL8vq@jUdu^i08yDibG>4Nw9ZL}BZW0o!TGa-0Ab*D99Y_P_kVy(3;JS~u6t(qKj0eUJ?9 z0ZH%v$UrbiN3E~xPYS3DLp1Fys1^~@vg63^R3n0?E3D^}n24u4OzIH8z%y!)Phc%kSCrg!e#D9LP)$ zZfBcII-m308RgCbO3he4D&Gsi+r{s{N_s_x`G%pT9X>Kw;-8whKW*d~JuWIn!Dz{u ze;RNA(W?)rAOp~wb@ z#i-}ozkkF|C?eoAF`Xg;U2wr57gxHGkbc;uv3OY*QH?QqqvmBwZ$#4x(ldg~WStb| zx8cs>^J>Ft4Bq}0YHR(!&$Aol=E^9qK$5{o$aYjfT`T|Mj6_}n?9=K|Ph<>tE{N(c zqv4n0Fx`^4UvVR?5t1f~->W22)<)*CRK|^|zBzt%bUO{PsH|_jMq#cVN8DoaK+6

    !+1ZgK?~S*y=NU(j4Z0{a?8)_#Rj%e*Ra`Ku38D#Y-!-vHVR&90bK7K88rj<})#I zjKZ`1`+KdMX?^X)Zj5%hY`=N3nk-L$vMl=3tc162j$IWwyW4yRp#BpZzx8~oDva61 zONsmgHB~Oa_1&*T*fKCrrDofG_Ca9V4-oA)h~Yt5zF^x2IJ)hw9ah8Q&vxQ3rE$3V zX6Soyl#zcLRqdXcdkOgd*@fG(AnQck{)=Fk_ZU`>W&#Id1RXQQ%Ro1q?CS}o*iQBx zD39E5R67@Gw0AQ{*)sN+s?o|y0lVo8Qpi?+I87Icq8j=hfdo5R;wLV&mE zU4%ha;SaN5wl6v*rTTi+FUR8^p5sd^^Hn5a#k@WR{5y%5Y4eM?wYVwSNLdAU)N3x- z1Im*pvX!_;#*a!Q{jn*P_qZ17=RQmy_s_82%%}2@CqXS2B@|gdlkjuLJ@|gUE|4D1 zXzSD42lQw~G=r6VcIC9hv5isKybNAo!TE-1cZT%w!hQRBA8VnQ1Nzrxu_#}ezeW@( z2~3%qBc9$ek+(&;nFmz~bK2!yK-iHf*s8*-y;&DSFHY)lV()pBrR#dzXwlZ++inpY@mq>8t!xM{U-X?t z{ZLGZ(TrA&wcIz!%e3*v{SJ|)xoTL-^BEJrx=HXd7z$3k<^(7zjP)umW1ffl1V=X7 zbFR8FP5X4frM@?uiBmK0h~rmnB_cV9uX(!wFk|8oxpQe!AHzqeZKh}af#UAbpU110 z(`;vg9&&FhojBWR_D4x-xbv*UH=d9Og(6T=xi&puXoVTo4y6}??9^V$>E~xt;CMr6 z&;MQCs0vW=2b-0TgtQ9iJQ3YmEg(yJ62~eAa$2t#&H=F?clI$zEI|uzMj1mA-fIu% z9n8YC=dRR7RMj@@Qf{}o2IzyZX3s{pl7M@Nq4`;N6g{#GjhFYb#mbmt{&Tg6?hL*Y z3+mOPB!FVZy6w_)ZXRoCf~-TJB^puS1-}ZUt}R5{7DNHomgSadm&r}_ zKW#!nnm;iE^A9**G&v-^1(b~kq2#QyY)8xvHx*zP?Gn}wdgW?rhhyHoXM(=+G(C@E zVQUPF;MnzfgfzcuLJb*-cwnO@PA<=tNASbEbn;Ao&qB@R!VPI!oz7HbI)<^;u`5uH-6DUsw?`8bHyp3z69d)t9~Z8u z3zzr>YZFbbk7|I7{r1#R`=^hb<$a%{sRgcJ8UN7vlN2}m`4$Gl*!Q>d3Q?3D6Ixl4 zSH#QK1!M9l8s5A^T3yT435vg7;xOPdG>v`uOZLFQ-LLF!Kc!E~&n8qEn6Duc9A2pW z*4W&nyH*n~OkKP*;r@@d55o%v57}pmZ29=g0hxYp!upx}E|Jv@l}kruhKHBF~5jYM8iCck;#fiNEoC zp@#dSOR-J23)v&o0zpAsK=0N)oo`;iRjguyxBL&`ULg=L&>#4>Rs2gdN9 z8wjN%Q1&X}j#^{`xxnix!>*P#NUks1^P`gk8OVe4NCj;{e+q7_v2^Fy8@=AdlwJZ$ z&9$}p)Zab8DthE8c1Al?d%>5KPX3w&De*X{W@uivyJQZjSpD6Sss=Rx7%3^s3HB;A zr`SiaV-$E~J3dY0;hLivuBI*^SNsnTa4(n@wy?J+H>n6nYLJVidsPEM27nR|xfg3P zYBhP+H#dYZ&Z|$rB1;#ajg4;sN!m=j{KMgR^ORvobeHM1RLc%WCF0~%r?#C@Jr~&u zk{(`!ElaISH~QgV4D(u;BOqrgp&?v7!=Va zFLLAgtfY+Op*I8i^^iP)x)^qHX*kgelM6dpGak*;Kb?&=kM(kW(U^E4@ih9(DQEK2 zeF`8#?O|Mw-B#sy`$MSR|1OmAK6UXzHQsXA4%rR)lv2Tq_sJq8qPaff=rx z<;O#D$sHN?vx=e#69XQe=d3eY@hM8t8@30icl5)T9alGrtYs^JHZ}|DEyIK%Bf<{q zuBv~+w~OZG)5ZJ;Gla?-r9A5l8-WxPvJF50s&o zSJWW?H+)RAJxu=&%Vz%jU82wLf>}0(4KeU8x)B1W>D}iL*d&Wmu|ys-v5%p3@2K5P z+MeB`M5*Hmv7#NfsE&K0-W}T@ddwO!J$8C{>c&g)ck<%!QwxHqKTuK>?Q~L_gCyo* z$`bhI%rS&x0AHudZ^56>m)A^;L5zA{MszQbWkd9)@`}|Cu`Yul&#Ny({|JH#TmjF5 zYr&PRx}&XoawrR0Do#QQVqUOW$ZEGh9X4SMx>FI0pC{EGIHE&;(bn{tF{I`rXMYz- zt`MDwCXtHo-P8sOiFfkIlsrHqQ*!b%1JXmE{4S0qa7_!}sEEFq5fS5{54bf5Ar-Y= z0Xge>RFCrkY8{~NfR!Amy&PKFrjHC*7wiWNV+aX3@IH0Xtt~_UBK+`claYzEVUOw_7TGh?!1Y9u9 zpTA%Yz1+eDaR4qNFQw9k#juJV!RJxR`~`AfTIdzodAdB-d?vEC=>|#i(j+2Jn&kx; zX_yZA!%q${z~vyv-7Sc#ffL9IK#p_JPvp1+Z6L>gFZk~`Aa?Lyd-#7|7sWzmh+M(6 zZ-eVP;fJz+bw7H&R{2T!(LLu@8hYG~aNHuf526v~zh{^2FCc4bzCTzJ^dk$bm2- z$bm3m$boDgL=J?-L5}B0UI51h5t;xu3MnG;`Ty4q=!_?n3J0i*P&pbJ`F;~G2dQS@ z!`|h&^*Xl|y7I<@;&7;);O(!~BBQkzoZKtGw0EOnOpCX|>3TT*2g02+Le%>Nrw@n- z^B6dN9!?)Q4r6!$@|gn;FzTs@k934u1{O}Q7a{lKa2nBzJwcH2^P}jckKpwGJ2%^k z6U>@wYHCu=e(AX`CBPF1&E89j34e8$Q_x)EP4)f{+HhG z%+sA4i<_I9Ygf8CK3-=Q63U+V;fnnXEqJj-tjD*_>T#}+_Ft+0X7KIn7fQR1=$a>t?l+$=Y;oM1GsSEs@IpQsWTa+rx*WdSUB zGr?AFs$GKb++<0+()0;WPftln$;t#`8h1JBCImNRYUg`rG$Nir6if|U!61m{=bNwK zZ4{`q`KkZ&Dha=j5esdj4usFo|NNtT^!r=G1ENmPTf$D!!&M?L9C-xL2Qi1O zz^O>nqmUPaoSL_Zl5Wx1L5CJy+c9q#4`Z?N#%Q~%(8`JL`}_Y*r#x9CUX2OyU`Non zfG^A?3jNqJ?yzJ2+m0jGq>}|5=~ld}Y?rh1&8^f+}zW0Pdd zeD^GF;2n9LSw7iC$m%S)MZKkkFoO#-^R->G0uRpna3$4AOcAE zX!6!*7dVBw4v-HF`merA(2fiCk65O3T*9eqnYm4{(}O= zg-Jw(NlKCDW@TwZ)Qii_G7H@YS;1hnLuv`W0!E?%@@pbdn4*j4jQ7ZDvM>C;U=*m0 z0W8?>8;F%Zj!s$fwJ|*oWcvE((5=xm|6VYMYez`<^~kgvNYgJvJ|nV)1DhFIcae3F z7{Gdku&an6tiOkqKZ2|ShMwDbh~XkDSbh{OwHa9lSkivwFD7t%bM(>`h^3+#v8%qA zuigr}7-FVc(O6^g|912LVl*fCx`l36ukKCzmtU1d?&uqFt0C&YEA=>Mza4US0%3+- z8tP46{nh~I>50R6lOL%uv?5@zrR25tY2*t!UR!xf;Wx^v`p#sRD0~SvsJl?Zhtw2> z_aRaqp6=@A19uikj_yATG%&f?}p+3OgFC;u7ir xhJ^neniBak)c6XzHG~*Z2>I`=76wqbKjw^^Ns14_^59{{dOD&LRK+ literal 0 HcmV?d00001 From 9b07b195233f7f201afd5d1e1ecfeaadd0d5a8aa Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 21 Sep 2024 10:35:41 +0200 Subject: [PATCH 58/78] Feature/improve usability of create or update access dialog (#3791) * Improve usability * Dialog height * Always show permission selector * Update changelog --- CHANGELOG.md | 1 + ...reate-or-update-access-dialog.component.ts | 3 +-- .../create-or-update-access-dialog.html | 22 +++++++++---------- .../user-account-access.component.ts | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ae53a5fc..1868c050f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Improved the usability of the create or update access dialog - Improved the loading indicator of the accounts table - Improved the language localization for German (`de`) - Improved the language localization for Polish (`pl`) diff --git a/apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts b/apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts index dd755a8b9..5bb6ca3e5 100644 --- a/apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts +++ b/apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts @@ -52,13 +52,12 @@ export class CreateOrUpdateAccessDialog implements OnDestroy { if (accessType === 'PRIVATE') { granteeUserIdControl.setValidators(Validators.required); - permissionsControl.setValidators(Validators.required); } else { granteeUserIdControl.clearValidators(); + permissionsControl.setValue(this.data.access.permissions[0]); } granteeUserIdControl.updateValueAndValidity(); - permissionsControl.updateValueAndValidity(); this.changeDetectorRef.markForCheck(); }); diff --git a/apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html b/apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html index 951079717..b903c64d5 100644 --- a/apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html +++ b/apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html @@ -27,18 +27,18 @@

    - @if (accessForm.get('type').value === 'PRIVATE') { -
    - - Permission - - Restricted view +
    + + Permission + + Restricted view + @if (accessForm.get('type').value === 'PRIVATE') { View - - -
    + } +
    +
    +
    + @if (accessForm.get('type').value === 'PRIVATE') {
    diff --git a/apps/client/src/app/components/user-account-access/user-account-access.component.ts b/apps/client/src/app/components/user-account-access/user-account-access.component.ts index d36c31632..2a4452485 100644 --- a/apps/client/src/app/components/user-account-access/user-account-access.component.ts +++ b/apps/client/src/app/components/user-account-access/user-account-access.component.ts @@ -111,7 +111,7 @@ export class UserAccountAccessComponent implements OnDestroy, OnInit { type: 'PRIVATE' } }, - height: this.deviceType === 'mobile' ? '97.5vh' : '80vh', + height: this.deviceType === 'mobile' ? '97.5vh' : undefined, width: this.deviceType === 'mobile' ? '100vw' : '50rem' }); From 9059d4f971a1d920a60c69d6b36a00934372d2a8 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 21 Sep 2024 10:36:05 +0200 Subject: [PATCH 59/78] Feature/upgrade prisma to version 5.19.1 (#3784) * Upgrade prisma to version 5.19.1 * Update changelog --- CHANGELOG.md | 1 + package-lock.json | 68 +++++++++++++++++++++++------------------------ package.json | 4 +-- 3 files changed, 37 insertions(+), 36 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1868c050f..f419b6ba9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Improved the loading indicator of the accounts table - Improved the language localization for German (`de`) - Improved the language localization for Polish (`pl`) +- Upgraded `prisma` from version `5.19.0` to `5.19.1` ## 2.108.0 - 2024-09-17 diff --git a/package-lock.json b/package-lock.json index 5f20e8427..be502a497 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ghostfolio", - "version": "2.106.0", + "version": "2.108.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ghostfolio", - "version": "2.106.0", + "version": "2.108.0", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { @@ -40,7 +40,7 @@ "@nestjs/platform-express": "10.1.3", "@nestjs/schedule": "3.0.2", "@nestjs/serve-static": "4.0.0", - "@prisma/client": "5.19.0", + "@prisma/client": "5.19.1", "@simplewebauthn/browser": "9.0.1", "@simplewebauthn/server": "9.0.3", "@stripe/stripe-js": "3.5.0", @@ -84,7 +84,7 @@ "passport": "0.7.0", "passport-google-oauth20": "2.0.0", "passport-jwt": "4.0.1", - "prisma": "5.19.0", + "prisma": "5.19.1", "reflect-metadata": "0.1.13", "rxjs": "7.5.6", "stripe": "15.11.0", @@ -9646,9 +9646,9 @@ "dev": true }, "node_modules/@prisma/client": { - "version": "5.19.0", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.19.0.tgz", - "integrity": "sha512-CzOpau+q1kEWQyoQMvlnXIHqPvwmWbh48xZ4n8KWbAql0p8PC0BIgSTYW5ncxXa4JSEff0tcoxSZB874wDstdg==", + "version": "5.19.1", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.19.1.tgz", + "integrity": "sha512-x30GFguInsgt+4z5I4WbkZP2CGpotJMUXy+Gl/aaUjHn2o1DnLYNTA+q9XdYmAQZM8fIIkvUiA2NpgosM3fneg==", "hasInstallScript": true, "license": "Apache-2.0", "engines": { @@ -9664,48 +9664,48 @@ } }, "node_modules/@prisma/debug": { - "version": "5.19.0", - "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.19.0.tgz", - "integrity": "sha512-+b/G0ubAZlrS+JSiDhXnYV5DF/aTJ3pinktkiV/L4TtLRLZO6SVGyFELgxBsicCTWJ2ZMu5vEV/jTtYCdjFTRA==", + "version": "5.19.1", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.19.1.tgz", + "integrity": "sha512-lAG6A6QnG2AskAukIEucYJZxxcSqKsMK74ZFVfCTOM/7UiyJQi48v6TQ47d6qKG3LbMslqOvnTX25dj/qvclGg==", "license": "Apache-2.0" }, "node_modules/@prisma/engines": { - "version": "5.19.0", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.19.0.tgz", - "integrity": "sha512-UtW+0m4HYoRSSR3LoDGKF3Ud4BSMWYlLEt4slTnuP1mI+vrV3zaDoiAPmejdAT76vCN5UqnWURbkXxf66nSylQ==", + "version": "5.19.1", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.19.1.tgz", + "integrity": "sha512-kR/PoxZDrfUmbbXqqb8SlBBgCjvGaJYMCOe189PEYzq9rKqitQ2fvT/VJ8PDSe8tTNxhc2KzsCfCAL+Iwm/7Cg==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "5.19.0", - "@prisma/engines-version": "5.19.0-31.5fe21811a6ba0b952a3bc71400666511fe3b902f", - "@prisma/fetch-engine": "5.19.0", - "@prisma/get-platform": "5.19.0" + "@prisma/debug": "5.19.1", + "@prisma/engines-version": "5.19.1-2.69d742ee20b815d88e17e54db4a2a7a3b30324e3", + "@prisma/fetch-engine": "5.19.1", + "@prisma/get-platform": "5.19.1" } }, "node_modules/@prisma/engines-version": { - "version": "5.19.0-31.5fe21811a6ba0b952a3bc71400666511fe3b902f", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.19.0-31.5fe21811a6ba0b952a3bc71400666511fe3b902f.tgz", - "integrity": "sha512-GimI9aZIFy/yvvR11KfXRn3pliFn1QAkdebVlsXlnoh5uk0YhLblVmeYiHfsu+wDA7BeKqYT4sFfzg8mutzuWw==", + "version": "5.19.1-2.69d742ee20b815d88e17e54db4a2a7a3b30324e3", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.19.1-2.69d742ee20b815d88e17e54db4a2a7a3b30324e3.tgz", + "integrity": "sha512-xR6rt+z5LnNqTP5BBc+8+ySgf4WNMimOKXRn6xfNRDSpHvbOEmd7+qAOmzCrddEc4Cp8nFC0txU14dstjH7FXA==", "license": "Apache-2.0" }, "node_modules/@prisma/fetch-engine": { - "version": "5.19.0", - "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.19.0.tgz", - "integrity": "sha512-oOiPNtmJX0cP/ebu7BBEouJvCw8T84/MFD/Hf2zlqjxkK4ojl38bB9i9J5LAxotL6WlYVThKdxc7HqoWnPOhqQ==", + "version": "5.19.1", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.19.1.tgz", + "integrity": "sha512-pCq74rtlOVJfn4pLmdJj+eI4P7w2dugOnnTXpRilP/6n5b2aZiA4ulJlE0ddCbTPkfHmOL9BfaRgA8o+1rfdHw==", "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "5.19.0", - "@prisma/engines-version": "5.19.0-31.5fe21811a6ba0b952a3bc71400666511fe3b902f", - "@prisma/get-platform": "5.19.0" + "@prisma/debug": "5.19.1", + "@prisma/engines-version": "5.19.1-2.69d742ee20b815d88e17e54db4a2a7a3b30324e3", + "@prisma/get-platform": "5.19.1" } }, "node_modules/@prisma/get-platform": { - "version": "5.19.0", - "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.19.0.tgz", - "integrity": "sha512-s9DWkZKnuP4Y8uy6yZfvqQ/9X3/+2KYf3IZUVZz5OstJdGBJrBlbmIuMl81917wp5TuK/1k2TpHNCEdpYLPKmg==", + "version": "5.19.1", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.19.1.tgz", + "integrity": "sha512-sCeoJ+7yt0UjnR+AXZL7vXlg5eNxaFOwC23h0KvW1YIXUoa7+W2ZcAUhoEQBmJTW4GrFqCuZ8YSP0mkDa4k3Zg==", "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "5.19.0" + "@prisma/debug": "5.19.1" } }, "node_modules/@redis/bloom": { @@ -28820,13 +28820,13 @@ } }, "node_modules/prisma": { - "version": "5.19.0", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.19.0.tgz", - "integrity": "sha512-Pu7lUKpVyTx8cVwM26dYh8NdvMOkMnJXzE8L6cikFuR4JwyMU5NKofQkWyxJKlTT4fNjmcnibTvklV8oVMrn+g==", + "version": "5.19.1", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.19.1.tgz", + "integrity": "sha512-c5K9MiDaa+VAAyh1OiYk76PXOme9s3E992D7kvvIOhCrNsBQfy2mP2QAQtX0WNj140IgG++12kwZpYB9iIydNQ==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@prisma/engines": "5.19.0" + "@prisma/engines": "5.19.1" }, "bin": { "prisma": "build/index.js" diff --git a/package.json b/package.json index d8d6b2d53..ce0736128 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,7 @@ "@nestjs/platform-express": "10.1.3", "@nestjs/schedule": "3.0.2", "@nestjs/serve-static": "4.0.0", - "@prisma/client": "5.19.0", + "@prisma/client": "5.19.1", "@simplewebauthn/browser": "9.0.1", "@simplewebauthn/server": "9.0.3", "@stripe/stripe-js": "3.5.0", @@ -128,7 +128,7 @@ "passport": "0.7.0", "passport-google-oauth20": "2.0.0", "passport-jwt": "4.0.1", - "prisma": "5.19.0", + "prisma": "5.19.1", "reflect-metadata": "0.1.13", "rxjs": "7.5.6", "stripe": "15.11.0", From 583c14128bfab4e2a3b91fc40fbe03f1ccc84c3e Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 21 Sep 2024 10:42:43 +0200 Subject: [PATCH 60/78] Feature/extend public api with portfolio performance metrics endpoint (#3762) * Extend Public API with portfolio performance metrics endpoint * Update changelog --- CHANGELOG.md | 1 + README.md | 30 ++++ apps/api/src/app/app.module.ts | 2 + .../app/endpoints/public/public.controller.ts | 134 ++++++++++++++++++ .../src/app/endpoints/public/public.module.ts | 49 +++++++ .../src/app/portfolio/portfolio.controller.ts | 81 +---------- .../access-table/access-table.component.html | 9 ++ .../access-table/access-table.component.ts | 3 +- .../user-account-access.html | 1 + .../app/pages/public/public-page.component.ts | 30 ++-- .../src/app/pages/public/public-page.html | 10 +- apps/client/src/app/services/data.service.ts | 14 +- libs/common/src/lib/interfaces/index.ts | 4 +- .../public-portfolio-response.interface.ts} | 18 ++- 14 files changed, 275 insertions(+), 111 deletions(-) create mode 100644 apps/api/src/app/endpoints/public/public.controller.ts create mode 100644 apps/api/src/app/endpoints/public/public.module.ts rename libs/common/src/lib/interfaces/{portfolio-public-details.interface.ts => responses/public-portfolio-response.interface.ts} (55%) diff --git a/CHANGELOG.md b/CHANGELOG.md index f419b6ba9..6c4ea5c66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Extended the _Public API_ with a new endpoint that provides portfolio performance metrics (experimental) - Added a blog post: _Hacktoberfest 2024_ ### Changed diff --git a/README.md b/README.md index 365a473ee..0f4772d94 100644 --- a/README.md +++ b/README.md @@ -220,6 +220,36 @@ Deprecated: `GET http://localhost:3333/api/v1/auth/anonymous//portfolio` + +#### Response + +##### Success + +``` +{ + "performance": { + "1d": { + "relativeChange": 0 // normalized from -1 to 1 + }; + "ytd": { + "relativeChange": 0 // normalized from -1 to 1 + }, + "max": { + "relativeChange": 0 // normalized from -1 to 1 + } + } +} +``` + ## Community Projects Discover a variety of community projects for Ghostfolio: https://github.com/topics/ghostfolio diff --git a/apps/api/src/app/app.module.ts b/apps/api/src/app/app.module.ts index 86d97eaf8..2803a0580 100644 --- a/apps/api/src/app/app.module.ts +++ b/apps/api/src/app/app.module.ts @@ -31,6 +31,7 @@ import { AuthDeviceModule } from './auth-device/auth-device.module'; import { AuthModule } from './auth/auth.module'; import { BenchmarkModule } from './benchmark/benchmark.module'; import { CacheModule } from './cache/cache.module'; +import { PublicModule } from './endpoints/public/public.module'; import { ExchangeRateModule } from './exchange-rate/exchange-rate.module'; import { ExportModule } from './export/export.module'; import { HealthModule } from './health/health.module'; @@ -85,6 +86,7 @@ import { UserModule } from './user/user.module'; PortfolioSnapshotQueueModule, PrismaModule, PropertyModule, + PublicModule, RedisCacheModule, ScheduleModule.forRoot(), ServeStaticModule.forRoot({ diff --git a/apps/api/src/app/endpoints/public/public.controller.ts b/apps/api/src/app/endpoints/public/public.controller.ts new file mode 100644 index 000000000..4e931372f --- /dev/null +++ b/apps/api/src/app/endpoints/public/public.controller.ts @@ -0,0 +1,134 @@ +import { AccessService } from '@ghostfolio/api/app/access/access.service'; +import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service'; +import { UserService } from '@ghostfolio/api/app/user/user.service'; +import { TransformDataSourceInResponseInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor'; +import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; +import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; +import { DEFAULT_CURRENCY } from '@ghostfolio/common/config'; +import { getSum } from '@ghostfolio/common/helper'; +import { PublicPortfolioResponse } from '@ghostfolio/common/interfaces'; +import type { RequestWithUser } from '@ghostfolio/common/types'; + +import { + Controller, + Get, + HttpException, + Inject, + Param, + UseInterceptors +} from '@nestjs/common'; +import { REQUEST } from '@nestjs/core'; +import { Big } from 'big.js'; +import { StatusCodes, getReasonPhrase } from 'http-status-codes'; + +@Controller('public') +export class PublicController { + public constructor( + private readonly accessService: AccessService, + private readonly configurationService: ConfigurationService, + private readonly exchangeRateDataService: ExchangeRateDataService, + private readonly portfolioService: PortfolioService, + @Inject(REQUEST) private readonly request: RequestWithUser, + private readonly userService: UserService + ) {} + + @Get(':accessId/portfolio') + @UseInterceptors(TransformDataSourceInResponseInterceptor) + public async getPublicPortfolio( + @Param('accessId') accessId + ): Promise { + const access = await this.accessService.access({ id: accessId }); + + if (!access) { + throw new HttpException( + getReasonPhrase(StatusCodes.NOT_FOUND), + StatusCodes.NOT_FOUND + ); + } + + let hasDetails = true; + + const user = await this.userService.user({ + id: access.userId + }); + + if (this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION')) { + hasDetails = user.subscription.type === 'Premium'; + } + + const [ + { holdings }, + { performance: performance1d }, + { performance: performanceMax }, + { performance: performanceYtd } + ] = await Promise.all([ + this.portfolioService.getDetails({ + filters: [{ id: 'EQUITY', type: 'ASSET_CLASS' }], + impersonationId: access.userId, + userId: user.id, + withMarkets: true + }), + ...['1d', 'max', 'ytd'].map((dateRange) => { + return this.portfolioService.getPerformance({ + dateRange, + impersonationId: undefined, + userId: user.id + }); + }) + ]); + + const publicPortfolioResponse: PublicPortfolioResponse = { + hasDetails, + alias: access.alias, + holdings: {}, + performance: { + '1d': { + relativeChange: + performance1d.netPerformancePercentageWithCurrencyEffect + }, + max: { + relativeChange: + performanceMax.netPerformancePercentageWithCurrencyEffect + }, + ytd: { + relativeChange: + performanceYtd.netPerformancePercentageWithCurrencyEffect + } + } + }; + + const totalValue = getSum( + Object.values(holdings).map(({ currency, marketPrice, quantity }) => { + return new Big( + this.exchangeRateDataService.toCurrency( + quantity * marketPrice, + currency, + this.request.user?.Settings?.settings.baseCurrency ?? + DEFAULT_CURRENCY + ) + ); + }) + ).toNumber(); + + for (const [symbol, portfolioPosition] of Object.entries(holdings)) { + publicPortfolioResponse.holdings[symbol] = { + allocationInPercentage: + portfolioPosition.valueInBaseCurrency / totalValue, + countries: hasDetails ? portfolioPosition.countries : [], + currency: hasDetails ? portfolioPosition.currency : undefined, + dataSource: portfolioPosition.dataSource, + dateOfFirstActivity: portfolioPosition.dateOfFirstActivity, + markets: hasDetails ? portfolioPosition.markets : undefined, + name: portfolioPosition.name, + netPerformancePercentWithCurrencyEffect: + portfolioPosition.netPerformancePercentWithCurrencyEffect, + sectors: hasDetails ? portfolioPosition.sectors : [], + symbol: portfolioPosition.symbol, + url: portfolioPosition.url, + valueInPercentage: portfolioPosition.valueInBaseCurrency / totalValue + }; + } + + return publicPortfolioResponse; + } +} diff --git a/apps/api/src/app/endpoints/public/public.module.ts b/apps/api/src/app/endpoints/public/public.module.ts new file mode 100644 index 000000000..9b43522c1 --- /dev/null +++ b/apps/api/src/app/endpoints/public/public.module.ts @@ -0,0 +1,49 @@ +import { AccessModule } from '@ghostfolio/api/app/access/access.module'; +import { AccountBalanceService } from '@ghostfolio/api/app/account-balance/account-balance.service'; +import { AccountService } from '@ghostfolio/api/app/account/account.service'; +import { OrderModule } from '@ghostfolio/api/app/order/order.module'; +import { PortfolioCalculatorFactory } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory'; +import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service'; +import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service'; +import { RulesService } from '@ghostfolio/api/app/portfolio/rules.service'; +import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.module'; +import { UserModule } from '@ghostfolio/api/app/user/user.module'; +import { TransformDataSourceInRequestModule } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.module'; +import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module'; +import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module'; +import { ImpersonationModule } from '@ghostfolio/api/services/impersonation/impersonation.module'; +import { MarketDataModule } from '@ghostfolio/api/services/market-data/market-data.module'; +import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module'; +import { PortfolioSnapshotQueueModule } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.module'; +import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/symbol-profile.module'; + +import { Module } from '@nestjs/common'; + +import { PublicController } from './public.controller'; + +@Module({ + controllers: [PublicController], + imports: [ + AccessModule, + DataProviderModule, + ExchangeRateDataModule, + ImpersonationModule, + MarketDataModule, + OrderModule, + PortfolioSnapshotQueueModule, + PrismaModule, + RedisCacheModule, + SymbolProfileModule, + TransformDataSourceInRequestModule, + UserModule + ], + providers: [ + AccountBalanceService, + AccountService, + CurrentRateService, + PortfolioCalculatorFactory, + PortfolioService, + RulesService + ] +}) +export class PublicModule {} diff --git a/apps/api/src/app/portfolio/portfolio.controller.ts b/apps/api/src/app/portfolio/portfolio.controller.ts index 036e48901..9f5635cf5 100644 --- a/apps/api/src/app/portfolio/portfolio.controller.ts +++ b/apps/api/src/app/portfolio/portfolio.controller.ts @@ -1,6 +1,5 @@ import { AccessService } from '@ghostfolio/api/app/access/access.service'; import { OrderService } from '@ghostfolio/api/app/order/order.service'; -import { UserService } from '@ghostfolio/api/app/user/user.service'; import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator'; import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard'; import { @@ -13,20 +12,15 @@ import { TransformDataSourceInRequestInterceptor } from '@ghostfolio/api/interce import { TransformDataSourceInResponseInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor'; import { ApiService } from '@ghostfolio/api/services/api/api.service'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; -import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { ImpersonationService } from '@ghostfolio/api/services/impersonation/impersonation.service'; import { getIntervalFromDateRange } from '@ghostfolio/common/calculation-helper'; -import { - DEFAULT_CURRENCY, - HEADER_KEY_IMPERSONATION -} from '@ghostfolio/common/config'; +import { HEADER_KEY_IMPERSONATION } from '@ghostfolio/common/config'; import { PortfolioDetails, PortfolioDividends, PortfolioHoldingsResponse, PortfolioInvestments, PortfolioPerformanceResponse, - PortfolioPublicDetails, PortfolioReport } from '@ghostfolio/common/interfaces'; import { @@ -70,12 +64,10 @@ export class PortfolioController { private readonly accessService: AccessService, private readonly apiService: ApiService, private readonly configurationService: ConfigurationService, - private readonly exchangeRateDataService: ExchangeRateDataService, private readonly impersonationService: ImpersonationService, private readonly orderService: OrderService, private readonly portfolioService: PortfolioService, - @Inject(REQUEST) private readonly request: RequestWithUser, - private readonly userService: UserService + @Inject(REQUEST) private readonly request: RequestWithUser ) {} @Get('details') @@ -497,75 +489,6 @@ export class PortfolioController { return performanceInformation; } - @Get('public/:accessId') - @UseInterceptors(TransformDataSourceInResponseInterceptor) - public async getPublic( - @Param('accessId') accessId - ): Promise { - const access = await this.accessService.access({ id: accessId }); - - if (!access) { - throw new HttpException( - getReasonPhrase(StatusCodes.NOT_FOUND), - StatusCodes.NOT_FOUND - ); - } - - let hasDetails = true; - - const user = await this.userService.user({ - id: access.userId - }); - - if (this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION')) { - hasDetails = user.subscription.type === 'Premium'; - } - - const { holdings } = await this.portfolioService.getDetails({ - filters: [{ id: 'EQUITY', type: 'ASSET_CLASS' }], - impersonationId: access.userId, - userId: user.id, - withMarkets: true - }); - - const portfolioPublicDetails: PortfolioPublicDetails = { - hasDetails, - alias: access.alias, - holdings: {} - }; - - const totalValue = Object.values(holdings) - .map((portfolioPosition) => { - return this.exchangeRateDataService.toCurrency( - portfolioPosition.quantity * portfolioPosition.marketPrice, - portfolioPosition.currency, - this.request.user?.Settings?.settings.baseCurrency ?? DEFAULT_CURRENCY - ); - }) - .reduce((a, b) => a + b, 0); - - for (const [symbol, portfolioPosition] of Object.entries(holdings)) { - portfolioPublicDetails.holdings[symbol] = { - allocationInPercentage: - portfolioPosition.valueInBaseCurrency / totalValue, - countries: hasDetails ? portfolioPosition.countries : [], - currency: hasDetails ? portfolioPosition.currency : undefined, - dataSource: portfolioPosition.dataSource, - dateOfFirstActivity: portfolioPosition.dateOfFirstActivity, - markets: hasDetails ? portfolioPosition.markets : undefined, - name: portfolioPosition.name, - netPerformancePercentWithCurrencyEffect: - portfolioPosition.netPerformancePercentWithCurrencyEffect, - sectors: hasDetails ? portfolioPosition.sectors : [], - symbol: portfolioPosition.symbol, - url: portfolioPosition.url, - valueInPercentage: portfolioPosition.valueInBaseCurrency / totalValue - }; - } - - return portfolioPublicDetails; - } - @Get('position/:dataSource/:symbol') @UseInterceptors(RedactValuesInResponseInterceptor) @UseInterceptors(TransformDataSourceInRequestInterceptor) diff --git a/apps/client/src/app/components/access-table/access-table.component.html b/apps/client/src/app/components/access-table/access-table.component.html index e625cbf75..8716873a7 100644 --- a/apps/client/src/app/components/access-table/access-table.component.html +++ b/apps/client/src/app/components/access-table/access-table.component.html @@ -39,6 +39,15 @@ getPublicUrl(element.id) }}
    + @if (user?.settings?.isExperimentalFeatures) { +
    + GET {{ baseUrl }}/api/v1/public/{{ + element.id + }}/portfolio +
    + } } diff --git a/apps/client/src/app/components/access-table/access-table.component.ts b/apps/client/src/app/components/access-table/access-table.component.ts index 3d47c6087..94756634b 100644 --- a/apps/client/src/app/components/access-table/access-table.component.ts +++ b/apps/client/src/app/components/access-table/access-table.component.ts @@ -1,7 +1,7 @@ import { ConfirmationDialogType } from '@ghostfolio/client/core/notification/confirmation-dialog/confirmation-dialog.type'; import { NotificationService } from '@ghostfolio/client/core/notification/notification.service'; import { DEFAULT_LANGUAGE_CODE } from '@ghostfolio/common/config'; -import { Access } from '@ghostfolio/common/interfaces'; +import { Access, User } from '@ghostfolio/common/interfaces'; import { Clipboard } from '@angular/cdk/clipboard'; import { @@ -24,6 +24,7 @@ import { MatTableDataSource } from '@angular/material/table'; export class AccessTableComponent implements OnChanges, OnInit { @Input() accesses: Access[]; @Input() showActions: boolean; + @Input() user: User; @Output() accessDeleted = new EventEmitter(); diff --git a/apps/client/src/app/components/user-account-access/user-account-access.html b/apps/client/src/app/components/user-account-access/user-account-access.html index f651b0419..e5d43cadc 100644 --- a/apps/client/src/app/components/user-account-access/user-account-access.html +++ b/apps/client/src/app/components/user-account-access/user-account-access.html @@ -10,6 +10,7 @@ @if (hasPermissionToCreateAccess) { diff --git a/apps/client/src/app/pages/public/public-page.component.ts b/apps/client/src/app/pages/public/public-page.component.ts index 4e593b959..5e901c3f5 100644 --- a/apps/client/src/app/pages/public/public-page.component.ts +++ b/apps/client/src/app/pages/public/public-page.component.ts @@ -3,7 +3,7 @@ import { UNKNOWN_KEY } from '@ghostfolio/common/config'; import { prettifySymbol } from '@ghostfolio/common/helper'; import { PortfolioPosition, - PortfolioPublicDetails + PublicPortfolioResponse } from '@ghostfolio/common/interfaces'; import { Market } from '@ghostfolio/common/types'; @@ -29,16 +29,16 @@ export class PublicPageComponent implements OnInit { [code: string]: { name: string; value: number }; }; public deviceType: string; - public holdings: PortfolioPublicDetails['holdings'][string][]; + public holdings: PublicPortfolioResponse['holdings'][string][]; public markets: { [key in Market]: { name: string; value: number }; }; - public portfolioPublicDetails: PortfolioPublicDetails; public positions: { [symbol: string]: Pick & { value: number; }; }; + public publicPortfolioDetails: PublicPortfolioResponse; public sectors: { [name: string]: { name: string; value: number }; }; @@ -47,7 +47,7 @@ export class PublicPageComponent implements OnInit { }; public UNKNOWN_KEY = UNKNOWN_KEY; - private id: string; + private accessId: string; private unsubscribeSubject = new Subject(); public constructor( @@ -58,7 +58,7 @@ export class PublicPageComponent implements OnInit { private router: Router ) { this.activatedRoute.params.subscribe((params) => { - this.id = params['id']; + this.accessId = params['id']; }); } @@ -66,7 +66,7 @@ export class PublicPageComponent implements OnInit { this.deviceType = this.deviceService.getDeviceInfo().deviceType; this.dataService - .fetchPortfolioPublic(this.id) + .fetchPublicPortfolio(this.accessId) .pipe( takeUntil(this.unsubscribeSubject), catchError((error) => { @@ -79,7 +79,7 @@ export class PublicPageComponent implements OnInit { }) ) .subscribe((portfolioPublicDetails) => { - this.portfolioPublicDetails = portfolioPublicDetails; + this.publicPortfolioDetails = portfolioPublicDetails; this.initializeAnalysisData(); @@ -135,7 +135,7 @@ export class PublicPageComponent implements OnInit { }; for (const [symbol, position] of Object.entries( - this.portfolioPublicDetails.holdings + this.publicPortfolioDetails.holdings )) { this.holdings.push(position); @@ -164,7 +164,7 @@ export class PublicPageComponent implements OnInit { name: continent, value: weight * - this.portfolioPublicDetails.holdings[symbol].valueInBaseCurrency + this.publicPortfolioDetails.holdings[symbol].valueInBaseCurrency }; } @@ -175,19 +175,19 @@ export class PublicPageComponent implements OnInit { name, value: weight * - this.portfolioPublicDetails.holdings[symbol].valueInBaseCurrency + this.publicPortfolioDetails.holdings[symbol].valueInBaseCurrency }; } } } else { this.continents[UNKNOWN_KEY].value += - this.portfolioPublicDetails.holdings[symbol].valueInBaseCurrency; + this.publicPortfolioDetails.holdings[symbol].valueInBaseCurrency; this.countries[UNKNOWN_KEY].value += - this.portfolioPublicDetails.holdings[symbol].valueInBaseCurrency; + this.publicPortfolioDetails.holdings[symbol].valueInBaseCurrency; this.markets[UNKNOWN_KEY].value += - this.portfolioPublicDetails.holdings[symbol].valueInBaseCurrency; + this.publicPortfolioDetails.holdings[symbol].valueInBaseCurrency; } if (position.sectors.length > 0) { @@ -201,13 +201,13 @@ export class PublicPageComponent implements OnInit { name, value: weight * - this.portfolioPublicDetails.holdings[symbol].valueInBaseCurrency + this.publicPortfolioDetails.holdings[symbol].valueInBaseCurrency }; } } } else { this.sectors[UNKNOWN_KEY].value += - this.portfolioPublicDetails.holdings[symbol].valueInBaseCurrency; + this.publicPortfolioDetails.holdings[symbol].valueInBaseCurrency; } this.symbols[prettifySymbol(symbol)] = { diff --git a/apps/client/src/app/pages/public/public-page.html b/apps/client/src/app/pages/public/public-page.html index 04d8aca1e..fe213166f 100644 --- a/apps/client/src/app/pages/public/public-page.html +++ b/apps/client/src/app/pages/public/public-page.html @@ -2,7 +2,7 @@

    - Hello, {{ portfolioPublicDetails?.alias ?? 'someone' }} has shared a + Hello, {{ publicPortfolioDetails?.alias ?? 'someone' }} has shared a Portfolio with you!

    @@ -24,7 +24,7 @@
    - @if (portfolioPublicDetails?.hasDetails) { + @if (publicPortfolioDetails?.hasDetails) {
    @@ -43,7 +43,7 @@
    } - @if (portfolioPublicDetails?.hasDetails) { + @if (publicPortfolioDetails?.hasDetails) {
    @@ -60,7 +60,7 @@
    } - @if (portfolioPublicDetails?.hasDetails) { + @if (publicPortfolioDetails?.hasDetails) {
    @@ -79,7 +79,7 @@
    }
    - @if (portfolioPublicDetails?.hasDetails) { + @if (publicPortfolioDetails?.hasDetails) {
    diff --git a/apps/client/src/app/services/data.service.ts b/apps/client/src/app/services/data.service.ts index 78373adcc..4135335c6 100644 --- a/apps/client/src/app/services/data.service.ts +++ b/apps/client/src/app/services/data.service.ts @@ -36,8 +36,8 @@ import { PortfolioHoldingsResponse, PortfolioInvestments, PortfolioPerformanceResponse, - PortfolioPublicDetails, PortfolioReport, + PublicPortfolioResponse, User } from '@ghostfolio/common/interfaces'; import { filterGlobalPermissions } from '@ghostfolio/common/permissions'; @@ -611,9 +611,13 @@ export class DataService { ); } - public fetchPortfolioPublic(aId: string) { + public fetchPortfolioReport() { + return this.http.get('/api/v1/portfolio/report'); + } + + public fetchPublicPortfolio(aAccessId: string) { return this.http - .get(`/api/v1/portfolio/public/${aId}`) + .get(`/api/v1/public/${aAccessId}/portfolio`) .pipe( map((response) => { if (response.holdings) { @@ -631,10 +635,6 @@ export class DataService { ); } - public fetchPortfolioReport() { - return this.http.get('/api/v1/portfolio/report'); - } - public loginAnonymous(accessToken: string) { return this.http.post(`/api/v1/auth/anonymous`, { accessToken diff --git a/libs/common/src/lib/interfaces/index.ts b/libs/common/src/lib/interfaces/index.ts index efab780fd..51bb7c10e 100644 --- a/libs/common/src/lib/interfaces/index.ts +++ b/libs/common/src/lib/interfaces/index.ts @@ -31,7 +31,6 @@ 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'; @@ -44,6 +43,7 @@ import type { ImportResponse } from './responses/import-response.interface'; import type { OAuthResponse } from './responses/oauth-response.interface'; import type { PortfolioHoldingsResponse } from './responses/portfolio-holdings-response.interface'; import type { PortfolioPerformanceResponse } from './responses/portfolio-performance-response.interface'; +import type { PublicPortfolioResponse } from './responses/public-portfolio-response.interface'; import type { ScraperConfiguration } from './scraper-configuration.interface'; import type { Statistics } from './statistics.interface'; import type { Subscription } from './subscription.interface'; @@ -91,12 +91,12 @@ export { PortfolioPerformance, PortfolioPerformanceResponse, PortfolioPosition, - PortfolioPublicDetails, PortfolioReport, PortfolioReportRule, PortfolioSummary, Position, Product, + PublicPortfolioResponse, ResponseError, ScraperConfiguration, Statistics, diff --git a/libs/common/src/lib/interfaces/portfolio-public-details.interface.ts b/libs/common/src/lib/interfaces/responses/public-portfolio-response.interface.ts similarity index 55% rename from libs/common/src/lib/interfaces/portfolio-public-details.interface.ts rename to libs/common/src/lib/interfaces/responses/public-portfolio-response.interface.ts index 57b0b36cc..f7ce78479 100644 --- a/libs/common/src/lib/interfaces/portfolio-public-details.interface.ts +++ b/libs/common/src/lib/interfaces/responses/public-portfolio-response.interface.ts @@ -1,6 +1,6 @@ -import { PortfolioPosition } from '@ghostfolio/common/interfaces'; +import { PortfolioPosition } from '../portfolio-position.interface'; -export interface PortfolioPublicDetails { +export interface PublicPortfolioResponse extends PublicPortfolioResponseV1 { alias?: string; hasDetails: boolean; holdings: { @@ -22,3 +22,17 @@ export interface PortfolioPublicDetails { >; }; } + +interface PublicPortfolioResponseV1 { + performance: { + '1d': { + relativeChange: number; + }; + max: { + relativeChange: number; + }; + ytd: { + relativeChange: number; + }; + }; +} From c2f69501c7b531b570d38e7bdd1526946ac1af41 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 21 Sep 2024 11:34:26 +0200 Subject: [PATCH 61/78] Feature/improve documentation for public API (#3792) --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 0f4772d94..477554749 100644 --- a/README.md +++ b/README.md @@ -165,6 +165,10 @@ Deprecated: `GET http://localhost:3333/api/v1/auth/anonymous//portfolio` +**Info:** No Bearer Token is required for authorization + #### Response ##### Success From 7053aba2da513b3adaf360bb4589e720969446b9 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 21 Sep 2024 13:28:49 +0200 Subject: [PATCH 62/78] Feature/add portfolio performance metrics to public page (#3793) * Add portfolio performance metrics * Update changelog --- CHANGELOG.md | 1 + .../src/app/pages/public/public-page.html | 56 +++++++++++++++++++ libs/ui/src/lib/value/value.component.html | 2 +- 3 files changed, 58 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c4ea5c66..180306acd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Extended the _Public API_ with a new endpoint that provides portfolio performance metrics (experimental) +- Added the portfolio performance metrics to the public page - Added a blog post: _Hacktoberfest 2024_ ### Changed diff --git a/apps/client/src/app/pages/public/public-page.html b/apps/client/src/app/pages/public/public-page.html index fe213166f..369ea50f5 100644 --- a/apps/client/src/app/pages/public/public-page.html +++ b/apps/client/src/app/pages/public/public-page.html @@ -7,6 +7,62 @@
    +
    +
    + + + Today + + +
    +
    + + + This year + + +
    +
    + + + From the beginning + + +
    +
    diff --git a/libs/ui/src/lib/value/value.component.html b/libs/ui/src/lib/value/value.component.html index d1e498bcc..a691c54e8 100644 --- a/libs/ui/src/lib/value/value.component.html +++ b/libs/ui/src/lib/value/value.component.html @@ -5,7 +5,7 @@
    From 20d709380ad90e94fa62cdeea2e65cc542102e59 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 21 Sep 2024 14:34:17 +0200 Subject: [PATCH 63/78] Feature/add no auto-renewal hint to account membership page (#3795) * Add hint --- .../user-account-membership/user-account-membership.html | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/client/src/app/components/user-account-membership/user-account-membership.html b/apps/client/src/app/components/user-account-membership/user-account-membership.html index 030f5488e..644ec0605 100644 --- a/apps/client/src/app/components/user-account-membership/user-account-membership.html +++ b/apps/client/src/app/components/user-account-membership/user-account-membership.html @@ -56,6 +56,10 @@ }
    + } @else { +
    + No auto-renewal. +
    }
    From 5e4201d8317813c40fae928787257dc06903b2da Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 21 Sep 2024 15:04:52 +0200 Subject: [PATCH 64/78] Feature/remove nx cloud access token (#3798) * Remove nxCloudAccessToken --- nx.json | 1 - 1 file changed, 1 deletion(-) diff --git a/nx.json b/nx.json index 17123544e..11f805e5a 100644 --- a/nx.json +++ b/nx.json @@ -70,7 +70,6 @@ "!{projectRoot}/webpack.config.js" ] }, - "nxCloudAccessToken": "Mjg0ZGQ2YjAtNGI4NS00NmYwLThhOWEtMWZmNmQzODM4YzU4fHJlYWQ=", "parallel": 1, "defaultBase": "origin/main" } From e918970feb0d12c1347abba2cbb0b8d04af07e11 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 21 Sep 2024 18:16:34 +0200 Subject: [PATCH 65/78] Feature/expose concurrency of portfolio snapshot calculation as environment variable (#3796) * Expose PROCESSOR_CONCURRENCY_PORTFOLIO_SNAPSHOT * Update changelog --- CHANGELOG.md | 1 + .../services/configuration/configuration.service.ts | 4 ++++ .../portfolio-snapshot/portfolio-snapshot.processor.ts | 10 +++++++++- libs/common/src/lib/config.ts | 1 + 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 180306acd..52ca01d15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Improved the usability of the create or update access dialog - Improved the loading indicator of the accounts table +- Exposed the concurrency of the portfolio snapshot calculation as an environment variable (`PROCESSOR_CONCURRENCY_PORTFOLIO_SNAPSHOT`) - Improved the language localization for German (`de`) - Improved the language localization for Polish (`pl`) - Upgraded `prisma` from version `5.19.0` to `5.19.1` diff --git a/apps/api/src/services/configuration/configuration.service.ts b/apps/api/src/services/configuration/configuration.service.ts index 26ef38c0a..0f9246107 100644 --- a/apps/api/src/services/configuration/configuration.service.ts +++ b/apps/api/src/services/configuration/configuration.service.ts @@ -1,6 +1,7 @@ import { Environment } from '@ghostfolio/api/services/interfaces/environment.interface'; import { CACHE_TTL_NO_CACHE, + DEFAULT_PROCESSOR_CONCURRENCY_PORTFOLIO_SNAPSHOT, DEFAULT_ROOT_URL } from '@ghostfolio/common/config'; @@ -47,6 +48,9 @@ export class ConfigurationService { MAX_ACTIVITIES_TO_IMPORT: num({ default: Number.MAX_SAFE_INTEGER }), MAX_CHART_ITEMS: num({ default: 365 }), PORT: port({ default: 3333 }), + PROCESSOR_CONCURRENCY_PORTFOLIO_SNAPSHOT: num({ + default: DEFAULT_PROCESSOR_CONCURRENCY_PORTFOLIO_SNAPSHOT + }), REDIS_DB: num({ default: 0 }), REDIS_HOST: str({ default: 'localhost' }), REDIS_PASSWORD: str({ default: '' }), diff --git a/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.processor.ts b/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.processor.ts index f8173559e..b3ef4eb88 100644 --- a/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.processor.ts +++ b/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.processor.ts @@ -8,6 +8,7 @@ import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.s import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { CACHE_TTL_INFINITE, + DEFAULT_PROCESSOR_CONCURRENCY_PORTFOLIO_SNAPSHOT, PORTFOLIO_SNAPSHOT_PROCESS_JOB_NAME, PORTFOLIO_SNAPSHOT_QUEUE } from '@ghostfolio/common/config'; @@ -29,7 +30,14 @@ export class PortfolioSnapshotProcessor { private readonly redisCacheService: RedisCacheService ) {} - @Process({ concurrency: 1, name: PORTFOLIO_SNAPSHOT_PROCESS_JOB_NAME }) + @Process({ + concurrency: parseInt( + process.env.PROCESSOR_CONCURRENCY_PORTFOLIO_SNAPSHOT ?? + DEFAULT_PROCESSOR_CONCURRENCY_PORTFOLIO_SNAPSHOT.toString(), + 10 + ), + name: PORTFOLIO_SNAPSHOT_PROCESS_JOB_NAME + }) public async calculatePortfolioSnapshot( job: Job ) { diff --git a/libs/common/src/lib/config.ts b/libs/common/src/lib/config.ts index 79fdf6d05..6fc5650cc 100644 --- a/libs/common/src/lib/config.ts +++ b/libs/common/src/lib/config.ts @@ -48,6 +48,7 @@ export const DEFAULT_CURRENCY = 'USD'; export const DEFAULT_DATE_FORMAT_MONTH_YEAR = 'MMM yyyy'; export const DEFAULT_LANGUAGE_CODE = 'en'; export const DEFAULT_PAGE_SIZE = 50; +export const DEFAULT_PROCESSOR_CONCURRENCY_PORTFOLIO_SNAPSHOT = 1; export const DEFAULT_ROOT_URL = 'https://localhost:4200'; // USX is handled separately From 6f227e677caba3378f40653df236445f852a9c4e Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 21 Sep 2024 18:22:14 +0200 Subject: [PATCH 66/78] Feature/refactor environment variable access in create user of user service (#3797) * Refactor environment variable access --- apps/api/src/app/user/user.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/api/src/app/user/user.service.ts b/apps/api/src/app/user/user.service.ts index f8746881f..edb27aead 100644 --- a/apps/api/src/app/user/user.service.ts +++ b/apps/api/src/app/user/user.service.ts @@ -371,7 +371,7 @@ export class UserService { const hashedAccessToken = this.createAccessToken( accessToken, - process.env.ACCESS_TOKEN_SALT + this.configurationService.get('ACCESS_TOKEN_SALT') ); user = await this.prismaService.user.update({ From be09acdb242304d0053d2373b18b6df8bf3ef614 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 21 Sep 2024 18:56:02 +0200 Subject: [PATCH 67/78] Feature/expose concurrency of data gathering processor as environment variable (#3799) * Expose concurrency of data gathering processor * PROCESSOR_CONCURRENCY_GATHER_ASSET_PROFILE * PROCESSOR_CONCURRENCY_GATHER_HISTORICAL_MARKET_DATA * Update changelog --- CHANGELOG.md | 2 ++ .../configuration/configuration.service.ts | 8 ++++++++ .../data-gathering/data-gathering.processor.ts | 17 +++++++++++++++-- libs/common/src/lib/config.ts | 2 ++ 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 52ca01d15..eae8ef40b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Improved the usability of the create or update access dialog - Improved the loading indicator of the accounts table +- Exposed the concurrency of the asset profile data gathering as an environment variable (`PROCESSOR_CONCURRENCY_GATHER_ASSET_PROFILE`) +- Exposed the concurrency of the historical market data gathering as an environment variable (`PROCESSOR_CONCURRENCY_GATHER_HISTORICAL_MARKET_DATA`) - Exposed the concurrency of the portfolio snapshot calculation as an environment variable (`PROCESSOR_CONCURRENCY_PORTFOLIO_SNAPSHOT`) - Improved the language localization for German (`de`) - Improved the language localization for Polish (`pl`) diff --git a/apps/api/src/services/configuration/configuration.service.ts b/apps/api/src/services/configuration/configuration.service.ts index 0f9246107..cca393a2a 100644 --- a/apps/api/src/services/configuration/configuration.service.ts +++ b/apps/api/src/services/configuration/configuration.service.ts @@ -1,6 +1,8 @@ import { Environment } from '@ghostfolio/api/services/interfaces/environment.interface'; import { CACHE_TTL_NO_CACHE, + DEFAULT_PROCESSOR_CONCURRENCY_GATHER_ASSET_PROFILE, + DEFAULT_PROCESSOR_CONCURRENCY_GATHER_HISTORICAL_MARKET_DATA, DEFAULT_PROCESSOR_CONCURRENCY_PORTFOLIO_SNAPSHOT, DEFAULT_ROOT_URL } from '@ghostfolio/common/config'; @@ -48,6 +50,12 @@ export class ConfigurationService { MAX_ACTIVITIES_TO_IMPORT: num({ default: Number.MAX_SAFE_INTEGER }), MAX_CHART_ITEMS: num({ default: 365 }), PORT: port({ default: 3333 }), + PROCESSOR_CONCURRENCY_GATHER_ASSET_PROFILE: num({ + default: DEFAULT_PROCESSOR_CONCURRENCY_GATHER_ASSET_PROFILE + }), + PROCESSOR_CONCURRENCY_GATHER_HISTORICAL_MARKET_DATA: num({ + default: DEFAULT_PROCESSOR_CONCURRENCY_GATHER_HISTORICAL_MARKET_DATA + }), PROCESSOR_CONCURRENCY_PORTFOLIO_SNAPSHOT: num({ default: DEFAULT_PROCESSOR_CONCURRENCY_PORTFOLIO_SNAPSHOT }), diff --git a/apps/api/src/services/queues/data-gathering/data-gathering.processor.ts b/apps/api/src/services/queues/data-gathering/data-gathering.processor.ts index 62f52d45b..2745aa288 100644 --- a/apps/api/src/services/queues/data-gathering/data-gathering.processor.ts +++ b/apps/api/src/services/queues/data-gathering/data-gathering.processor.ts @@ -3,6 +3,8 @@ import { IDataGatheringItem } from '@ghostfolio/api/services/interfaces/interfac import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service'; import { DATA_GATHERING_QUEUE, + DEFAULT_PROCESSOR_CONCURRENCY_GATHER_ASSET_PROFILE, + DEFAULT_PROCESSOR_CONCURRENCY_GATHER_HISTORICAL_MARKET_DATA, GATHER_ASSET_PROFILE_PROCESS, GATHER_HISTORICAL_MARKET_DATA_PROCESS_JOB_NAME } from '@ghostfolio/common/config'; @@ -34,7 +36,14 @@ export class DataGatheringProcessor { private readonly marketDataService: MarketDataService ) {} - @Process({ concurrency: 1, name: GATHER_ASSET_PROFILE_PROCESS }) + @Process({ + concurrency: parseInt( + process.env.PROCESSOR_CONCURRENCY_GATHER_ASSET_PROFILE ?? + DEFAULT_PROCESSOR_CONCURRENCY_GATHER_ASSET_PROFILE.toString(), + 10 + ), + name: GATHER_ASSET_PROFILE_PROCESS + }) public async gatherAssetProfile(job: Job) { try { Logger.log( @@ -59,7 +68,11 @@ export class DataGatheringProcessor { } @Process({ - concurrency: 1, + concurrency: parseInt( + process.env.PROCESSOR_CONCURRENCY_GATHER_HISTORICAL_MARKET_DATA ?? + DEFAULT_PROCESSOR_CONCURRENCY_GATHER_HISTORICAL_MARKET_DATA.toString(), + 10 + ), name: GATHER_HISTORICAL_MARKET_DATA_PROCESS_JOB_NAME }) public async gatherHistoricalMarketData(job: Job) { diff --git a/libs/common/src/lib/config.ts b/libs/common/src/lib/config.ts index 6fc5650cc..19ec965fa 100644 --- a/libs/common/src/lib/config.ts +++ b/libs/common/src/lib/config.ts @@ -48,6 +48,8 @@ export const DEFAULT_CURRENCY = 'USD'; export const DEFAULT_DATE_FORMAT_MONTH_YEAR = 'MMM yyyy'; export const DEFAULT_LANGUAGE_CODE = 'en'; export const DEFAULT_PAGE_SIZE = 50; +export const DEFAULT_PROCESSOR_CONCURRENCY_GATHER_ASSET_PROFILE = 1; +export const DEFAULT_PROCESSOR_CONCURRENCY_GATHER_HISTORICAL_MARKET_DATA = 1; export const DEFAULT_PROCESSOR_CONCURRENCY_PORTFOLIO_SNAPSHOT = 1; export const DEFAULT_ROOT_URL = 'https://localhost:4200'; From 336f7b002c70d45a13e94a783a29b2795e6a8c92 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 21 Sep 2024 20:00:56 +0200 Subject: [PATCH 68/78] Feature/extend personal finance tools (#3801) * Add Finanzfluss Copilot --- libs/common/src/lib/personal-finance-tools.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/libs/common/src/lib/personal-finance-tools.ts b/libs/common/src/lib/personal-finance-tools.ts index 29fcc391e..85fe737d0 100644 --- a/libs/common/src/lib/personal-finance-tools.ts +++ b/libs/common/src/lib/personal-finance-tools.ts @@ -212,6 +212,16 @@ export const personalFinanceTools: Product[] = [ pricingPerYear: '$115', slogan: 'Flexible Financial Management' }, + { + founded: 2023, + hasFreePlan: true, + hasSelfHostingAbility: false, + key: 'finanzfluss-copilot', + name: 'Finanzfluss Copilot', + origin: 'Germany', + pricingPerYear: '€69.99', + slogan: 'Portfolio Tracker für dein Vermögen' + }, { founded: 2020, key: 'finary', From f59e8c8798d17ba097ad840031ce3a4a7601b77c Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 21 Sep 2024 20:01:33 +0200 Subject: [PATCH 69/78] Feature/add feature graphic for hacktoberfest 2024 blog post (#3800) * Add feature graphic --- apps/api/src/middlewares/html-template.middleware.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/api/src/middlewares/html-template.middleware.ts b/apps/api/src/middlewares/html-template.middleware.ts index b38a90ef8..7b7cb09f2 100644 --- a/apps/api/src/middlewares/html-template.middleware.ts +++ b/apps/api/src/middlewares/html-template.middleware.ts @@ -83,6 +83,10 @@ const locales = { '/en/blog/2023/11/hacktoberfest-2023-debriefing': { featureGraphicPath: 'assets/images/blog/hacktoberfest-2023.png', title: `Hacktoberfest 2023 Debriefing - ${title}` + }, + '/en/blog/2024/09/hacktoberfest-2024': { + featureGraphicPath: 'assets/images/blog/hacktoberfest-2024.png', + title: `Hacktoberfest 2024 - ${title}` } }; From 67aa76d31c9412f6328a7ce174b0483c4e074a58 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 21 Sep 2024 20:03:31 +0200 Subject: [PATCH 70/78] Release 2.109.0 (#3803) --- CHANGELOG.md | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eae8ef40b..3797a071d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased +## 2.109.0 - 2024-09-17 ### Added diff --git a/package.json b/package.json index ce0736128..4519558a9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "2.108.0", + "version": "2.109.0", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "repository": "https://github.com/ghostfolio/ghostfolio", From 98e9b5d895ba508f79e5a07e0f59157bb94899a4 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 22 Sep 2024 09:09:02 +0200 Subject: [PATCH 71/78] Feature/consider user language in sharable portfolio link (#3806) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Consider user’s language in sharable portfolio link * Update changelog --- CHANGELOG.md | 6 ++++++ .../app/components/access-table/access-table.component.ts | 5 +++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3797a071d..c7edd5207 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 + +- Considered the user’s language in the link of the access table to share the portfolio + ## 2.109.0 - 2024-09-17 ### Added diff --git a/apps/client/src/app/components/access-table/access-table.component.ts b/apps/client/src/app/components/access-table/access-table.component.ts index 94756634b..8b147fdd3 100644 --- a/apps/client/src/app/components/access-table/access-table.component.ts +++ b/apps/client/src/app/components/access-table/access-table.component.ts @@ -30,7 +30,6 @@ export class AccessTableComponent implements OnChanges, OnInit { public baseUrl = window.location.origin; public dataSource: MatTableDataSource; - public defaultLanguageCode = DEFAULT_LANGUAGE_CODE; public displayedColumns = []; public constructor( @@ -53,7 +52,9 @@ export class AccessTableComponent implements OnChanges, OnInit { } public getPublicUrl(aId: string): string { - return `${this.baseUrl}/${this.defaultLanguageCode}/p/${aId}`; + const languageCode = this.user?.settings?.language ?? DEFAULT_LANGUAGE_CODE; + + return `${this.baseUrl}/${languageCode}/p/${aId}`; } public onCopyToClipboard(aId: string): void { From 46fb075ecbc2cd54313495f9cad4e53fcae16c91 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Mon, 23 Sep 2024 19:49:00 +0200 Subject: [PATCH 72/78] Feature/improve language localization for de 20240921 (#3804) * Update translations * Update changelog --- CHANGELOG.md | 1 + apps/client/src/locales/messages.ca.xlf | 86 ++++++++++++++++++------- apps/client/src/locales/messages.de.xlf | 84 +++++++++++++++++------- apps/client/src/locales/messages.es.xlf | 86 ++++++++++++++++++------- apps/client/src/locales/messages.fr.xlf | 86 ++++++++++++++++++------- apps/client/src/locales/messages.it.xlf | 86 ++++++++++++++++++------- apps/client/src/locales/messages.nl.xlf | 86 ++++++++++++++++++------- apps/client/src/locales/messages.pl.xlf | 86 ++++++++++++++++++------- apps/client/src/locales/messages.pt.xlf | 86 ++++++++++++++++++------- apps/client/src/locales/messages.tr.xlf | 86 ++++++++++++++++++------- apps/client/src/locales/messages.xlf | 80 ++++++++++++++++------- apps/client/src/locales/messages.zh.xlf | 86 ++++++++++++++++++------- 12 files changed, 688 insertions(+), 251 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c7edd5207..38fb0dde2 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 - Considered the user’s language in the link of the access table to share the portfolio +- Improved the language localization for German (`de`) ## 2.109.0 - 2024-09-17 diff --git a/apps/client/src/locales/messages.ca.xlf b/apps/client/src/locales/messages.ca.xlf index 7646af290..00ea1dbb1 100644 --- a/apps/client/src/locales/messages.ca.xlf +++ b/apps/client/src/locales/messages.ca.xlf @@ -200,6 +200,10 @@ apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.html 270
    + + apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.html + 187 + apps/client/src/app/pages/blog/blog-page.html 5 @@ -421,6 +425,10 @@ apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.component.ts 13 + + apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.component.ts + 13 + apps/client/src/app/pages/landing/landing-page.component.ts 26 @@ -787,7 +795,7 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html - 33 + 32
    @@ -799,7 +807,7 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html - 38 + 36 @@ -811,7 +819,7 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html - 36 + 34 @@ -827,7 +835,7 @@ Revocar apps/client/src/app/components/access-table/access-table.component.html - 65 + 74 @@ -835,7 +843,7 @@ Realment vol revocar aquest accés? apps/client/src/app/components/access-table/access-table.component.ts - 68 + 69 @@ -931,7 +939,7 @@ apps/client/src/app/pages/public/public-page.html - 14 + 70 libs/ui/src/lib/assistant/assistant.html @@ -1771,7 +1779,7 @@ apps/client/src/app/pages/public/public-page.html - 50 + 106 @@ -3199,7 +3207,7 @@ Oops! Could not grant access. apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts - 91 + 90 @@ -3663,7 +3671,7 @@ Oops, cash balance transfer has failed. apps/client/src/app/pages/accounts/accounts-page.component.ts - 311 + 317 @@ -4023,7 +4031,7 @@ apps/client/src/app/pages/public/public-page.html - 164 + 220 @@ -4863,7 +4871,7 @@ apps/client/src/app/pages/public/public-page.html - 87 + 143 @@ -4875,7 +4883,7 @@ apps/client/src/app/pages/public/public-page.html - 104 + 160 @@ -4887,7 +4895,7 @@ apps/client/src/app/pages/public/public-page.html - 113 + 169 @@ -4899,7 +4907,7 @@ apps/client/src/app/pages/public/public-page.html - 122 + 178 @@ -4911,7 +4919,7 @@ apps/client/src/app/pages/public/public-page.html - 132 + 188 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -5374,9 +5382,9 @@ 301 - - Hello, has shared a Portfolio with you! - Hello, has shared a Portfolio with you! + + Hello, has shared a Portfolio with you! + Hello, has shared a Portfolio with you! apps/client/src/app/pages/public/public-page.html 4 @@ -5387,7 +5395,7 @@ Currencies apps/client/src/app/pages/public/public-page.html - 32 + 88 @@ -5395,7 +5403,7 @@ Continents apps/client/src/app/pages/public/public-page.html - 68 + 124 @@ -5403,7 +5411,7 @@ Would you like to refine your personal investment strategy? apps/client/src/app/pages/public/public-page.html - 155 + 211 @@ -5411,7 +5419,7 @@ Ghostfolio empowers you to keep track of your wealth. apps/client/src/app/pages/public/public-page.html - 159 + 215 @@ -7007,7 +7015,7 @@ Copy link to clipboard apps/client/src/app/components/access-table/access-table.component.html - 61 + 70 @@ -7066,6 +7074,38 @@ 67 + + No auto-renewal. + No auto-renewal. + + apps/client/src/app/components/user-account-membership/user-account-membership.html + 61 + + + + Today + Today + + apps/client/src/app/pages/public/public-page.html + 24 + + + + This year + This year + + apps/client/src/app/pages/public/public-page.html + 42 + + + + From the beginning + From the beginning + + apps/client/src/app/pages/public/public-page.html + 60 + + diff --git a/apps/client/src/locales/messages.de.xlf b/apps/client/src/locales/messages.de.xlf index e758fcf1d..340b2a562 100644 --- a/apps/client/src/locales/messages.de.xlf +++ b/apps/client/src/locales/messages.de.xlf @@ -66,7 +66,7 @@ Widerrufen apps/client/src/app/components/access-table/access-table.component.html - 65 + 74 @@ -74,7 +74,7 @@ Möchtest du diese Zugangsberechtigung wirklich widerrufen? apps/client/src/app/components/access-table/access-table.component.ts - 68 + 69 @@ -1018,7 +1018,7 @@ apps/client/src/app/pages/public/public-page.html - 164 + 220 @@ -1314,7 +1314,7 @@ apps/client/src/app/pages/public/public-page.html - 50 + 106 @@ -1580,6 +1580,10 @@ apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.html 270 + + apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.html + 187 + apps/client/src/app/pages/blog/blog-page.html 5 @@ -2070,7 +2074,7 @@ apps/client/src/app/pages/public/public-page.html - 87 + 143 @@ -2182,7 +2186,7 @@ apps/client/src/app/pages/public/public-page.html - 14 + 70 libs/ui/src/lib/assistant/assistant.html @@ -2374,7 +2378,7 @@ Währungen apps/client/src/app/pages/public/public-page.html - 32 + 88 @@ -2382,7 +2386,7 @@ Kontinente apps/client/src/app/pages/public/public-page.html - 68 + 124 @@ -2390,7 +2394,7 @@ Ghostfolio verschafft Ihnen den Überblick über Ihr Vermögen. apps/client/src/app/pages/public/public-page.html - 159 + 215 @@ -2722,7 +2726,7 @@ apps/client/src/app/pages/public/public-page.html - 104 + 160 @@ -2734,7 +2738,7 @@ apps/client/src/app/pages/public/public-page.html - 113 + 169 @@ -2746,7 +2750,7 @@ apps/client/src/app/pages/public/public-page.html - 122 + 178 @@ -2853,8 +2857,8 @@ 11 - - Hello, has shared a Portfolio with you! + + Hello, has shared a Portfolio with you! Hallo, hat ein Portfolio mit dir geteilt! apps/client/src/app/pages/public/public-page.html @@ -4682,7 +4686,7 @@ apps/client/src/app/pages/public/public-page.html - 132 + 188 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -5327,6 +5331,10 @@ apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.component.ts 13 + + apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.component.ts + 13 + apps/client/src/app/pages/landing/landing-page.component.ts 26 @@ -6027,7 +6035,7 @@ Ups, der Cash-Bestand Transfer ist fehlgeschlagen. apps/client/src/app/pages/accounts/accounts-page.component.ts - 311 + 317 @@ -6175,7 +6183,7 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html - 33 + 32 @@ -6187,7 +6195,7 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html - 36 + 34 @@ -6195,7 +6203,7 @@ Ups! Der Zugang konnte nicht gewährt werden. apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts - 91 + 90 @@ -6339,7 +6347,7 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html - 38 + 36 @@ -6687,7 +6695,7 @@ Möchtest du deine persönliche Anlagestrategie verfeinern? apps/client/src/app/pages/public/public-page.html - 155 + 211 @@ -7007,7 +7015,7 @@ Link in die Zwischenablage kopieren apps/client/src/app/components/access-table/access-table.component.html - 61 + 70 @@ -7066,6 +7074,38 @@ 67 + + No auto-renewal. + Keine automatische Erneuerung. + + apps/client/src/app/components/user-account-membership/user-account-membership.html + 61 + + + + Today + Heute + + apps/client/src/app/pages/public/public-page.html + 24 + + + + This year + Dieses Jahr + + apps/client/src/app/pages/public/public-page.html + 42 + + + + From the beginning + Seit Beginn + + apps/client/src/app/pages/public/public-page.html + 60 + + diff --git a/apps/client/src/locales/messages.es.xlf b/apps/client/src/locales/messages.es.xlf index 0be9acdd3..a0de164bc 100644 --- a/apps/client/src/locales/messages.es.xlf +++ b/apps/client/src/locales/messages.es.xlf @@ -67,7 +67,7 @@ Revoca apps/client/src/app/components/access-table/access-table.component.html - 65 + 74 @@ -75,7 +75,7 @@ ¿Quieres revocar el acceso concedido? apps/client/src/app/components/access-table/access-table.component.ts - 68 + 69 @@ -1019,7 +1019,7 @@ apps/client/src/app/pages/public/public-page.html - 164 + 220 @@ -1315,7 +1315,7 @@ apps/client/src/app/pages/public/public-page.html - 50 + 106 @@ -1581,6 +1581,10 @@ apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.html 270 + + apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.html + 187 + apps/client/src/app/pages/blog/blog-page.html 5 @@ -2071,7 +2075,7 @@ apps/client/src/app/pages/public/public-page.html - 87 + 143 @@ -2183,7 +2187,7 @@ apps/client/src/app/pages/public/public-page.html - 14 + 70 libs/ui/src/lib/assistant/assistant.html @@ -2375,7 +2379,7 @@ Divisas apps/client/src/app/pages/public/public-page.html - 32 + 88 @@ -2383,7 +2387,7 @@ Continentes apps/client/src/app/pages/public/public-page.html - 68 + 124 @@ -2391,7 +2395,7 @@ Ghostfolio te permite hacer un seguimiento de tu riqueza. apps/client/src/app/pages/public/public-page.html - 159 + 215 @@ -2647,7 +2651,7 @@ apps/client/src/app/pages/public/public-page.html - 104 + 160 @@ -2699,7 +2703,7 @@ apps/client/src/app/pages/public/public-page.html - 122 + 178 @@ -2711,7 +2715,7 @@ apps/client/src/app/pages/public/public-page.html - 113 + 169 @@ -2842,9 +2846,9 @@ 329 - - Hello, has shared a Portfolio with you! - Hola, ha compartido una Cartera contigo! + + Hello, has shared a Portfolio with you! + Hola, ha compartido una Cartera contigo! apps/client/src/app/pages/public/public-page.html 4 @@ -4683,7 +4687,7 @@ apps/client/src/app/pages/public/public-page.html - 132 + 188 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -5328,6 +5332,10 @@ apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.component.ts 13 + + apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.component.ts + 13 + apps/client/src/app/pages/landing/landing-page.component.ts 26 @@ -6028,7 +6036,7 @@ Oops, cash balance transfer has failed. apps/client/src/app/pages/accounts/accounts-page.component.ts - 311 + 317 @@ -6176,7 +6184,7 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html - 33 + 32 @@ -6188,7 +6196,7 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html - 36 + 34 @@ -6196,7 +6204,7 @@ Oops! Could not grant access. apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts - 91 + 90 @@ -6340,7 +6348,7 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html - 38 + 36 @@ -6688,7 +6696,7 @@ Would you like to refine your personal investment strategy? apps/client/src/app/pages/public/public-page.html - 155 + 211 @@ -7008,7 +7016,7 @@ Copy link to clipboard apps/client/src/app/components/access-table/access-table.component.html - 61 + 70 @@ -7067,6 +7075,38 @@ 67 + + No auto-renewal. + No auto-renewal. + + apps/client/src/app/components/user-account-membership/user-account-membership.html + 61 + + + + Today + Today + + apps/client/src/app/pages/public/public-page.html + 24 + + + + This year + This year + + apps/client/src/app/pages/public/public-page.html + 42 + + + + From the beginning + From the beginning + + apps/client/src/app/pages/public/public-page.html + 60 + + diff --git a/apps/client/src/locales/messages.fr.xlf b/apps/client/src/locales/messages.fr.xlf index 149d940df..37e0f7903 100644 --- a/apps/client/src/locales/messages.fr.xlf +++ b/apps/client/src/locales/messages.fr.xlf @@ -62,7 +62,7 @@ Révoquer apps/client/src/app/components/access-table/access-table.component.html - 65 + 74 @@ -70,7 +70,7 @@ Voulez-vous vraiment révoquer cet accès ? apps/client/src/app/components/access-table/access-table.component.ts - 68 + 69 @@ -818,7 +818,7 @@ apps/client/src/app/pages/public/public-page.html - 50 + 106 @@ -2328,6 +2328,10 @@ apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.html 270 + + apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.html + 187 + apps/client/src/app/pages/blog/blog-page.html 5 @@ -2646,7 +2650,7 @@ apps/client/src/app/pages/public/public-page.html - 87 + 143 @@ -2658,7 +2662,7 @@ apps/client/src/app/pages/public/public-page.html - 104 + 160 @@ -2670,7 +2674,7 @@ apps/client/src/app/pages/public/public-page.html - 113 + 169 @@ -2682,7 +2686,7 @@ apps/client/src/app/pages/public/public-page.html - 122 + 178 @@ -2818,7 +2822,7 @@ apps/client/src/app/pages/public/public-page.html - 14 + 70 libs/ui/src/lib/assistant/assistant.html @@ -2833,9 +2837,9 @@ 13 - - Hello, has shared a Portfolio with you! - Bonjour, a partagé un Portefeuille avec vous ! + + Hello, has shared a Portfolio with you! + Bonjour, a partagé un Portefeuille avec vous ! apps/client/src/app/pages/public/public-page.html 4 @@ -2846,7 +2850,7 @@ Devises apps/client/src/app/pages/public/public-page.html - 32 + 88 @@ -2854,7 +2858,7 @@ Continents apps/client/src/app/pages/public/public-page.html - 68 + 124 @@ -2862,7 +2866,7 @@ Ghostfolio vous aide à garder un aperçu de votre patrimoine. apps/client/src/app/pages/public/public-page.html - 159 + 215 @@ -2874,7 +2878,7 @@ apps/client/src/app/pages/public/public-page.html - 164 + 220 @@ -4682,7 +4686,7 @@ apps/client/src/app/pages/public/public-page.html - 132 + 188 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -5327,6 +5331,10 @@ apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.component.ts 13 + + apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.component.ts + 13 + apps/client/src/app/pages/landing/landing-page.component.ts 26 @@ -6027,7 +6035,7 @@ Oops, échec du transfert de la cash balance. apps/client/src/app/pages/accounts/accounts-page.component.ts - 311 + 317 @@ -6175,7 +6183,7 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html - 33 + 32 @@ -6187,7 +6195,7 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html - 36 + 34 @@ -6195,7 +6203,7 @@ Oops! Impossible d'accorder l'accès. apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts - 91 + 90 @@ -6339,7 +6347,7 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html - 38 + 36 @@ -6687,7 +6695,7 @@ Souhaitez-vous affiner votre stratégie d'investissement personnelle? apps/client/src/app/pages/public/public-page.html - 155 + 211 @@ -7007,7 +7015,7 @@ Copy link to clipboard apps/client/src/app/components/access-table/access-table.component.html - 61 + 70 @@ -7066,6 +7074,38 @@ 67 + + No auto-renewal. + No auto-renewal. + + apps/client/src/app/components/user-account-membership/user-account-membership.html + 61 + + + + Today + Today + + apps/client/src/app/pages/public/public-page.html + 24 + + + + This year + This year + + apps/client/src/app/pages/public/public-page.html + 42 + + + + From the beginning + From the beginning + + apps/client/src/app/pages/public/public-page.html + 60 + + diff --git a/apps/client/src/locales/messages.it.xlf b/apps/client/src/locales/messages.it.xlf index 23a2ea362..22a76f569 100644 --- a/apps/client/src/locales/messages.it.xlf +++ b/apps/client/src/locales/messages.it.xlf @@ -67,7 +67,7 @@ Revoca apps/client/src/app/components/access-table/access-table.component.html - 65 + 74 @@ -75,7 +75,7 @@ Vuoi davvero revocare l’accesso concesso? apps/client/src/app/components/access-table/access-table.component.ts - 68 + 69 @@ -1019,7 +1019,7 @@ apps/client/src/app/pages/public/public-page.html - 164 + 220 @@ -1315,7 +1315,7 @@ apps/client/src/app/pages/public/public-page.html - 50 + 106 @@ -1581,6 +1581,10 @@ apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.html 270 + + apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.html + 187 + apps/client/src/app/pages/blog/blog-page.html 5 @@ -2071,7 +2075,7 @@ apps/client/src/app/pages/public/public-page.html - 87 + 143 @@ -2183,7 +2187,7 @@ apps/client/src/app/pages/public/public-page.html - 14 + 70 libs/ui/src/lib/assistant/assistant.html @@ -2375,7 +2379,7 @@ Valute apps/client/src/app/pages/public/public-page.html - 32 + 88 @@ -2383,7 +2387,7 @@ Continenti apps/client/src/app/pages/public/public-page.html - 68 + 124 @@ -2391,7 +2395,7 @@ Ghostfolio ti permette di tenere traccia della tua ricchezza. apps/client/src/app/pages/public/public-page.html - 159 + 215 @@ -2647,7 +2651,7 @@ apps/client/src/app/pages/public/public-page.html - 104 + 160 @@ -2699,7 +2703,7 @@ apps/client/src/app/pages/public/public-page.html - 122 + 178 @@ -2711,7 +2715,7 @@ apps/client/src/app/pages/public/public-page.html - 113 + 169 @@ -2842,9 +2846,9 @@ 329 - - Hello, has shared a Portfolio with you! - Salve, ha condiviso un Portafoglio con te! + + Hello, has shared a Portfolio with you! + Salve, ha condiviso un Portafoglio con te! apps/client/src/app/pages/public/public-page.html 4 @@ -4683,7 +4687,7 @@ apps/client/src/app/pages/public/public-page.html - 132 + 188 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -5328,6 +5332,10 @@ apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.component.ts 13 + + apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.component.ts + 13 + apps/client/src/app/pages/landing/landing-page.component.ts 26 @@ -6028,7 +6036,7 @@ Ops, il trasferimento del saldo di cassa è fallito. apps/client/src/app/pages/accounts/accounts-page.component.ts - 311 + 317 @@ -6176,7 +6184,7 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html - 33 + 32 @@ -6188,7 +6196,7 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html - 36 + 34 @@ -6196,7 +6204,7 @@ Ops! Impossibile abilitare l'accesso. apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts - 91 + 90 @@ -6340,7 +6348,7 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html - 38 + 36 @@ -6688,7 +6696,7 @@ Vorresti perfezionare la tua strategia personale di investimento? apps/client/src/app/pages/public/public-page.html - 155 + 211 @@ -7008,7 +7016,7 @@ Copy link to clipboard apps/client/src/app/components/access-table/access-table.component.html - 61 + 70 @@ -7067,6 +7075,38 @@ 67 + + No auto-renewal. + No auto-renewal. + + apps/client/src/app/components/user-account-membership/user-account-membership.html + 61 + + + + Today + Today + + apps/client/src/app/pages/public/public-page.html + 24 + + + + This year + This year + + apps/client/src/app/pages/public/public-page.html + 42 + + + + From the beginning + From the beginning + + apps/client/src/app/pages/public/public-page.html + 60 + + diff --git a/apps/client/src/locales/messages.nl.xlf b/apps/client/src/locales/messages.nl.xlf index a324f53e8..a556fa01a 100644 --- a/apps/client/src/locales/messages.nl.xlf +++ b/apps/client/src/locales/messages.nl.xlf @@ -66,7 +66,7 @@ Intrekken apps/client/src/app/components/access-table/access-table.component.html - 65 + 74 @@ -74,7 +74,7 @@ Wil je deze verleende toegang echt intrekken? apps/client/src/app/components/access-table/access-table.component.ts - 68 + 69 @@ -1018,7 +1018,7 @@ apps/client/src/app/pages/public/public-page.html - 164 + 220 @@ -1314,7 +1314,7 @@ apps/client/src/app/pages/public/public-page.html - 50 + 106 @@ -1580,6 +1580,10 @@ apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.html 270 + + apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.html + 187 + apps/client/src/app/pages/blog/blog-page.html 5 @@ -2070,7 +2074,7 @@ apps/client/src/app/pages/public/public-page.html - 87 + 143 @@ -2182,7 +2186,7 @@ apps/client/src/app/pages/public/public-page.html - 14 + 70 libs/ui/src/lib/assistant/assistant.html @@ -2374,7 +2378,7 @@ Valuta apps/client/src/app/pages/public/public-page.html - 32 + 88 @@ -2382,7 +2386,7 @@ Continenten apps/client/src/app/pages/public/public-page.html - 68 + 124 @@ -2390,7 +2394,7 @@ Ghostfolio stelt je in staat om je vermogen bij te houden. apps/client/src/app/pages/public/public-page.html - 159 + 215 @@ -2646,7 +2650,7 @@ apps/client/src/app/pages/public/public-page.html - 104 + 160 @@ -2698,7 +2702,7 @@ apps/client/src/app/pages/public/public-page.html - 122 + 178 @@ -2710,7 +2714,7 @@ apps/client/src/app/pages/public/public-page.html - 113 + 169 @@ -2841,9 +2845,9 @@ 329 - - Hello, has shared a Portfolio with you! - Hallo, heeft een portefeuille met je gedeeld! + + Hello, has shared a Portfolio with you! + Hallo, heeft een portefeuille met je gedeeld! apps/client/src/app/pages/public/public-page.html 4 @@ -4682,7 +4686,7 @@ apps/client/src/app/pages/public/public-page.html - 132 + 188 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -5327,6 +5331,10 @@ apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.component.ts 13 + + apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.component.ts + 13 + apps/client/src/app/pages/landing/landing-page.component.ts 26 @@ -6027,7 +6035,7 @@ Oops, cash balance transfer has failed. apps/client/src/app/pages/accounts/accounts-page.component.ts - 311 + 317 @@ -6175,7 +6183,7 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html - 33 + 32 @@ -6187,7 +6195,7 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html - 36 + 34 @@ -6195,7 +6203,7 @@ Oops! Could not grant access. apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts - 91 + 90 @@ -6339,7 +6347,7 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html - 38 + 36 @@ -6687,7 +6695,7 @@ Would you like to refine your personal investment strategy? apps/client/src/app/pages/public/public-page.html - 155 + 211 @@ -7007,7 +7015,7 @@ Copy link to clipboard apps/client/src/app/components/access-table/access-table.component.html - 61 + 70 @@ -7066,6 +7074,38 @@ 67 + + No auto-renewal. + No auto-renewal. + + apps/client/src/app/components/user-account-membership/user-account-membership.html + 61 + + + + Today + Today + + apps/client/src/app/pages/public/public-page.html + 24 + + + + This year + This year + + apps/client/src/app/pages/public/public-page.html + 42 + + + + From the beginning + From the beginning + + apps/client/src/app/pages/public/public-page.html + 60 + + diff --git a/apps/client/src/locales/messages.pl.xlf b/apps/client/src/locales/messages.pl.xlf index 103140890..dd00df9df 100644 --- a/apps/client/src/locales/messages.pl.xlf +++ b/apps/client/src/locales/messages.pl.xlf @@ -73,6 +73,10 @@ apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.component.ts 13 + + apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.component.ts + 13 + apps/client/src/app/pages/landing/landing-page.component.ts 26 @@ -581,6 +585,10 @@ apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.html 270 + + apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.html + 187 + apps/client/src/app/pages/blog/blog-page.html 5 @@ -783,7 +791,7 @@ Cofnij apps/client/src/app/components/access-table/access-table.component.html - 65 + 74 @@ -791,7 +799,7 @@ Czy na pewno chcesz cofnąć przyznany dostęp? apps/client/src/app/components/access-table/access-table.component.ts - 68 + 69 @@ -1623,7 +1631,7 @@ apps/client/src/app/pages/public/public-page.html - 50 + 106 @@ -3343,7 +3351,7 @@ Ups, transfer salda nie powiódł się. apps/client/src/app/pages/accounts/accounts-page.component.ts - 311 + 317 @@ -3647,7 +3655,7 @@ apps/client/src/app/pages/public/public-page.html - 164 + 220 @@ -4471,7 +4479,7 @@ apps/client/src/app/pages/public/public-page.html - 87 + 143 @@ -4483,7 +4491,7 @@ apps/client/src/app/pages/public/public-page.html - 104 + 160 @@ -4495,7 +4503,7 @@ apps/client/src/app/pages/public/public-page.html - 113 + 169 @@ -4507,7 +4515,7 @@ apps/client/src/app/pages/public/public-page.html - 122 + 178 @@ -4519,7 +4527,7 @@ apps/client/src/app/pages/public/public-page.html - 132 + 188 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -4731,7 +4739,7 @@ apps/client/src/app/pages/public/public-page.html - 14 + 70 libs/ui/src/lib/assistant/assistant.html @@ -4946,9 +4954,9 @@ 301 - - Hello, has shared a Portfolio with you! - Hello, has shared a Portfolio with you! + + Hello, has shared a Portfolio with you! + Hello, has shared a Portfolio with you! apps/client/src/app/pages/public/public-page.html 4 @@ -4959,7 +4967,7 @@ Currencies apps/client/src/app/pages/public/public-page.html - 32 + 88 @@ -4967,7 +4975,7 @@ Continents apps/client/src/app/pages/public/public-page.html - 68 + 124 @@ -4975,7 +4983,7 @@ Ghostfolio empowers you to keep track of your wealth. apps/client/src/app/pages/public/public-page.html - 159 + 215 @@ -6175,7 +6183,7 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html - 33 + 32 @@ -6187,7 +6195,7 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html - 36 + 34 @@ -6195,7 +6203,7 @@ Ups! Nie udało się przyznać dostępu. apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts - 91 + 90 @@ -6339,7 +6347,7 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html - 38 + 36 @@ -6687,7 +6695,7 @@ Chcesz udoskonalić swoją osobistą strategię inwestycyjną? apps/client/src/app/pages/public/public-page.html - 155 + 211 @@ -7007,7 +7015,7 @@ Copy link to clipboard apps/client/src/app/components/access-table/access-table.component.html - 61 + 70 @@ -7066,6 +7074,38 @@ 67 + + No auto-renewal. + No auto-renewal. + + apps/client/src/app/components/user-account-membership/user-account-membership.html + 61 + + + + Today + Today + + apps/client/src/app/pages/public/public-page.html + 24 + + + + This year + This year + + apps/client/src/app/pages/public/public-page.html + 42 + + + + From the beginning + From the beginning + + apps/client/src/app/pages/public/public-page.html + 60 + + diff --git a/apps/client/src/locales/messages.pt.xlf b/apps/client/src/locales/messages.pt.xlf index 7ad18e060..467fbdeb1 100644 --- a/apps/client/src/locales/messages.pt.xlf +++ b/apps/client/src/locales/messages.pt.xlf @@ -62,7 +62,7 @@ Revogar apps/client/src/app/components/access-table/access-table.component.html - 65 + 74 @@ -70,7 +70,7 @@ Pretende realmente revogar este acesso concedido? apps/client/src/app/components/access-table/access-table.component.ts - 68 + 69 @@ -1614,7 +1614,7 @@ apps/client/src/app/pages/public/public-page.html - 50 + 106 @@ -2248,6 +2248,10 @@ apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.html 270 + + apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.html + 187 + apps/client/src/app/pages/blog/blog-page.html 5 @@ -2546,7 +2550,7 @@ apps/client/src/app/pages/public/public-page.html - 87 + 143 @@ -2558,7 +2562,7 @@ apps/client/src/app/pages/public/public-page.html - 104 + 160 @@ -2570,7 +2574,7 @@ apps/client/src/app/pages/public/public-page.html - 113 + 169 @@ -2582,7 +2586,7 @@ apps/client/src/app/pages/public/public-page.html - 122 + 178 @@ -2710,7 +2714,7 @@ apps/client/src/app/pages/public/public-page.html - 14 + 70 libs/ui/src/lib/assistant/assistant.html @@ -2725,9 +2729,9 @@ 13 - - Hello, has shared a Portfolio with you! - Olá, partilhou um Portefólio consigo! + + Hello, has shared a Portfolio with you! + Olá, partilhou um Portefólio consigo! apps/client/src/app/pages/public/public-page.html 4 @@ -2738,7 +2742,7 @@ Moedas apps/client/src/app/pages/public/public-page.html - 32 + 88 @@ -2746,7 +2750,7 @@ Continentes apps/client/src/app/pages/public/public-page.html - 68 + 124 @@ -2754,7 +2758,7 @@ O Ghostfolio permite-lhe estar a par e gerir a sua riqueza. apps/client/src/app/pages/public/public-page.html - 159 + 215 @@ -2766,7 +2770,7 @@ apps/client/src/app/pages/public/public-page.html - 164 + 220 @@ -4682,7 +4686,7 @@ apps/client/src/app/pages/public/public-page.html - 132 + 188 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -5327,6 +5331,10 @@ apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.component.ts 13 + + apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.component.ts + 13 + apps/client/src/app/pages/landing/landing-page.component.ts 26 @@ -6027,7 +6035,7 @@ Oops, cash balance transfer has failed. apps/client/src/app/pages/accounts/accounts-page.component.ts - 311 + 317 @@ -6175,7 +6183,7 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html - 33 + 32 @@ -6187,7 +6195,7 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html - 36 + 34 @@ -6195,7 +6203,7 @@ Oops! Could not grant access. apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts - 91 + 90 @@ -6339,7 +6347,7 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html - 38 + 36 @@ -6687,7 +6695,7 @@ Would you like to refine your personal investment strategy? apps/client/src/app/pages/public/public-page.html - 155 + 211 @@ -7007,7 +7015,7 @@ Copy link to clipboard apps/client/src/app/components/access-table/access-table.component.html - 61 + 70 @@ -7066,6 +7074,38 @@ 67 + + No auto-renewal. + No auto-renewal. + + apps/client/src/app/components/user-account-membership/user-account-membership.html + 61 + + + + Today + Today + + apps/client/src/app/pages/public/public-page.html + 24 + + + + This year + This year + + apps/client/src/app/pages/public/public-page.html + 42 + + + + From the beginning + From the beginning + + apps/client/src/app/pages/public/public-page.html + 60 + + diff --git a/apps/client/src/locales/messages.tr.xlf b/apps/client/src/locales/messages.tr.xlf index 3eed053a7..db640d37b 100644 --- a/apps/client/src/locales/messages.tr.xlf +++ b/apps/client/src/locales/messages.tr.xlf @@ -73,6 +73,10 @@ apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.component.ts 13 + + apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.component.ts + 13 + apps/client/src/app/pages/landing/landing-page.component.ts 26 @@ -557,6 +561,10 @@ apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.html 270 + + apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.html + 187 + apps/client/src/app/pages/blog/blog-page.html 5 @@ -759,7 +767,7 @@ Geri Al apps/client/src/app/components/access-table/access-table.component.html - 65 + 74 @@ -767,7 +775,7 @@ Bu erişim iznini geri almayı gerçekten istiyor musunuz? apps/client/src/app/components/access-table/access-table.component.ts - 68 + 69 @@ -1555,7 +1563,7 @@ apps/client/src/app/pages/public/public-page.html - 50 + 106 @@ -3211,7 +3219,7 @@ apps/client/src/app/pages/public/public-page.html - 164 + 220 @@ -3959,7 +3967,7 @@ apps/client/src/app/pages/public/public-page.html - 87 + 143 @@ -3971,7 +3979,7 @@ apps/client/src/app/pages/public/public-page.html - 104 + 160 @@ -3983,7 +3991,7 @@ apps/client/src/app/pages/public/public-page.html - 113 + 169 @@ -3995,7 +4003,7 @@ apps/client/src/app/pages/public/public-page.html - 122 + 178 @@ -4007,7 +4015,7 @@ apps/client/src/app/pages/public/public-page.html - 132 + 188 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -4195,7 +4203,7 @@ apps/client/src/app/pages/public/public-page.html - 14 + 70 libs/ui/src/lib/assistant/assistant.html @@ -4410,9 +4418,9 @@ 301 - - Hello, has shared a Portfolio with you! - Merhaba, size bir Portföy paylaştı! + + Hello, has shared a Portfolio with you! + Merhaba, size bir Portföy paylaştı! apps/client/src/app/pages/public/public-page.html 4 @@ -4423,7 +4431,7 @@ Para birimleri apps/client/src/app/pages/public/public-page.html - 32 + 88 @@ -4431,7 +4439,7 @@ Kıtalar apps/client/src/app/pages/public/public-page.html - 68 + 124 @@ -4439,7 +4447,7 @@ Ghostfolio, varlıklarınızı takip etmenizi sağlar. apps/client/src/app/pages/public/public-page.html - 159 + 215 @@ -6027,7 +6035,7 @@ Hay Allah, Nakit bakiyesi tranferi başarısız oldu. apps/client/src/app/pages/accounts/accounts-page.component.ts - 311 + 317 @@ -6175,7 +6183,7 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html - 33 + 32 @@ -6187,7 +6195,7 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html - 36 + 34 @@ -6195,7 +6203,7 @@ Oops! Could not grant access. apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts - 91 + 90 @@ -6339,7 +6347,7 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html - 38 + 36 @@ -6687,7 +6695,7 @@ Would you like to refine your personal investment strategy? apps/client/src/app/pages/public/public-page.html - 155 + 211 @@ -7007,7 +7015,7 @@ Copy link to clipboard apps/client/src/app/components/access-table/access-table.component.html - 61 + 70 @@ -7066,6 +7074,38 @@ 67 + + No auto-renewal. + No auto-renewal. + + apps/client/src/app/components/user-account-membership/user-account-membership.html + 61 + + + + Today + Today + + apps/client/src/app/pages/public/public-page.html + 24 + + + + This year + This year + + apps/client/src/app/pages/public/public-page.html + 42 + + + + From the beginning + From the beginning + + apps/client/src/app/pages/public/public-page.html + 60 + + diff --git a/apps/client/src/locales/messages.xlf b/apps/client/src/locales/messages.xlf index 10f332052..999284c8f 100644 --- a/apps/client/src/locales/messages.xlf +++ b/apps/client/src/locales/messages.xlf @@ -73,6 +73,10 @@ apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.component.ts 13 + + apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.component.ts + 13 + apps/client/src/app/pages/landing/landing-page.component.ts 26 @@ -566,6 +570,10 @@ apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.html 270 + + apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.html + 187 + apps/client/src/app/pages/blog/blog-page.html 5 @@ -755,14 +763,14 @@ Revoke apps/client/src/app/components/access-table/access-table.component.html - 65 + 74 Do you really want to revoke this granted access? apps/client/src/app/components/access-table/access-table.component.ts - 68 + 69 @@ -1550,7 +1558,7 @@ apps/client/src/app/pages/public/public-page.html - 50 + 106 @@ -3103,7 +3111,7 @@ Oops, cash balance transfer has failed. apps/client/src/app/pages/accounts/accounts-page.component.ts - 311 + 317 @@ -3375,7 +3383,7 @@ apps/client/src/app/pages/public/public-page.html - 164 + 220 @@ -4107,7 +4115,7 @@ apps/client/src/app/pages/public/public-page.html - 87 + 143 @@ -4118,7 +4126,7 @@ apps/client/src/app/pages/public/public-page.html - 104 + 160 @@ -4129,7 +4137,7 @@ apps/client/src/app/pages/public/public-page.html - 113 + 169 @@ -4140,7 +4148,7 @@ apps/client/src/app/pages/public/public-page.html - 122 + 178 @@ -4151,7 +4159,7 @@ apps/client/src/app/pages/public/public-page.html - 132 + 188 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -4339,7 +4347,7 @@ apps/client/src/app/pages/public/public-page.html - 14 + 70 libs/ui/src/lib/assistant/assistant.html @@ -4534,8 +4542,8 @@ 301 - - Hello, has shared a Portfolio with you! + + Hello, has shared a Portfolio with you! apps/client/src/app/pages/public/public-page.html 4 @@ -4545,21 +4553,21 @@ Currencies apps/client/src/app/pages/public/public-page.html - 32 + 88 Continents apps/client/src/app/pages/public/public-page.html - 68 + 124 Ghostfolio empowers you to keep track of your wealth. apps/client/src/app/pages/public/public-page.html - 159 + 215 @@ -5606,7 +5614,7 @@ Oops! Could not grant access. apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts - 91 + 90 @@ -5617,7 +5625,7 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html - 36 + 34 @@ -5628,7 +5636,7 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html - 33 + 32 @@ -5763,7 +5771,7 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html - 38 + 36 @@ -6062,7 +6070,7 @@ Would you like to refine your personal investment strategy? apps/client/src/app/pages/public/public-page.html - 155 + 211 @@ -6377,7 +6385,7 @@ Copy link to clipboard apps/client/src/app/components/access-table/access-table.component.html - 61 + 70 @@ -6394,6 +6402,34 @@ 15 + + No auto-renewal. + + apps/client/src/app/components/user-account-membership/user-account-membership.html + 61 + + + + From the beginning + + apps/client/src/app/pages/public/public-page.html + 60 + + + + This year + + apps/client/src/app/pages/public/public-page.html + 42 + + + + Today + + apps/client/src/app/pages/public/public-page.html + 24 + + diff --git a/apps/client/src/locales/messages.zh.xlf b/apps/client/src/locales/messages.zh.xlf index 3a804b376..e5b699287 100644 --- a/apps/client/src/locales/messages.zh.xlf +++ b/apps/client/src/locales/messages.zh.xlf @@ -74,6 +74,10 @@ apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.component.ts 13 + + apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.component.ts + 13 + apps/client/src/app/pages/landing/landing-page.component.ts 26 @@ -582,6 +586,10 @@ apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.html 270 + + apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.html + 187 + apps/client/src/app/pages/blog/blog-page.html 5 @@ -784,7 +792,7 @@ 撤销 apps/client/src/app/components/access-table/access-table.component.html - 65 + 74 @@ -792,7 +800,7 @@ 您真的要撤销此授予的访问权限吗? apps/client/src/app/components/access-table/access-table.component.ts - 68 + 69 @@ -1632,7 +1640,7 @@ apps/client/src/app/pages/public/public-page.html - 50 + 106 @@ -3360,7 +3368,7 @@ 糟糕,现金余额转账失败。 apps/client/src/app/pages/accounts/accounts-page.component.ts - 311 + 317 @@ -3664,7 +3672,7 @@ apps/client/src/app/pages/public/public-page.html - 164 + 220 @@ -4488,7 +4496,7 @@ apps/client/src/app/pages/public/public-page.html - 87 + 143 @@ -4500,7 +4508,7 @@ apps/client/src/app/pages/public/public-page.html - 104 + 160 @@ -4512,7 +4520,7 @@ apps/client/src/app/pages/public/public-page.html - 113 + 169 @@ -4524,7 +4532,7 @@ apps/client/src/app/pages/public/public-page.html - 122 + 178 @@ -4536,7 +4544,7 @@ apps/client/src/app/pages/public/public-page.html - 132 + 188 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -4748,7 +4756,7 @@ apps/client/src/app/pages/public/public-page.html - 14 + 70 libs/ui/src/lib/assistant/assistant.html @@ -4963,9 +4971,9 @@ 301 - - Hello, has shared a Portfolio with you! - 你好,分享了一个文件夹与你! + + Hello, has shared a Portfolio with you! + 你好,分享了一个文件夹与你! apps/client/src/app/pages/public/public-page.html 4 @@ -4976,7 +4984,7 @@ 货币 apps/client/src/app/pages/public/public-page.html - 32 + 88 @@ -4984,7 +4992,7 @@ 大陆 apps/client/src/app/pages/public/public-page.html - 68 + 124 @@ -4992,7 +5000,7 @@ Ghostfolio 使您能够跟踪您的财富。 apps/client/src/app/pages/public/public-page.html - 159 + 215 @@ -6172,7 +6180,7 @@ 哎呀!无法授予访问权限。 apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts - 91 + 90 @@ -6184,7 +6192,7 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html - 36 + 34 @@ -6196,7 +6204,7 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html - 33 + 32 @@ -6348,7 +6356,7 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html - 38 + 36 @@ -6688,7 +6696,7 @@ Would you like to refine your personal investment strategy? apps/client/src/app/pages/public/public-page.html - 155 + 211 @@ -7008,7 +7016,7 @@ Copy link to clipboard apps/client/src/app/components/access-table/access-table.component.html - 61 + 70 @@ -7067,6 +7075,38 @@ 67 + + No auto-renewal. + No auto-renewal. + + apps/client/src/app/components/user-account-membership/user-account-membership.html + 61 + + + + Today + Today + + apps/client/src/app/pages/public/public-page.html + 24 + + + + This year + This year + + apps/client/src/app/pages/public/public-page.html + 42 + + + + From the beginning + From the beginning + + apps/client/src/app/pages/public/public-page.html + 60 + + From e7f10ad4ad6970b2dbb359c17ecc6d5792942bb5 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Tue, 24 Sep 2024 11:10:59 +0200 Subject: [PATCH 73/78] Bugfix/fix typo and update date of Hacktoberfest 2024 blog post (#3811) * Fix typo and update date --- .../2024/09/hacktoberfest-2024/hacktoberfest-2024-page.html | 4 ++-- apps/client/src/app/pages/blog/blog-page.html | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.html b/apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.html index 5b4a0353b..7f6ad024e 100644 --- a/apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.html +++ b/apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.html @@ -4,7 +4,7 @@

    Hacktoberfest 2024

    -
    2024-09-21
    +
    2024-09-24
    Hacktoberfest 2024 with Ghostfolio Teaserthird time and look forward to connecting with new, enthusiastic open-source - contributors. Hacktoberfest is a a month-long celebration of all + contributors. Hacktoberfest is a month-long celebration of all things open-source: projects, their maintainers, and the entire community of contributors. Every October, open source maintainers around the globe dedicate extra time to support new contributors diff --git a/apps/client/src/app/pages/blog/blog-page.html b/apps/client/src/app/pages/blog/blog-page.html index f5a4b22fd..73b4b0908 100644 --- a/apps/client/src/app/pages/blog/blog-page.html +++ b/apps/client/src/app/pages/blog/blog-page.html @@ -18,7 +18,7 @@ >
    Hacktoberfest 2024
    -
    2024-09-21
    +
    2024-09-24
    Date: Tue, 24 Sep 2024 18:53:25 +0200 Subject: [PATCH 74/78] Feature/add horizontal lines to separate delete actions in menus (#3805) * Add horizontal lines to separate delete action * Update changelog --- CHANGELOG.md | 1 + .../src/app/components/access-table/access-table.component.html | 1 + .../app/components/accounts-table/accounts-table.component.html | 1 + apps/client/src/app/components/admin-jobs/admin-jobs.html | 1 + .../src/app/components/admin-market-data/admin-market-data.html | 2 ++ .../asset-profile-dialog/asset-profile-dialog.html | 1 + .../src/app/components/admin-overview/admin-overview.html | 1 + .../app/components/admin-platform/admin-platform.component.html | 1 + .../src/app/components/admin-tag/admin-tag.component.html | 1 + apps/client/src/app/components/admin-users/admin-users.html | 1 + .../ui/src/lib/activities-table/activities-table.component.html | 2 ++ 11 files changed, 13 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 38fb0dde2..2a8920872 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 +- Improved the usability of various action menus by introducing horizontal lines to separate the delete action - Considered the user’s language in the link of the access table to share the portfolio - Improved the language localization for German (`de`) diff --git a/apps/client/src/app/components/access-table/access-table.component.html b/apps/client/src/app/components/access-table/access-table.component.html index 8716873a7..2a20e4631 100644 --- a/apps/client/src/app/components/access-table/access-table.component.html +++ b/apps/client/src/app/components/access-table/access-table.component.html @@ -69,6 +69,7 @@ +
    } +
    +
    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 a151d1cd0..de5707d02 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 @@ -197,6 +197,7 @@ +
    +
    +
    +
    } } +
    +
    - + @if (user?.settings?.isExperimentalFeatures) { +
    + +
    + }
    diff --git a/libs/common/src/lib/interfaces/responses/account-balances-response.interface.ts b/libs/common/src/lib/interfaces/responses/account-balances-response.interface.ts index 98a765e8a..a623baaff 100644 --- a/libs/common/src/lib/interfaces/responses/account-balances-response.interface.ts +++ b/libs/common/src/lib/interfaces/responses/account-balances-response.interface.ts @@ -1,7 +1,7 @@ import { AccountBalance } from '@prisma/client'; export interface AccountBalancesResponse { - balances: (Pick & { + balances: (Pick & { valueInBaseCurrency: number; })[]; } From ba438c25ef7021eca2a3c077bf2298b1b20ab23d Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Tue, 24 Sep 2024 19:47:46 +0200 Subject: [PATCH 77/78] Release 2.110.0 (#3816) --- CHANGELOG.md | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ee84dd06..c42980218 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased +## 2.110.0 - 2024-09-24 ### Changed @@ -15,7 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Considered the user’s language in the link of the access table to share the portfolio - Improved the language localization for German (`de`) -## 2.109.0 - 2024-09-17 +## 2.109.0 - 2024-09-21 ### Added diff --git a/package.json b/package.json index 4519558a9..e03fc937c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "2.109.0", + "version": "2.110.0", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "repository": "https://github.com/ghostfolio/ghostfolio", From 395d7f08ac9cb5d0a35c56053898abfdc4519c64 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Wed, 25 Sep 2024 18:07:24 +0200 Subject: [PATCH 78/78] Feature/upgrade webpack bundle analyzer to version 4.10.2 (#3818) * Upgrade webpack-bundle-analyzer to version 4.10.2 * Update changelog --- CHANGELOG.md | 6 ++++++ package-lock.json | 23 +++++++---------------- package.json | 2 +- 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c42980218..49e7bfb12 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Changed + +- Upgraded `webpack-bundle-analyzer` from version `4.10.1` to `4.10.2` + ## 2.110.0 - 2024-09-24 ### Changed diff --git a/package-lock.json b/package-lock.json index be502a497..55a0dd609 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ghostfolio", - "version": "2.108.0", + "version": "2.110.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ghostfolio", - "version": "2.108.0", + "version": "2.110.0", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { @@ -158,7 +158,7 @@ "ts-node": "10.9.2", "tslib": "2.6.0", "typescript": "5.5.3", - "webpack-bundle-analyzer": "4.10.1" + "webpack-bundle-analyzer": "4.10.2" }, "engines": { "node": ">=20" @@ -33666,10 +33666,11 @@ } }, "node_modules/webpack-bundle-analyzer": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.1.tgz", - "integrity": "sha512-s3P7pgexgT/HTUSYgxJyn28A+99mmLq4HsJepMPzu0R8ImJc52QNqaFYW1Z2z2uIb1/J3eYgaAWVpaC+v/1aAQ==", + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.2.tgz", + "integrity": "sha512-vJptkMm9pk5si4Bv922ZbKLV8UTT4zib4FPgXMhgzUny0bfDDkLXAVQs3ly3fS4/TN9ROFtb0NFrm04UXFE/Vw==", "dev": true, + "license": "MIT", "dependencies": { "@discoveryjs/json-ext": "0.5.7", "acorn": "^8.0.4", @@ -33679,7 +33680,6 @@ "escape-string-regexp": "^4.0.0", "gzip-size": "^6.0.0", "html-escaper": "^2.0.2", - "is-plain-object": "^5.0.0", "opener": "^1.5.2", "picocolors": "^1.0.0", "sirv": "^2.0.3", @@ -33713,15 +33713,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/webpack-bundle-analyzer/node_modules/is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/webpack-bundle-analyzer/node_modules/ws": { "version": "7.5.10", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", diff --git a/package.json b/package.json index e03fc937c..6b1c1a09b 100644 --- a/package.json +++ b/package.json @@ -202,7 +202,7 @@ "ts-node": "10.9.2", "tslib": "2.6.0", "typescript": "5.5.3", - "webpack-bundle-analyzer": "4.10.1" + "webpack-bundle-analyzer": "4.10.2" }, "engines": { "node": ">=20"