diff --git a/.github/workflows/build-code.yml b/.github/workflows/build-code.yml index 7a8f72ac4..bd5d1efdc 100644 --- a/.github/workflows/build-code.yml +++ b/.github/workflows/build-code.yml @@ -13,7 +13,7 @@ jobs: strategy: matrix: node_version: - - 22 + - 22.22.1 steps: - name: Checkout code uses: actions/checkout@v4 diff --git a/CHANGELOG.md b/CHANGELOG.md index 90430f5c4..407767cac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,215 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Added + +- Added support for a copy-to-clipboard functionality in the value component +- Extended the holding detail dialog by adding a copy-to-clipboard button for the ISIN number (experimental) +- Extended the holding detail dialog by adding a copy-to-clipboard button for the symbol (experimental) +- Extended the user detail dialog of the admin control panel’s users section by adding a copy-to-clipboard button for the user id + +### Changed + +- Improved the language localization for German (`de`) +- Improved the language localization for Spanish (`es`) +- Upgraded `countries-list` from version `3.2.2` to `3.3.0` +- Upgraded `ng-extract-i18n-merge` from `3.2.1` to `3.3.0` +- Upgraded `stripe` from version `20.3.0` to `20.4.1` + +## 2.251.0 - 2026-03-24 + +### Added + +- Added the quantity column to the holdings table of the portfolio holdings page + +### Changed + +- Hardened the endpoint `DELETE /api/v1/auth-device/:id` by improving the user validation +- Improved the allocations by ETF holding on the allocations page by refining the grouping of the same assets with diverging names (experimental) +- Improved the language localization for Polish (`pl`) +- Upgraded `@trivago/prettier-plugin-sort-imports` from version `5.2.2` to `6.0.2` + +### Fixed + +- Fixed an issue by adding a missing guard in the public access for portfolio sharing + +## 2.250.0 - 2026-03-17 + +### Added + +- Added support for specific calendar year date ranges (`2025`, `2024`, `2023`, etc.) on the portfolio activities page + +### Changed + +- Consolidated the sign-out logic within the user service to unify cookie, state and token clearance +- Improved the language localization for Polish (`pl`) +- Upgraded `@ionic/angular` from version `8.7.3` to `8.8.1` +- Upgraded `replace-in-file` from version `8.3.0` to `8.4.0` +- Upgraded `svgmap` from version `2.14.0` to `2.19.2` +- Pinned the _Node.js_ version in the _Build code_ _GitHub Action_ to ensure environment consistency for tests + +### Fixed + +- Fixed an issue with the detection of the thousand separator for the `de-CH` locale +- Fixed an issue in the _Storybook_ stories of the symbol autocomplete component caused by a circular dependency + +## 2.249.0 - 2026-03-10 + +### Added + +- Integrated _Bull Dashboard_ for a detailed jobs queue view in the admin control panel (experimental) +- Added a debounce to the `PortfolioChangedListener` and `AssetProfileChangedListener` to minimize redundant _Redis_ and database operations + +### Changed + +- Improved the _Storybook_ stories of the value component +- Improved the language localization for Dutch (`nl`) +- Improved the language localization for German (`de`) +- Upgraded `class-validator` from version `0.14.3` to `0.15.1` + +### Fixed + +- Fixed false _Redis_ health check failures by using unique keys and increasing the timeout to 5s + +## 2.248.0 - 2026-03-07 + +### Added + +- Added support for column sorting to the data providers management of the admin control panel + +### Changed + +- Included asset profile data in the endpoint `GET api/v1/portfolio/holdings` +- Included asset profile data in the holdings of the public page +- Reused the value component in the platform management of the admin control panel +- Reused the value component in the tag management of the admin control panel +- Deprecated the `api/v1/order` endpoints in favor of the `api/v1/activities` endpoints +- Upgraded `jsonpath` from version `1.1.1` to `1.2.1` + +### Fixed + +- Fixed an issue in the _FIRE_ calculator to correctly calculate the projected total amount + +## 2.247.0 - 2026-03-04 + +### Changed + +- Upgraded `yahoo-finance2` from version `3.13.0` to `3.13.2` + +## 2.246.0 - 2026-03-03 + +### Changed + +- Removed the deprecated `committedFunds` from the summary of the portfolio details endpoint +- Upgraded `Nx` from version `22.4.5` to `22.5.3` + +### Fixed + +- Fixed an issue where the apply and reset filter buttons remained disabled in the assistant + +## 2.245.0 - 2026-03-01 + +### Changed + +- Excluded the scraper configuration from the import and export functionality +- Excluded the symbol mapping from the import and export functionality +- Improved the language localization for Dutch (`nl`) +- Improved the language localization for Italian (`it`) +- Improved the language localization for Spanish (`es`) + +### Fixed + +- Resolved the data source transformation in the errors of the performance endpoint +- Resolved the data source transformation in the export functionality + +## 2.244.0 - 2026-02-28 + +### Changed + +- Improved the usability of the asset profile details dialog in the admin control panel for currencies +- Removed the deprecated static portfolio analysis rule: _Fees_ (Fee Ratio) +- Refactored queries in the data provider service to use Prisma’s safe query methods + +### Fixed + +- Fixed an exception by adding a fallback for missing market price values on the _X-ray_ page + +## 2.243.0 - 2026-02-23 + +### Changed + +- Improved the language localization for Chinese (`zh`) +- Upgraded `nestjs` from version `11.1.8` to `11.1.14` + +### Fixed + +- Fixed an issue when creating activities of type `FEE`, `INTEREST` or `LIABILITY` + +## 2.242.0 - 2026-02-22 + +### Changed + +- Changed the account field to optional in the create or update activity dialog + +### Fixed + +- Fixed a validation issue for valuables used in the create and import activity logic +- Fixed the page size for presets in the historical market data table of the admin control panel + +## 2.241.0 - 2026-02-21 + +### Changed + +- Improved the usability of the portfolio summary tab on the home page in the _Presenter View_ +- Refreshed the cryptocurrencies list +- Improved the language localization for German (`de`) +- Improved the language localization for Spanish (`es`) + +### Fixed + +- Fixed an issue with `balanceInBaseCurrency` of the accounts in the value redaction interceptor for the impersonation mode +- Fixed an issue with `comment` of the accounts in the value redaction interceptor for the impersonation mode +- Fixed an issue with `dividendInBaseCurrency` of the accounts in the value redaction interceptor for the impersonation mode +- Fixed an issue with `interestInBaseCurrency` of the accounts in the value redaction interceptor for the impersonation mode +- Fixed an issue with `value` of the accounts in the value redaction interceptor for the impersonation mode + +## 2.240.0 - 2026-02-18 + +### Added + +- Added a _No Activities_ preset to the historical market data table of the admin control panel +- Added support for custom cryptocurrencies defined in the database +- Added support for the cryptocurrency _Sky_ + +### Changed + +- Harmonized the validation for the create activity endpoint with the existing import activity logic +- Upgraded `marked` from version `17.0.1` to `17.0.2` +- Upgraded `ngx-markdown` from version `21.0.1` to `21.1.0` + +## 2.239.0 - 2026-02-15 + +### Added + +- Added a new static portfolio analysis rule based on the total investment volume: _Fees_ (Fee Ratio) +- Extended the content of the _Self-Hosting_ section on the Frequently Asked Questions (FAQ) page with information on derived currencies + +### Changed + +- Deprecated the existing static portfolio analysis rule: _Fees_ (Fee Ratio) +- Ignored nested ETFs when fetching top holdings for ETF and mutual fund assets from _Yahoo Finance_ +- Improved the scraper configuration with more detailed error messages +- Improved the language localization for German (`de`) +- Upgraded `@simplewebauthn/browser` and `@simplewebauthn/server` from version `13.1.0` to `13.2.2` +- Upgraded `cheerio` from version `1.0.0` to `1.2.0` + +### Fixed + +- Fixed the investment value by including currency effects in the portfolio summary tab on the home page +- Added the missing `valueInBaseCurrency` to the response of the import activities endpoint + ## 2.238.0 - 2026-02-12 ### Changed diff --git a/README.md b/README.md index 3be15e49f..44212b607 100644 --- a/README.md +++ b/README.md @@ -313,10 +313,12 @@ Ghostfolio is **100% free** and **open source**. We encourage and support an act Not sure what to work on? We have [some ideas](https://github.com/ghostfolio/ghostfolio/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22%20no%3Aassignee), even for [newcomers](https://github.com/ghostfolio/ghostfolio/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22%20no%3Aassignee). Please join the Ghostfolio [Slack](https://join.slack.com/t/ghostfolio/shared_invite/zt-vsaan64h-F_I0fEo5M0P88lP9ibCxFg) channel or post to [@ghostfolio\_](https://x.com/ghostfolio_) on _X_. We would love to hear from you. -If you like to support this project, become a [**Sponsor**](https://github.com/sponsors/ghostfolio), get [**Ghostfolio Premium**](https://ghostfol.io/en/pricing) or [**Buy me a coffee**](https://www.buymeacoffee.com/ghostfolio). - ## Sponsors +If you like to support this project, get [**Ghostfolio Premium**](https://ghostfol.io/en/pricing), become a [**Sponsor**](https://github.com/sponsors/ghostfolio) or [**Buy me a coffee**](https://www.buymeacoffee.com/ghostfolio). + +
+
TestMu AI Logo diff --git a/apps/api/src/app/order/order.controller.ts b/apps/api/src/app/activities/activities.controller.ts similarity index 78% rename from apps/api/src/app/order/order.controller.ts rename to apps/api/src/app/activities/activities.controller.ts index 73c295f1b..141fd4c82 100644 --- a/apps/api/src/app/order/order.controller.ts +++ b/apps/api/src/app/activities/activities.controller.ts @@ -4,6 +4,7 @@ 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 { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.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'; @@ -36,27 +37,32 @@ import { } from '@nestjs/common'; import { REQUEST } from '@nestjs/core'; import { AuthGuard } from '@nestjs/passport'; -import { Order as OrderModel, Prisma } from '@prisma/client'; +import { Order, Prisma } from '@prisma/client'; import { parseISO } from 'date-fns'; import { StatusCodes, getReasonPhrase } from 'http-status-codes'; -import { OrderService } from './order.service'; +import { ActivitiesService } from './activities.service'; -@Controller('order') -export class OrderController { +@Controller([ + 'activities', + /** @deprecated */ + 'order' +]) +export class ActivitiesController { public constructor( + private readonly activitiesService: ActivitiesService, private readonly apiService: ApiService, + private readonly dataProviderService: DataProviderService, private readonly dataGatheringService: DataGatheringService, private readonly impersonationService: ImpersonationService, - private readonly orderService: OrderService, @Inject(REQUEST) private readonly request: RequestWithUser ) {} @Delete() - @HasPermission(permissions.deleteOrder) + @HasPermission(permissions.deleteActivity) @UseGuards(AuthGuard('jwt'), HasPermissionGuard) @UseInterceptors(TransformDataSourceInRequestInterceptor) - public async deleteOrders( + public async deleteActivities( @Query('accounts') filterByAccounts?: string, @Query('assetClasses') filterByAssetClasses?: string, @Query('dataSource') filterByDataSource?: string, @@ -71,29 +77,29 @@ export class OrderController { filterByTags }); - return this.orderService.deleteOrders({ + return this.activitiesService.deleteActivities({ filters, userId: this.request.user.id }); } @Delete(':id') - @HasPermission(permissions.deleteOrder) + @HasPermission(permissions.deleteActivity) @UseGuards(AuthGuard('jwt'), HasPermissionGuard) - public async deleteOrder(@Param('id') id: string): Promise { - const order = await this.orderService.order({ + public async deleteActivity(@Param('id') id: string): Promise { + const activity = await this.activitiesService.order({ id, userId: this.request.user.id }); - if (!order) { + if (!activity) { throw new HttpException( getReasonPhrase(StatusCodes.FORBIDDEN), StatusCodes.FORBIDDEN ); } - return this.orderService.deleteOrder({ + return this.activitiesService.deleteActivity({ id }); } @@ -103,7 +109,7 @@ export class OrderController { @UseInterceptors(RedactValuesInResponseInterceptor) @UseInterceptors(TransformDataSourceInRequestInterceptor) @UseInterceptors(TransformDataSourceInResponseInterceptor) - public async getAllOrders( + public async getAllActivities( @Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string, @Query('accounts') filterByAccounts?: string, @Query('assetClasses') filterByAssetClasses?: string, @@ -120,7 +126,7 @@ export class OrderController { let startDate: Date; if (dateRange) { - ({ endDate, startDate } = getIntervalFromDateRange(dateRange)); + ({ endDate, startDate } = getIntervalFromDateRange({ dateRange })); } const filters = this.apiService.buildFiltersFromQueryParams({ @@ -135,7 +141,7 @@ export class OrderController { await this.impersonationService.validateImpersonationId(impersonationId); const userCurrency = this.request.user.settings.settings.baseCurrency; - const { activities, count } = await this.orderService.getOrders({ + const { activities, count } = await this.activitiesService.getActivities({ endDate, filters, sortColumn, @@ -156,7 +162,7 @@ export class OrderController { @UseGuards(AuthGuard('jwt'), HasPermissionGuard) @UseInterceptors(RedactValuesInResponseInterceptor) @UseInterceptors(TransformDataSourceInResponseInterceptor) - public async getOrderById( + public async getActivityById( @Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string, @Param('id') id: string ): Promise { @@ -164,7 +170,7 @@ export class OrderController { await this.impersonationService.validateImpersonationId(impersonationId); const userCurrency = this.request.user.settings.settings.baseCurrency; - const { activities } = await this.orderService.getOrders({ + const { activities } = await this.activitiesService.getActivities({ userCurrency, includeDrafts: true, userId: impersonationUserId || this.request.user.id, @@ -185,11 +191,34 @@ export class OrderController { return activity; } - @HasPermission(permissions.createOrder) + @HasPermission(permissions.createActivity) @Post() @UseGuards(AuthGuard('jwt'), HasPermissionGuard) @UseInterceptors(TransformDataSourceInRequestInterceptor) - public async createOrder(@Body() data: CreateOrderDto): Promise { + public async createActivity(@Body() data: CreateOrderDto): Promise { + try { + await this.dataProviderService.validateActivities({ + activitiesDto: [ + { + currency: data.currency, + dataSource: data.dataSource, + symbol: data.symbol, + type: data.type + } + ], + maxActivitiesToImport: 1, + user: this.request.user + }); + } catch (error) { + throw new HttpException( + { + error: getReasonPhrase(StatusCodes.BAD_REQUEST), + message: [error.message] + }, + StatusCodes.BAD_REQUEST + ); + } + const currency = data.currency; const customCurrency = data.customCurrency; const dataSource = data.dataSource; @@ -202,7 +231,7 @@ export class OrderController { delete data.dataSource; - const order = await this.orderService.createOrder({ + const activity = await this.activitiesService.createActivity({ ...data, date: parseISO(data.date), SymbolProfile: { @@ -227,14 +256,14 @@ export class OrderController { userId: this.request.user.id }); - if (dataSource && !order.isDraft) { + if (dataSource && !activity.isDraft) { // Gather symbol data in the background, if data source is set // (not MANUAL) and not draft this.dataGatheringService.gatherSymbols({ dataGatheringItems: [ { dataSource, - date: order.date, + date: activity.date, symbol: data.symbol } ], @@ -242,19 +271,22 @@ export class OrderController { }); } - return order; + return activity; } - @HasPermission(permissions.updateOrder) + @HasPermission(permissions.updateActivity) @Put(':id') @UseGuards(AuthGuard('jwt'), HasPermissionGuard) @UseInterceptors(TransformDataSourceInRequestInterceptor) - public async update(@Param('id') id: string, @Body() data: UpdateOrderDto) { - const originalOrder = await this.orderService.order({ + public async updateActivity( + @Param('id') id: string, + @Body() data: UpdateOrderDto + ) { + const originalActivity = await this.activitiesService.order({ id }); - if (!originalOrder || originalOrder.userId !== this.request.user.id) { + if (!originalActivity || originalActivity.userId !== this.request.user.id) { throw new HttpException( getReasonPhrase(StatusCodes.FORBIDDEN), StatusCodes.FORBIDDEN @@ -277,7 +309,7 @@ export class OrderController { delete data.dataSource; - return this.orderService.updateOrder({ + return this.activitiesService.updateActivity({ data: { ...data, date, diff --git a/apps/api/src/app/order/order.module.ts b/apps/api/src/app/activities/activities.module.ts similarity index 86% rename from apps/api/src/app/order/order.module.ts rename to apps/api/src/app/activities/activities.module.ts index 9bc837aa6..7476ad66a 100644 --- a/apps/api/src/app/order/order.module.ts +++ b/apps/api/src/app/activities/activities.module.ts @@ -15,12 +15,12 @@ import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/sym import { Module } from '@nestjs/common'; -import { OrderController } from './order.controller'; -import { OrderService } from './order.service'; +import { ActivitiesController } from './activities.controller'; +import { ActivitiesService } from './activities.service'; @Module({ - controllers: [OrderController], - exports: [OrderService], + controllers: [ActivitiesController], + exports: [ActivitiesService], imports: [ ApiModule, CacheModule, @@ -35,6 +35,6 @@ import { OrderService } from './order.service'; TransformDataSourceInRequestModule, TransformDataSourceInResponseModule ], - providers: [AccountBalanceService, AccountService, OrderService] + providers: [AccountBalanceService, AccountService, ActivitiesService] }) -export class OrderModule {} +export class ActivitiesModule {} diff --git a/apps/api/src/app/order/order.service.ts b/apps/api/src/app/activities/activities.service.ts similarity index 93% rename from apps/api/src/app/order/order.service.ts rename to apps/api/src/app/activities/activities.service.ts index 9a4f1e46b..89b9468f8 100644 --- a/apps/api/src/app/order/order.service.ts +++ b/apps/api/src/app/activities/activities.service.ts @@ -44,7 +44,7 @@ import { groupBy, uniqBy } from 'lodash'; import { randomUUID } from 'node:crypto'; @Injectable() -export class OrderService { +export class ActivitiesService { public constructor( private readonly accountBalanceService: AccountBalanceService, private readonly accountService: AccountService, @@ -62,7 +62,7 @@ export class OrderService { tags, userId }: { tags: Tag[]; userId: string } & AssetProfileIdentifier) { - const orders = await this.prismaService.order.findMany({ + const activities = await this.prismaService.order.findMany({ where: { userId, SymbolProfile: { @@ -73,7 +73,7 @@ export class OrderService { }); await Promise.all( - orders.map(({ id }) => + activities.map(({ id }) => this.prismaService.order.update({ data: { tags: { @@ -96,7 +96,7 @@ export class OrderService { ); } - public async createOrder( + public async createActivity( data: Prisma.OrderCreateInput & { accountId?: string; assetClass?: AssetClass; @@ -201,7 +201,7 @@ export class OrderService { ? false : isAfter(data.date as Date, endOfToday()); - const order = await this.prismaService.order.create({ + const activity = await this.prismaService.order.create({ data: { ...orderData, account, @@ -235,56 +235,56 @@ export class OrderService { this.eventEmitter.emit( AssetProfileChangedEvent.getName(), new AssetProfileChangedEvent({ - currency: order.SymbolProfile.currency, - dataSource: order.SymbolProfile.dataSource, - symbol: order.SymbolProfile.symbol + currency: activity.SymbolProfile.currency, + dataSource: activity.SymbolProfile.dataSource, + symbol: activity.SymbolProfile.symbol }) ); this.eventEmitter.emit( PortfolioChangedEvent.getName(), new PortfolioChangedEvent({ - userId: order.userId + userId: activity.userId }) ); - return order; + return activity; } - public async deleteOrder( + public async deleteActivity( where: Prisma.OrderWhereUniqueInput ): Promise { - const order = await this.prismaService.order.delete({ + const activity = await this.prismaService.order.delete({ where }); const [symbolProfile] = await this.symbolProfileService.getSymbolProfilesByIds([ - order.symbolProfileId + activity.symbolProfileId ]); if (symbolProfile.activitiesCount === 0) { - await this.symbolProfileService.deleteById(order.symbolProfileId); + await this.symbolProfileService.deleteById(activity.symbolProfileId); } this.eventEmitter.emit( PortfolioChangedEvent.getName(), new PortfolioChangedEvent({ - userId: order.userId + userId: activity.userId }) ); - return order; + return activity; } - public async deleteOrders({ + public async deleteActivities({ filters, userId }: { filters?: Filter[]; userId: string; }): Promise { - const { activities } = await this.getOrders({ + const { activities } = await this.getActivities({ filters, userId, includeDrafts: true, @@ -324,7 +324,7 @@ export class OrderService { } /** - * Generates synthetic orders for cash holdings based on account balance history. + * Generates synthetic activities for cash holdings based on account balance history. * Treat currencies as assets with a fixed unit price of 1.0 (in their own currency) to allow * performance tracking based on exchange rate fluctuations. * @@ -334,7 +334,7 @@ export class OrderService { * @param userId - The ID of the user. * @returns A response containing the list of synthetic cash activities. */ - public async getCashOrders({ + public async getCashActivities({ cashDetails, filters = [], userCurrency, @@ -448,7 +448,10 @@ export class OrderService { }; } - public async getLatestOrder({ dataSource, symbol }: AssetProfileIdentifier) { + public async getLatestActivity({ + dataSource, + symbol + }: AssetProfileIdentifier) { return this.prismaService.order.findFirst({ orderBy: { date: 'desc' @@ -459,7 +462,7 @@ export class OrderService { }); } - public async getOrders({ + public async getActivities({ endDate, filters, includeDrafts = false, @@ -742,17 +745,17 @@ export class OrderService { } /** - * Retrieves all orders required for the portfolio calculator, including both standard asset orders - * and optional synthetic orders representing cash activities. + * Retrieves all activities required for the portfolio calculator, including both standard asset activities + * and optional synthetic activities representing cash activities. */ @LogPerformance - public async getOrdersForPortfolioCalculator({ + public async getActivitiesForPortfolioCalculator({ filters, userCurrency, userId, withCash = false }: { - /** Optional filters to apply to the orders. */ + /** Optional filters to apply to the activities. */ filters?: Filter[]; /** The base currency of the user. */ userCurrency: string; @@ -761,7 +764,7 @@ export class OrderService { /** Whether to include cash activities in the result. */ withCash?: boolean; }) { - const orders = await this.getOrders({ + const activities = await this.getActivities({ filters, userCurrency, userId, @@ -775,18 +778,18 @@ export class OrderService { currency: userCurrency }); - const cashOrders = await this.getCashOrders({ + const cashActivities = await this.getCashActivities({ cashDetails, filters, userCurrency, userId }); - orders.activities.push(...cashOrders.activities); - orders.count += cashOrders.count; + activities.activities.push(...cashActivities.activities); + activities.count += cashActivities.count; } - return orders; + return activities; } public async getStatisticsByCurrency( @@ -817,7 +820,7 @@ export class OrderService { }); } - public async updateOrder({ + public async updateActivity({ data, where }: { @@ -882,7 +885,7 @@ export class OrderService { data: { tags: { set: [] } } }); - const order = await this.prismaService.order.update({ + const activity = await this.prismaService.order.update({ where, data: { ...data, @@ -896,11 +899,11 @@ export class OrderService { this.eventEmitter.emit( PortfolioChangedEvent.getName(), new PortfolioChangedEvent({ - userId: order.userId + userId: activity.userId }) ); - return order; + return activity; } private async orders(params: { diff --git a/apps/api/src/app/admin/admin.controller.ts b/apps/api/src/app/admin/admin.controller.ts index 24467c732..69b619625 100644 --- a/apps/api/src/app/admin/admin.controller.ts +++ b/apps/api/src/app/admin/admin.controller.ts @@ -172,7 +172,7 @@ export class AdminController { let date: Date; if (dateRange) { - const { startDate } = getIntervalFromDateRange(dateRange); + const { startDate } = getIntervalFromDateRange({ dateRange }); date = startDate; } @@ -247,14 +247,17 @@ export class AdminController { @Param('symbol') symbol: string ): Promise<{ price: number }> { try { - const price = await this.manualService.test(data.scraperConfiguration); + const price = await this.manualService.test({ + symbol, + scraperConfiguration: data.scraperConfiguration + }); if (price) { return { price }; } throw new Error( - `Could not parse the current market price for ${symbol} (${dataSource})` + `Could not parse the market price for ${symbol} (${dataSource})` ); } catch (error) { Logger.error(error, 'AdminController'); diff --git a/apps/api/src/app/admin/admin.module.ts b/apps/api/src/app/admin/admin.module.ts index 598b68f17..960a36629 100644 --- a/apps/api/src/app/admin/admin.module.ts +++ b/apps/api/src/app/admin/admin.module.ts @@ -1,4 +1,4 @@ -import { OrderModule } from '@ghostfolio/api/app/order/order.module'; +import { ActivitiesModule } from '@ghostfolio/api/app/activities/activities.module'; import { TransformDataSourceInRequestModule } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.module'; import { ApiModule } from '@ghostfolio/api/services/api/api.module'; import { BenchmarkModule } from '@ghostfolio/api/services/benchmark/benchmark.module'; @@ -20,6 +20,7 @@ import { QueueModule } from './queue/queue.module'; @Module({ imports: [ + ActivitiesModule, ApiModule, BenchmarkModule, ConfigurationModule, @@ -28,7 +29,6 @@ import { QueueModule } from './queue/queue.module'; DemoModule, ExchangeRateDataModule, MarketDataModule, - OrderModule, PrismaModule, PropertyModule, QueueModule, diff --git a/apps/api/src/app/admin/admin.service.ts b/apps/api/src/app/admin/admin.service.ts index 2cc8bbfb8..d2bf6e411 100644 --- a/apps/api/src/app/admin/admin.service.ts +++ b/apps/api/src/app/admin/admin.service.ts @@ -1,4 +1,4 @@ -import { OrderService } from '@ghostfolio/api/app/order/order.service'; +import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.service'; import { environment } from '@ghostfolio/api/environments/environment'; import { BenchmarkService } from '@ghostfolio/api/services/benchmark/benchmark.service'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; @@ -55,12 +55,12 @@ import { groupBy } from 'lodash'; @Injectable() export class AdminService { public constructor( + private readonly activitiesService: ActivitiesService, private readonly benchmarkService: BenchmarkService, private readonly configurationService: ConfigurationService, private readonly dataProviderService: DataProviderService, private readonly exchangeRateDataService: ExchangeRateDataService, private readonly marketDataService: MarketDataService, - private readonly orderService: OrderService, private readonly prismaService: PrismaService, private readonly propertyService: PropertyService, private readonly symbolProfileService: SymbolProfileService @@ -225,6 +225,10 @@ export class AdminService { presetId === 'ETF_WITHOUT_SECTORS' ) { filters = [{ id: 'ETF', type: 'ASSET_SUB_CLASS' }]; + } else if (presetId === 'NO_ACTIVITIES') { + where.activities = { + none: {} + }; } const searchQuery = filters.find(({ type }) => { @@ -466,10 +470,12 @@ export class AdminService { let currency: EnhancedSymbolProfile['currency'] = '-'; let dateOfFirstActivity: EnhancedSymbolProfile['dateOfFirstActivity']; - if (isCurrency(getCurrencyFromSymbol(symbol))) { + const isCurrencyAssetProfile = isCurrency(getCurrencyFromSymbol(symbol)); + + if (isCurrencyAssetProfile) { currency = getCurrencyFromSymbol(symbol); ({ activitiesCount, dateOfFirstActivity } = - await this.orderService.getStatisticsByCurrency(currency)); + await this.activitiesService.getStatisticsByCurrency(currency)); } const [[assetProfile], marketData] = await Promise.all([ @@ -504,6 +510,8 @@ export class AdminService { dataSource, dateOfFirstActivity, symbol, + assetClass: isCurrencyAssetProfile ? AssetClass.LIQUIDITY : undefined, + assetSubClass: isCurrencyAssetProfile ? AssetSubClass.CASH : undefined, isActive: true } }; @@ -790,7 +798,7 @@ export class AdminService { if (isCurrency(getCurrencyFromSymbol(symbol))) { currency = getCurrencyFromSymbol(symbol); ({ activitiesCount, dateOfFirstActivity } = - await this.orderService.getStatisticsByCurrency(currency)); + await this.activitiesService.getStatisticsByCurrency(currency)); } const lastMarketPrice = lastMarketPriceMap.get( diff --git a/apps/api/src/app/app.module.ts b/apps/api/src/app/app.module.ts index 89f52e1ea..8ebe05928 100644 --- a/apps/api/src/app/app.module.ts +++ b/apps/api/src/app/app.module.ts @@ -1,4 +1,5 @@ import { EventsModule } from '@ghostfolio/api/events/events.module'; +import { BullBoardAuthMiddleware } from '@ghostfolio/api/middlewares/bull-board-auth.middleware'; import { HtmlTemplateMiddleware } from '@ghostfolio/api/middlewares/html-template.middleware'; import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module'; import { CronModule } from '@ghostfolio/api/services/cron/cron.module'; @@ -10,10 +11,13 @@ import { PropertyModule } from '@ghostfolio/api/services/property/property.modul 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 { + BULL_BOARD_ROUTE, DEFAULT_LANGUAGE_CODE, SUPPORTED_LANGUAGE_CODES } from '@ghostfolio/common/config'; +import { ExpressAdapter } from '@bull-board/express'; +import { BullBoardModule } from '@bull-board/nestjs'; import { BullModule } from '@nestjs/bull'; import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; @@ -25,6 +29,7 @@ import { join } from 'node:path'; import { AccessModule } from './access/access.module'; import { AccountModule } from './account/account.module'; +import { ActivitiesModule } from './activities/activities.module'; import { AdminModule } from './admin/admin.module'; import { AppController } from './app.controller'; import { AssetModule } from './asset/asset.module'; @@ -48,7 +53,6 @@ import { HealthModule } from './health/health.module'; import { ImportModule } from './import/import.module'; import { InfoModule } from './info/info.module'; import { LogoModule } from './logo/logo.module'; -import { OrderModule } from './order/order.module'; import { PlatformModule } from './platform/platform.module'; import { PortfolioModule } from './portfolio/portfolio.module'; import { RedisCacheModule } from './redis-cache/redis-cache.module'; @@ -62,6 +66,7 @@ import { UserModule } from './user/user.module'; AdminModule, AccessModule, AccountModule, + ActivitiesModule, AiModule, ApiKeysModule, AssetModule, @@ -69,6 +74,29 @@ import { UserModule } from './user/user.module'; AuthDeviceModule, AuthModule, BenchmarksModule, + ...(process.env.ENABLE_FEATURE_BULL_BOARD === 'true' + ? [ + BullBoardModule.forRoot({ + adapter: ExpressAdapter, + boardOptions: { + uiConfig: { + boardLogo: { + height: 0, + path: '', + width: 0 + }, + boardTitle: 'Job Queues', + favIcon: { + alternative: '/assets/favicon-32x32.png', + default: '/assets/favicon-32x32.png' + } + } + }, + middleware: BullBoardAuthMiddleware, + route: BULL_BOARD_ROUTE + }) + ] + : []), BullModule.forRoot({ redis: { db: parseInt(process.env.REDIS_DB ?? '0', 10), @@ -94,7 +122,6 @@ import { UserModule } from './user/user.module'; InfoModule, LogoModule, MarketDataModule, - OrderModule, PlatformModule, PlatformsModule, PortfolioModule, @@ -105,7 +132,12 @@ import { UserModule } from './user/user.module'; RedisCacheModule, ScheduleModule.forRoot(), ServeStaticModule.forRoot({ - exclude: ['/.well-known/*wildcard', '/api/*wildcard', '/sitemap.xml'], + exclude: [ + `${BULL_BOARD_ROUTE}/*wildcard`, + '/.well-known/*wildcard', + '/api/*wildcard', + '/sitemap.xml' + ], rootPath: join(__dirname, '..', 'client'), serveStaticOptions: { setHeaders: (res) => { diff --git a/apps/api/src/app/auth-device/auth-device.controller.ts b/apps/api/src/app/auth-device/auth-device.controller.ts index 15e853465..c46589d74 100644 --- a/apps/api/src/app/auth-device/auth-device.controller.ts +++ b/apps/api/src/app/auth-device/auth-device.controller.ts @@ -2,18 +2,43 @@ import { AuthDeviceService } from '@ghostfolio/api/app/auth-device/auth-device.s import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator'; import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard'; import { permissions } from '@ghostfolio/common/permissions'; +import { RequestWithUser } from '@ghostfolio/common/types'; -import { Controller, Delete, Param, UseGuards } from '@nestjs/common'; +import { + Controller, + Delete, + HttpException, + Inject, + Param, + UseGuards +} from '@nestjs/common'; +import { REQUEST } from '@nestjs/core'; import { AuthGuard } from '@nestjs/passport'; +import { getReasonPhrase, StatusCodes } from 'http-status-codes'; @Controller('auth-device') export class AuthDeviceController { - public constructor(private readonly authDeviceService: AuthDeviceService) {} + public constructor( + private readonly authDeviceService: AuthDeviceService, + @Inject(REQUEST) private readonly request: RequestWithUser + ) {} @Delete(':id') @HasPermission(permissions.deleteAuthDevice) @UseGuards(AuthGuard('jwt'), HasPermissionGuard) public async deleteAuthDevice(@Param('id') id: string): Promise { + const originalAuthDevice = await this.authDeviceService.authDevice({ + id, + userId: this.request.user.id + }); + + if (!originalAuthDevice) { + throw new HttpException( + getReasonPhrase(StatusCodes.FORBIDDEN), + StatusCodes.FORBIDDEN + ); + } + await this.authDeviceService.deleteAuthDevice({ id }); } } diff --git a/apps/api/src/app/endpoints/ai/ai.module.ts b/apps/api/src/app/endpoints/ai/ai.module.ts index 8a441fde7..eab4ecf8b 100644 --- a/apps/api/src/app/endpoints/ai/ai.module.ts +++ b/apps/api/src/app/endpoints/ai/ai.module.ts @@ -1,6 +1,6 @@ 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 { ActivitiesModule } from '@ghostfolio/api/app/activities/activities.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'; @@ -29,6 +29,7 @@ import { AiService } from './ai.service'; @Module({ controllers: [AiController], imports: [ + ActivitiesModule, ApiModule, BenchmarkModule, ConfigurationModule, @@ -37,7 +38,6 @@ import { AiService } from './ai.service'; I18nModule, ImpersonationModule, MarketDataModule, - OrderModule, PortfolioSnapshotQueueModule, PrismaModule, PropertyModule, diff --git a/apps/api/src/app/endpoints/assets/assets.controller.ts b/apps/api/src/app/endpoints/assets/assets.controller.ts index a314b3f19..397686d8c 100644 --- a/apps/api/src/app/endpoints/assets/assets.controller.ts +++ b/apps/api/src/app/endpoints/assets/assets.controller.ts @@ -4,6 +4,7 @@ import { interpolate } from '@ghostfolio/common/helper'; import { Controller, Get, + OnModuleInit, Param, Res, Version, @@ -14,12 +15,14 @@ import { readFileSync } from 'node:fs'; import { join } from 'node:path'; @Controller('assets') -export class AssetsController { +export class AssetsController implements OnModuleInit { private webManifest = ''; public constructor( public readonly configurationService: ConfigurationService - ) { + ) {} + + public onModuleInit() { try { this.webManifest = readFileSync( join(__dirname, 'assets', 'site.webmanifest'), diff --git a/apps/api/src/app/endpoints/benchmarks/benchmarks.controller.ts b/apps/api/src/app/endpoints/benchmarks/benchmarks.controller.ts index 629d90928..970925777 100644 --- a/apps/api/src/app/endpoints/benchmarks/benchmarks.controller.ts +++ b/apps/api/src/app/endpoints/benchmarks/benchmarks.controller.ts @@ -126,10 +126,10 @@ export class BenchmarksController { @Query('tags') filterByTags?: string, @Query('withExcludedAccounts') withExcludedAccountsParam = 'false' ): Promise { - const { endDate, startDate } = getIntervalFromDateRange( + const { endDate, startDate } = getIntervalFromDateRange({ dateRange, - new Date(startDateString) - ); + startDate: new Date(startDateString) + }); const filters = this.apiService.buildFiltersFromQueryParams({ filterByAccounts, diff --git a/apps/api/src/app/endpoints/benchmarks/benchmarks.module.ts b/apps/api/src/app/endpoints/benchmarks/benchmarks.module.ts index 8bdf79035..2bcd6177d 100644 --- a/apps/api/src/app/endpoints/benchmarks/benchmarks.module.ts +++ b/apps/api/src/app/endpoints/benchmarks/benchmarks.module.ts @@ -1,6 +1,6 @@ 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 { ActivitiesModule } from '@ghostfolio/api/app/activities/activities.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'; @@ -32,6 +32,7 @@ import { BenchmarksService } from './benchmarks.service'; @Module({ controllers: [BenchmarksController], imports: [ + ActivitiesModule, ApiModule, ConfigurationModule, DataProviderModule, @@ -39,7 +40,6 @@ import { BenchmarksService } from './benchmarks.service'; I18nModule, ImpersonationModule, MarketDataModule, - OrderModule, PortfolioSnapshotQueueModule, PrismaModule, PropertyModule, diff --git a/apps/api/src/app/endpoints/public/public.controller.ts b/apps/api/src/app/endpoints/public/public.controller.ts index b4ecd37ba..b97640cab 100644 --- a/apps/api/src/app/endpoints/public/public.controller.ts +++ b/apps/api/src/app/endpoints/public/public.controller.ts @@ -1,5 +1,5 @@ import { AccessService } from '@ghostfolio/api/app/access/access.service'; -import { OrderService } from '@ghostfolio/api/app/order/order.service'; +import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.service'; import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service'; import { UserService } from '@ghostfolio/api/app/user/user.service'; import { RedactValuesInResponseInterceptor } from '@ghostfolio/api/interceptors/redact-values-in-response/redact-values-in-response.interceptor'; @@ -28,9 +28,9 @@ import { StatusCodes, getReasonPhrase } from 'http-status-codes'; export class PublicController { public constructor( private readonly accessService: AccessService, + private readonly activitiesService: ActivitiesService, private readonly configurationService: ConfigurationService, private readonly exchangeRateDataService: ExchangeRateDataService, - private readonly orderService: OrderService, private readonly portfolioService: PortfolioService, @Inject(REQUEST) private readonly request: RequestWithUser, private readonly userService: UserService @@ -81,7 +81,7 @@ export class PublicController { }) ]); - const { activities } = await this.orderService.getOrders({ + const { activities } = await this.activitiesService.getActivities({ sortColumn: 'date', sortDirection: 'desc', take: 10, @@ -167,6 +167,7 @@ export class PublicController { allocationInPercentage: portfolioPosition.valueInBaseCurrency / totalValue, assetClass: hasDetails ? portfolioPosition.assetClass : undefined, + assetProfile: hasDetails ? portfolioPosition.assetProfile : undefined, countries: hasDetails ? portfolioPosition.countries : [], currency: hasDetails ? portfolioPosition.currency : undefined, dataSource: portfolioPosition.dataSource, diff --git a/apps/api/src/app/endpoints/public/public.module.ts b/apps/api/src/app/endpoints/public/public.module.ts index 19e281dde..e8395228f 100644 --- a/apps/api/src/app/endpoints/public/public.module.ts +++ b/apps/api/src/app/endpoints/public/public.module.ts @@ -1,7 +1,7 @@ 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 { ActivitiesModule } from '@ghostfolio/api/app/activities/activities.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'; @@ -27,13 +27,13 @@ import { PublicController } from './public.controller'; controllers: [PublicController], imports: [ AccessModule, + ActivitiesModule, BenchmarkModule, DataProviderModule, ExchangeRateDataModule, I18nModule, ImpersonationModule, MarketDataModule, - OrderModule, PortfolioSnapshotQueueModule, PrismaModule, RedisCacheModule, diff --git a/apps/api/src/app/export/export.module.ts b/apps/api/src/app/export/export.module.ts index 4f40cc417..6158fe043 100644 --- a/apps/api/src/app/export/export.module.ts +++ b/apps/api/src/app/export/export.module.ts @@ -1,5 +1,5 @@ import { AccountModule } from '@ghostfolio/api/app/account/account.module'; -import { OrderModule } from '@ghostfolio/api/app/order/order.module'; +import { ActivitiesModule } from '@ghostfolio/api/app/activities/activities.module'; import { TransformDataSourceInRequestModule } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.module'; import { ApiModule } from '@ghostfolio/api/services/api/api.module'; import { MarketDataModule } from '@ghostfolio/api/services/market-data/market-data.module'; @@ -14,9 +14,9 @@ import { ExportService } from './export.service'; controllers: [ExportController], imports: [ AccountModule, + ActivitiesModule, ApiModule, MarketDataModule, - OrderModule, TagModule, TransformDataSourceInRequestModule ], diff --git a/apps/api/src/app/export/export.service.ts b/apps/api/src/app/export/export.service.ts index d07b199be..4f2fb3309 100644 --- a/apps/api/src/app/export/export.service.ts +++ b/apps/api/src/app/export/export.service.ts @@ -1,5 +1,5 @@ import { AccountService } from '@ghostfolio/api/app/account/account.service'; -import { OrderService } from '@ghostfolio/api/app/order/order.service'; +import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.service'; import { environment } from '@ghostfolio/api/environments/environment'; import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service'; import { TagService } from '@ghostfolio/api/services/tag/tag.service'; @@ -17,8 +17,8 @@ import { groupBy, uniqBy } from 'lodash'; export class ExportService { public constructor( private readonly accountService: AccountService, + private readonly activitiesService: ActivitiesService, private readonly marketDataService: MarketDataService, - private readonly orderService: OrderService, private readonly tagService: TagService ) {} @@ -38,7 +38,7 @@ export class ExportService { }); const platformsMap: { [platformId: string]: Platform } = {}; - let { activities } = await this.orderService.getOrders({ + let { activities } = await this.activitiesService.getActivities({ filters, userId, includeDrafts: true, @@ -182,10 +182,8 @@ export class ExportService { isActive, isin, name, - scraperConfiguration, sectors, symbol, - symbolMapping, url }) => { return { @@ -204,11 +202,8 @@ export class ExportService { isin, marketData: marketDataByAssetProfile[id], name, - scraperConfiguration: - scraperConfiguration as unknown as Prisma.JsonArray, sectors: sectors as unknown as Prisma.JsonArray, symbol, - symbolMapping, url }; } diff --git a/apps/api/src/app/import/import.controller.ts b/apps/api/src/app/import/import.controller.ts index 81481fd65..d5724bef2 100644 --- a/apps/api/src/app/import/import.controller.ts +++ b/apps/api/src/app/import/import.controller.ts @@ -38,7 +38,7 @@ export class ImportController { @Post() @UseGuards(AuthGuard('jwt'), HasPermissionGuard) - @HasPermission(permissions.createOrder) + @HasPermission(permissions.createActivity) @UseInterceptors(TransformDataSourceInRequestInterceptor) @UseInterceptors(TransformDataSourceInResponseInterceptor) public async import( diff --git a/apps/api/src/app/import/import.module.ts b/apps/api/src/app/import/import.module.ts index a4a13f941..ca9b5667b 100644 --- a/apps/api/src/app/import/import.module.ts +++ b/apps/api/src/app/import/import.module.ts @@ -1,6 +1,6 @@ import { AccountModule } from '@ghostfolio/api/app/account/account.module'; +import { ActivitiesModule } from '@ghostfolio/api/app/activities/activities.module'; import { CacheModule } from '@ghostfolio/api/app/cache/cache.module'; -import { OrderModule } from '@ghostfolio/api/app/order/order.module'; import { PlatformModule } from '@ghostfolio/api/app/platform/platform.module'; import { PortfolioModule } from '@ghostfolio/api/app/portfolio/portfolio.module'; import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.module'; @@ -25,6 +25,7 @@ import { ImportService } from './import.service'; controllers: [ImportController], imports: [ AccountModule, + ActivitiesModule, ApiModule, CacheModule, ConfigurationModule, @@ -32,7 +33,6 @@ import { ImportService } from './import.service'; DataProviderModule, ExchangeRateDataModule, MarketDataModule, - OrderModule, PlatformModule, PortfolioModule, PrismaModule, diff --git a/apps/api/src/app/import/import.service.ts b/apps/api/src/app/import/import.service.ts index 7e8e333b9..b82f763a0 100644 --- a/apps/api/src/app/import/import.service.ts +++ b/apps/api/src/app/import/import.service.ts @@ -1,10 +1,10 @@ import { AccountService } from '@ghostfolio/api/app/account/account.service'; -import { OrderService } from '@ghostfolio/api/app/order/order.service'; +import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.service'; import { PlatformService } from '@ghostfolio/api/app/platform/platform.service'; import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service'; import { ApiService } from '@ghostfolio/api/services/api/api.service'; -import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service'; +import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service'; import { DataGatheringService } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.service'; import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service'; @@ -32,7 +32,7 @@ import { } from '@ghostfolio/common/types'; import { Injectable } from '@nestjs/common'; -import { DataSource, Prisma, SymbolProfile } from '@prisma/client'; +import { DataSource, Prisma } from '@prisma/client'; import { Big } from 'big.js'; import { endOfToday, isAfter, isSameSecond, parseISO } from 'date-fns'; import { omit, uniqBy } from 'lodash'; @@ -44,12 +44,12 @@ import { ImportDataDto } from './import-data.dto'; export class ImportService { public constructor( private readonly accountService: AccountService, + private readonly activitiesService: ActivitiesService, private readonly apiService: ApiService, - private readonly configurationService: ConfigurationService, private readonly dataGatheringService: DataGatheringService, private readonly dataProviderService: DataProviderService, + private readonly exchangeRateDataService: ExchangeRateDataService, private readonly marketDataService: MarketDataService, - private readonly orderService: OrderService, private readonly platformService: PlatformService, private readonly portfolioService: PortfolioService, private readonly symbolProfileService: SymbolProfileService, @@ -91,7 +91,7 @@ export class ImportService { userId, withExcludedAccounts: true }), - this.orderService.getOrders({ + this.activitiesService.getActivities({ filters, userCurrency, userId, @@ -393,7 +393,7 @@ export class ImportService { } } - const assetProfiles = await this.validateActivities({ + const assetProfiles = await this.dataProviderService.validateActivities({ activitiesDto, assetProfilesWithMarketDataDto, maxActivitiesToImport, @@ -548,7 +548,7 @@ export class ImportService { continue; } - order = await this.orderService.createOrder({ + order = await this.activitiesService.createActivity({ comment, currency, date, @@ -590,10 +590,18 @@ export class ImportService { const value = new Big(quantity).mul(unitPrice).toNumber(); + const valueInBaseCurrency = this.exchangeRateDataService.toCurrencyAtDate( + value, + currency ?? assetProfile.currency, + userCurrency, + date + ); + activities.push({ ...order, error, value, + valueInBaseCurrency: await valueInBaseCurrency, // @ts-ignore SymbolProfile: assetProfile }); @@ -637,7 +645,7 @@ export class ImportService { userId: string; }): Promise[]> { const { activities: existingActivities } = - await this.orderService.getOrders({ + await this.activitiesService.getActivities({ userCurrency, userId, includeDrafts: true, @@ -719,132 +727,4 @@ export class ImportService { return uniqueAccountIds.size === 1; } - - private async validateActivities({ - activitiesDto, - assetProfilesWithMarketDataDto, - maxActivitiesToImport, - user - }: { - activitiesDto: Partial[]; - assetProfilesWithMarketDataDto: ImportDataDto['assetProfiles']; - maxActivitiesToImport: number; - user: UserWithSettings; - }) { - if (activitiesDto?.length > maxActivitiesToImport) { - throw new Error(`Too many activities (${maxActivitiesToImport} at most)`); - } - - const assetProfiles: { - [assetProfileIdentifier: string]: Partial; - } = {}; - const dataSources = await this.dataProviderService.getDataSources(); - - for (const [ - index, - { currency, dataSource, symbol, type } - ] of activitiesDto.entries()) { - if (!dataSources.includes(dataSource)) { - throw new Error( - `activities.${index}.dataSource ("${dataSource}") is not valid` - ); - } - - if ( - this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') && - user.subscription.type === 'Basic' - ) { - const dataProvider = this.dataProviderService.getDataProvider( - DataSource[dataSource] - ); - - if (dataProvider.getDataProviderInfo().isPremium) { - throw new Error( - `activities.${index}.dataSource ("${dataSource}") is not valid` - ); - } - } - - if (!assetProfiles[getAssetProfileIdentifier({ dataSource, symbol })]) { - if (['FEE', 'INTEREST', 'LIABILITY'].includes(type)) { - // Skip asset profile validation for FEE, INTEREST, and LIABILITY - // as these activity types don't require asset profiles - const assetProfileInImport = assetProfilesWithMarketDataDto?.find( - (profile) => { - return ( - profile.dataSource === dataSource && profile.symbol === symbol - ); - } - ); - - assetProfiles[getAssetProfileIdentifier({ dataSource, symbol })] = { - currency, - dataSource, - symbol, - name: assetProfileInImport?.name - }; - - continue; - } - - let assetProfile: Partial = { currency }; - - try { - assetProfile = ( - await this.dataProviderService.getAssetProfiles([ - { dataSource, symbol } - ]) - )?.[symbol]; - } catch {} - - if (!assetProfile?.name) { - const assetProfileInImport = assetProfilesWithMarketDataDto?.find( - (profile) => { - return ( - profile.dataSource === dataSource && profile.symbol === symbol - ); - } - ); - - if (assetProfileInImport) { - // Merge all fields of custom asset profiles into the validation object - Object.assign(assetProfile, { - assetClass: assetProfileInImport.assetClass, - assetSubClass: assetProfileInImport.assetSubClass, - comment: assetProfileInImport.comment, - countries: assetProfileInImport.countries, - currency: assetProfileInImport.currency, - cusip: assetProfileInImport.cusip, - dataSource: assetProfileInImport.dataSource, - figi: assetProfileInImport.figi, - figiComposite: assetProfileInImport.figiComposite, - figiShareClass: assetProfileInImport.figiShareClass, - holdings: assetProfileInImport.holdings, - isActive: assetProfileInImport.isActive, - isin: assetProfileInImport.isin, - name: assetProfileInImport.name, - scraperConfiguration: assetProfileInImport.scraperConfiguration, - sectors: assetProfileInImport.sectors, - symbol: assetProfileInImport.symbol, - symbolMapping: assetProfileInImport.symbolMapping, - url: assetProfileInImport.url - }); - } - } - - if (!['FEE', 'INTEREST', 'LIABILITY'].includes(type)) { - if (!assetProfile?.name) { - throw new Error( - `activities.${index}.symbol ("${symbol}") is not valid for the specified data source ("${dataSource}")` - ); - } - } - - assetProfiles[getAssetProfileIdentifier({ dataSource, symbol })] = - assetProfile; - } - } - - return assetProfiles; - } } diff --git a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts index 553cb8c90..d57b85d8c 100644 --- a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts @@ -158,10 +158,10 @@ export abstract class PortfolioCalculator { this.redisCacheService = redisCacheService; this.userId = userId; - const { endDate, startDate } = getIntervalFromDateRange( - 'max', - subDays(dateOfFirstActivity, 1) - ); + const { endDate, startDate } = getIntervalFromDateRange({ + dateRange: 'max', + startDate: subDays(dateOfFirstActivity, 1) + }); this.endDate = endOfDay(endDate); this.startDate = startOfDay(startDate); @@ -885,7 +885,7 @@ export abstract class PortfolioCalculator { // Make sure some key dates are present for (const dateRange of ['1d', '1y', '5y', 'max', 'mtd', 'wtd', 'ytd']) { const { endDate: dateRangeEnd, startDate: dateRangeStart } = - getIntervalFromDateRange(dateRange); + getIntervalFromDateRange({ dateRange }); if ( !isBefore(dateRangeStart, startDate) && diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-buy.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-buy.spec.ts index 52c8489dd..9a93d0419 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-buy.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-buy.spec.ts @@ -194,6 +194,7 @@ describe('PortfolioCalculator', () => { netPerformanceInPercentage: 0.07032490039195362, netPerformanceInPercentageWithCurrencyEffect: 0.07032490039195362, netPerformanceWithCurrencyEffect: 33.4, + totalInvestment: 559, totalInvestmentValueWithCurrencyEffect: 559 }) ); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts index 3998b081d..c876d0db1 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts @@ -208,6 +208,7 @@ describe('PortfolioCalculator', () => { netPerformanceInPercentage: -0.05528341497550734703, netPerformanceInPercentageWithCurrencyEffect: -0.05528341497550734703, netPerformanceWithCurrencyEffect: -15.8, + totalInvestment: 0, totalInvestmentValueWithCurrencyEffect: 0 }) ); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell.spec.ts index acd0d0b2e..ae921d6d9 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell.spec.ts @@ -192,6 +192,7 @@ describe('PortfolioCalculator', () => { netPerformanceInPercentage: -0.05528341497550734703, netPerformanceInPercentageWithCurrencyEffect: -0.05528341497550734703, netPerformanceWithCurrencyEffect: -15.8, + totalInvestment: 0, totalInvestmentValueWithCurrencyEffect: 0 }) ); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy.spec.ts index 652e72db0..6207f1417 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy.spec.ts @@ -192,6 +192,7 @@ describe('PortfolioCalculator', () => { netPerformanceInPercentage: 0.08437042459736457, netPerformanceInPercentageWithCurrencyEffect: 0.08437042459736457, netPerformanceWithCurrencyEffect: 23.05, + totalInvestment: 273.2, totalInvestmentValueWithCurrencyEffect: 273.2 }) ); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts index a70cc2986..11765fc49 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts @@ -210,6 +210,7 @@ describe('PortfolioCalculator', () => { netPerformanceInPercentage: 42.41983590271396609433, netPerformanceInPercentageWithCurrencyEffect: 41.64017412624815597854, netPerformanceWithCurrencyEffect: 26516.208701400000064086, + totalInvestment: 318.542667299999967957, totalInvestmentValueWithCurrencyEffect: 318.542667299999967957 }) ); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-cash.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-cash.spec.ts index a53ebcf05..217a67c49 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-cash.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-cash.spec.ts @@ -1,6 +1,6 @@ import { AccountBalanceService } from '@ghostfolio/api/app/account-balance/account-balance.service'; import { AccountService } from '@ghostfolio/api/app/account/account.service'; -import { OrderService } from '@ghostfolio/api/app/order/order.service'; +import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.service'; import { userDummyData } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator-test-utils'; import { PortfolioCalculatorFactory } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory'; import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service'; @@ -62,11 +62,11 @@ jest.mock('@ghostfolio/api/app/redis-cache/redis-cache.service', () => { describe('PortfolioCalculator', () => { let accountBalanceService: AccountBalanceService; let accountService: AccountService; + let activitiesService: ActivitiesService; let configurationService: ConfigurationService; let currentRateService: CurrentRateService; let dataProviderService: DataProviderService; let exchangeRateDataService: ExchangeRateDataService; - let orderService: OrderService; let portfolioCalculatorFactory: PortfolioCalculatorFactory; let portfolioSnapshotService: PortfolioSnapshotService; let redisCacheService: RedisCacheService; @@ -106,13 +106,13 @@ describe('PortfolioCalculator', () => { ); currentRateService = new CurrentRateService( - dataProviderService, null, + dataProviderService, null, null ); - orderService = new OrderService( + activitiesService = new ActivitiesService( accountBalanceService, accountService, null, @@ -183,18 +183,17 @@ describe('PortfolioCalculator', () => { .spyOn(dataProviderService, 'getDataSourceForExchangeRates') .mockReturnValue(DataSource.YAHOO); - jest.spyOn(orderService, 'getOrders').mockResolvedValue({ + jest.spyOn(activitiesService, 'getActivities').mockResolvedValue({ activities: [], count: 0 }); - const { activities } = await orderService.getOrdersForPortfolioCalculator( - { + const { activities } = + await activitiesService.getActivitiesForPortfolioCalculator({ userCurrency: 'CHF', userId: userDummyData.id, withCash: true - } - ); + }); jest.spyOn(currentRateService, 'getValues').mockResolvedValue({ dataProviderInfos: [], diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-fee.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-fee.spec.ts index 59a5531df..a3fbc0758 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-fee.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-fee.spec.ts @@ -128,6 +128,7 @@ describe('PortfolioCalculator', () => { netPerformanceInPercentage: 0, netPerformanceInPercentageWithCurrencyEffect: 0, netPerformanceWithCurrencyEffect: 0, + totalInvestment: 0, totalInvestmentValueWithCurrencyEffect: 0 }) ); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-buy.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-buy.spec.ts index 9b48a1324..122a9aaed 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-buy.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-buy.spec.ts @@ -188,6 +188,7 @@ describe('PortfolioCalculator', () => { netPerformanceInPercentage: 0.29544434470377019749, netPerformanceInPercentageWithCurrencyEffect: 0.24112962014285697628, netPerformanceWithCurrencyEffect: 19.851974, + totalInvestment: new Big('89.12').mul(0.8854).toNumber(), totalInvestmentValueWithCurrencyEffect: 82.329056 }) ); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-msft-buy-with-dividend.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-msft-buy-with-dividend.spec.ts index b19adb642..e7eff6682 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-msft-buy-with-dividend.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-msft-buy-with-dividend.spec.ts @@ -174,6 +174,7 @@ describe('PortfolioCalculator', () => { expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject( expect.objectContaining({ + totalInvestment: 298.58, totalInvestmentValueWithCurrencyEffect: 298.58 }) ); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts index fecf17011..3034e3a1f 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts @@ -190,6 +190,7 @@ describe('PortfolioCalculator', () => { netPerformanceInPercentage: 0.12184460284330327256, netPerformanceInPercentageWithCurrencyEffect: 0.12184460284330327256, netPerformanceWithCurrencyEffect: 17.68, + totalInvestment: 75.8, totalInvestmentValueWithCurrencyEffect: 75.8 }) ); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts index adbb5c3ff..c79fdef58 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts @@ -241,6 +241,7 @@ describe('PortfolioCalculator', () => { netPerformanceInPercentage: 0.13100263852242744063, netPerformanceInPercentageWithCurrencyEffect: 0.13100263852242744063, netPerformanceWithCurrencyEffect: 19.86, + totalInvestment: 0, totalInvestmentValueWithCurrencyEffect: 0 }) ); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-valuable.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-valuable.spec.ts index 6fc94622f..e518a5994 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-valuable.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-valuable.spec.ts @@ -162,6 +162,7 @@ describe('PortfolioCalculator', () => { netPerformanceInPercentage: 0, netPerformanceInPercentageWithCurrencyEffect: 0, netPerformanceWithCurrencyEffect: 0, + totalInvestment: 500000, totalInvestmentValueWithCurrencyEffect: 500000 }) ); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts index be69048df..2841e9975 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts @@ -860,7 +860,7 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator { return format(date, 'yyyy'); }) ] as DateRange[]) { - const dateInterval = getIntervalFromDateRange(dateRange); + const dateInterval = getIntervalFromDateRange({ dateRange }); const endDate = dateInterval.endDate; let startDate = dateInterval.startDate; diff --git a/apps/api/src/app/portfolio/current-rate.service.spec.ts b/apps/api/src/app/portfolio/current-rate.service.spec.ts index d8b7482e7..5f2358679 100644 --- a/apps/api/src/app/portfolio/current-rate.service.spec.ts +++ b/apps/api/src/app/portfolio/current-rate.service.spec.ts @@ -114,9 +114,9 @@ describe('CurrentRateService', () => { marketDataService = new MarketDataService(null); currentRateService = new CurrentRateService( + null, dataProviderService, marketDataService, - null, null ); }); diff --git a/apps/api/src/app/portfolio/current-rate.service.ts b/apps/api/src/app/portfolio/current-rate.service.ts index 5d39a54bb..b454b01cd 100644 --- a/apps/api/src/app/portfolio/current-rate.service.ts +++ b/apps/api/src/app/portfolio/current-rate.service.ts @@ -1,4 +1,4 @@ -import { OrderService } from '@ghostfolio/api/app/order/order.service'; +import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.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'; @@ -24,9 +24,9 @@ export class CurrentRateService { private static readonly MARKET_DATA_PAGE_SIZE = 50000; public constructor( + private readonly activitiesService: ActivitiesService, private readonly dataProviderService: DataProviderService, private readonly marketDataService: MarketDataService, - private readonly orderService: OrderService, @Inject(REQUEST) private readonly request: RequestWithUser ) {} @@ -129,10 +129,11 @@ export class CurrentRateService { if (!value) { // Fallback to unit price of latest activity - const latestActivity = await this.orderService.getLatestOrder({ - dataSource, - symbol - }); + const latestActivity = + await this.activitiesService.getLatestActivity({ + dataSource, + symbol + }); value = { dataSource, diff --git a/apps/api/src/app/portfolio/portfolio.controller.ts b/apps/api/src/app/portfolio/portfolio.controller.ts index b8aefe0ac..9c41aecb9 100644 --- a/apps/api/src/app/portfolio/portfolio.controller.ts +++ b/apps/api/src/app/portfolio/portfolio.controller.ts @@ -1,4 +1,4 @@ -import { OrderService } from '@ghostfolio/api/app/order/order.service'; +import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.service'; import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator'; import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard'; import { @@ -63,10 +63,10 @@ import { UpdateHoldingTagsDto } from './update-holding-tags.dto'; @Controller('portfolio') export class PortfolioController { public constructor( + private readonly activitiesService: ActivitiesService, private readonly apiService: ApiService, private readonly configurationService: ConfigurationService, private readonly impersonationService: ImpersonationService, - private readonly orderService: OrderService, private readonly portfolioService: PortfolioService, @Inject(REQUEST) private readonly request: RequestWithUser ) {} @@ -187,7 +187,6 @@ export class PortfolioController { portfolioSummary = nullifyValuesInObject(summary, [ 'cash', - 'committedFunds', 'currentNetWorth', 'currentValueInBaseCurrency', 'dividendInBaseCurrency', @@ -206,6 +205,7 @@ export class PortfolioController { 'netPerformanceWithCurrencyEffect', 'totalBuy', 'totalInvestment', + 'totalInvestmentValueWithCurrencyEffect', 'totalSell', 'totalValueInBaseCurrency' ]); @@ -320,9 +320,9 @@ export class PortfolioController { await this.impersonationService.validateImpersonationId(impersonationId); const userCurrency = this.request.user.settings.settings.baseCurrency; - const { endDate, startDate } = getIntervalFromDateRange(dateRange); + const { endDate, startDate } = getIntervalFromDateRange({ dateRange }); - const { activities } = await this.orderService.getOrders({ + const { activities } = await this.activitiesService.getActivities({ endDate, filters, startDate, @@ -639,7 +639,7 @@ export class PortfolioController { return report; } - @HasPermission(permissions.updateOrder) + @HasPermission(permissions.updateActivity) @Put('holding/:dataSource/:symbol/tags') @UseInterceptors(TransformDataSourceInRequestInterceptor) @UseGuards(AuthGuard('jwt'), HasPermissionGuard) diff --git a/apps/api/src/app/portfolio/portfolio.module.ts b/apps/api/src/app/portfolio/portfolio.module.ts index 6dd5811a3..65a9b71aa 100644 --- a/apps/api/src/app/portfolio/portfolio.module.ts +++ b/apps/api/src/app/portfolio/portfolio.module.ts @@ -1,7 +1,7 @@ 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 { ActivitiesModule } from '@ghostfolio/api/app/activities/activities.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'; @@ -34,6 +34,7 @@ import { RulesService } from './rules.service'; exports: [PortfolioService], imports: [ AccessModule, + ActivitiesModule, ApiModule, BenchmarkModule, ConfigurationModule, @@ -43,7 +44,6 @@ import { RulesService } from './rules.service'; I18nModule, ImpersonationModule, MarketDataModule, - OrderModule, PerformanceLoggingModule, PortfolioSnapshotQueueModule, PrismaModule, diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index 7be375473..60b413cf9 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -1,7 +1,7 @@ import { AccountBalanceService } from '@ghostfolio/api/app/account-balance/account-balance.service'; import { AccountService } from '@ghostfolio/api/app/account/account.service'; import { CashDetails } from '@ghostfolio/api/app/account/interfaces/cash-details.interface'; -import { OrderService } from '@ghostfolio/api/app/order/order.service'; +import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.service'; import { UserService } from '@ghostfolio/api/app/user/user.service'; import { getFactor } from '@ghostfolio/api/helper/portfolio.helper'; import { AccountClusterRiskCurrentInvestment } from '@ghostfolio/api/models/rules/account-cluster-risk/current-investment'; @@ -13,7 +13,7 @@ import { CurrencyClusterRiskCurrentInvestment } from '@ghostfolio/api/models/rul import { EconomicMarketClusterRiskDevelopedMarkets } from '@ghostfolio/api/models/rules/economic-market-cluster-risk/developed-markets'; import { EconomicMarketClusterRiskEmergingMarkets } from '@ghostfolio/api/models/rules/economic-market-cluster-risk/emerging-markets'; import { EmergencyFundSetup } from '@ghostfolio/api/models/rules/emergency-fund/emergency-fund-setup'; -import { FeeRatioInitialInvestment } from '@ghostfolio/api/models/rules/fees/fee-ratio-initial-investment'; +import { FeeRatioTotalInvestmentVolume } from '@ghostfolio/api/models/rules/fees/fee-ratio-total-investment-volume'; import { BuyingPower } from '@ghostfolio/api/models/rules/liquidity/buying-power'; import { RegionalMarketClusterRiskAsiaPacific } from '@ghostfolio/api/models/rules/regional-market-cluster-risk/asia-pacific'; import { RegionalMarketClusterRiskEmergingMarkets } from '@ghostfolio/api/models/rules/regional-market-cluster-risk/emerging-markets'; @@ -105,13 +105,13 @@ export class PortfolioService { public constructor( private readonly accountBalanceService: AccountBalanceService, private readonly accountService: AccountService, + private readonly activitiesService: ActivitiesService, private readonly benchmarkService: BenchmarkService, private readonly calculatorFactory: PortfolioCalculatorFactory, private readonly dataProviderService: DataProviderService, private readonly exchangeRateDataService: ExchangeRateDataService, private readonly i18nService: I18nService, private readonly impersonationService: ImpersonationService, - private readonly orderService: OrderService, @Inject(REQUEST) private readonly request: RequestWithUser, private readonly rulesService: RulesService, private readonly symbolProfileService: SymbolProfileService, @@ -403,10 +403,10 @@ export class PortfolioService { const user = await this.userService.user({ id: userId }); const userCurrency = this.getUserCurrency(user); - const { endDate, startDate } = getIntervalFromDateRange(dateRange); + const { endDate, startDate } = getIntervalFromDateRange({ dateRange }); const { activities } = - await this.orderService.getOrdersForPortfolioCalculator({ + await this.activitiesService.getActivitiesForPortfolioCalculator({ filters, userCurrency, userId @@ -490,7 +490,7 @@ export class PortfolioService { ); const { activities } = - await this.orderService.getOrdersForPortfolioCalculator({ + await this.activitiesService.getActivitiesForPortfolioCalculator({ filters, userCurrency, userId @@ -623,6 +623,28 @@ export class PortfolioService { ? 0 : valueInBaseCurrency.div(filteredValueInBaseCurrency).toNumber(), assetClass: assetProfile.assetClass, + assetProfile: { + assetClass: assetProfile.assetClass, + assetSubClass: assetProfile.assetSubClass, + countries: assetProfile.countries, + currency: assetProfile.currency, + dataSource: assetProfile.dataSource, + holdings: assetProfile.holdings.map( + ({ allocationInPercentage, name }) => { + return { + allocationInPercentage, + name, + valueInBaseCurrency: valueInBaseCurrency + .mul(allocationInPercentage) + .toNumber() + }; + } + ), + name: assetProfile.name, + sectors: assetProfile.sectors, + symbol: assetProfile.symbol, + url: assetProfile.url + }, assetSubClass: assetProfile.assetSubClass, countries: assetProfile.countries, dataSource: assetProfile.dataSource, @@ -758,7 +780,7 @@ export class PortfolioService { const userCurrency = this.getUserCurrency(user); const { activities } = - await this.orderService.getOrdersForPortfolioCalculator({ + await this.activitiesService.getActivitiesForPortfolioCalculator({ userCurrency, userId }); @@ -988,7 +1010,7 @@ export class PortfolioService { userId, userCurrency }), - this.orderService.getOrdersForPortfolioCalculator({ + this.activitiesService.getActivitiesForPortfolioCalculator({ filters, userCurrency, userId @@ -1007,7 +1029,8 @@ export class PortfolioService { netPerformancePercentage: 0, netPerformancePercentageWithCurrencyEffect: 0, netPerformanceWithCurrencyEffect: 0, - totalInvestment: 0 + totalInvestment: 0, + totalInvestmentValueWithCurrencyEffect: 0 } }; } @@ -1024,7 +1047,7 @@ export class PortfolioService { const { errors, hasErrors, historicalData } = await portfolioCalculator.getSnapshot(); - const { endDate, startDate } = getIntervalFromDateRange(dateRange); + const { endDate, startDate } = getIntervalFromDateRange({ dateRange }); const { chart } = await portfolioCalculator.getPerformance({ end: endDate, @@ -1038,6 +1061,7 @@ export class PortfolioService { netPerformanceWithCurrencyEffect, netWorth, totalInvestment, + totalInvestmentValueWithCurrencyEffect, valueWithCurrencyEffect } = chart?.at(-1) ?? { netPerformance: 0, @@ -1058,6 +1082,7 @@ export class PortfolioService { netPerformance, netPerformanceWithCurrencyEffect, totalInvestment, + totalInvestmentValueWithCurrencyEffect, currentNetWorth: netWorth, currentValueInBaseCurrency: valueWithCurrencyEffect, netPerformancePercentage: netPerformanceInPercentage, @@ -1306,11 +1331,11 @@ export class PortfolioService { }), rules: await this.rulesService.evaluate( [ - new FeeRatioInitialInvestment( + new FeeRatioTotalInvestmentVolume( this.exchangeRateDataService, this.i18nService, userSettings.language, - summary.committedFunds, + summary.totalBuy + summary.totalSell, summary.fees ) ], @@ -1346,7 +1371,12 @@ export class PortfolioService { }) { userId = await this.getUserId(impersonationId, userId); - await this.orderService.assignTags({ dataSource, symbol, tags, userId }); + await this.activitiesService.assignTags({ + dataSource, + symbol, + tags, + userId + }); } private getAggregatedMarkets(holdings: Record): { @@ -1669,6 +1699,17 @@ export class PortfolioService { allocationInPercentage: 0, assetClass: AssetClass.LIQUIDITY, assetSubClass: AssetSubClass.CASH, + assetProfile: { + currency, + assetClass: AssetClass.LIQUIDITY, + assetSubClass: AssetSubClass.CASH, + countries: [], + dataSource: undefined, + holdings: [], + name: currency, + sectors: [], + symbol: currency + }, countries: [], dataSource: undefined, dateOfFirstActivity: undefined, @@ -1838,7 +1879,7 @@ export class PortfolioService { userId = await this.getUserId(impersonationId, userId); const user = await this.userService.user({ id: userId }); - const { activities } = await this.orderService.getOrders({ + const { activities } = await this.activitiesService.getActivities({ userCurrency, userId, withExcludedAccountsAndActivities: true @@ -1860,8 +1901,11 @@ export class PortfolioService { } } - const { currentValueInBaseCurrency, totalInvestment } = - await portfolioCalculator.getSnapshot(); + const { + currentValueInBaseCurrency, + totalInvestment, + totalInvestmentWithCurrencyEffect + } = await portfolioCalculator.getSnapshot(); const { performance } = await this.getPerformance({ impersonationId, @@ -1908,8 +1952,6 @@ export class PortfolioService { .plus(emergencyFundHoldingsValueInBaseCurrency) .toNumber(); - const committedFunds = new Big(totalBuy).minus(totalSell); - const totalOfExcludedActivities = this.getSumOfActivityType({ userCurrency, activities: excludedActivities, @@ -1973,7 +2015,6 @@ export class PortfolioService { activityCount: activities.filter(({ type }) => { return ['BUY', 'SELL'].includes(type); }).length, - committedFunds: committedFunds.toNumber(), currentValueInBaseCurrency: currentValueInBaseCurrency.toNumber(), dividendInBaseCurrency: dividendInBaseCurrency.toNumber(), emergencyFund: { @@ -2004,6 +2045,8 @@ export class PortfolioService { interestInBaseCurrency: interest.toNumber(), liabilitiesInBaseCurrency: liabilities.toNumber(), totalInvestment: totalInvestment.toNumber(), + totalInvestmentValueWithCurrencyEffect: + totalInvestmentWithCurrencyEffect.toNumber(), totalValueInBaseCurrency: netWorth }; } 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 1ea0a6137..619d23fc5 100644 --- a/apps/api/src/app/redis-cache/redis-cache.service.ts +++ b/apps/api/src/app/redis-cache/redis-cache.service.ts @@ -6,7 +6,7 @@ import { CACHE_MANAGER, Cache } from '@nestjs/cache-manager'; import { Inject, Injectable, Logger } from '@nestjs/common'; import Keyv from 'keyv'; import ms from 'ms'; -import { createHash } from 'node:crypto'; +import { createHash, randomUUID } from 'node:crypto'; @Injectable() export class RedisCacheService { @@ -75,13 +75,16 @@ export class RedisCacheService { } public async isHealthy() { - const testKey = '__health_check__'; + const HEALTH_CHECK_TIMEOUT = ms('5 seconds'); + + const testKey = `__health_check__${randomUUID().replace(/-/g, '')}`; const testValue = Date.now().toString(); try { await Promise.race([ (async () => { - await this.set(testKey, testValue, ms('1 second')); + await this.set(testKey, testValue, HEALTH_CHECK_TIMEOUT); + const result = await this.get(testKey); if (result !== testValue) { @@ -91,7 +94,7 @@ export class RedisCacheService { new Promise((_, reject) => setTimeout( () => reject(new Error('Redis health check failed: timeout')), - ms('2 seconds') + HEALTH_CHECK_TIMEOUT ) ) ]); diff --git a/apps/api/src/app/subscription/subscription.service.ts b/apps/api/src/app/subscription/subscription.service.ts index 689ee3e6a..877ea0ee4 100644 --- a/apps/api/src/app/subscription/subscription.service.ts +++ b/apps/api/src/app/subscription/subscription.service.ts @@ -35,7 +35,7 @@ export class SubscriptionService { this.stripe = new Stripe( this.configurationService.get('STRIPE_SECRET_KEY'), { - apiVersion: '2026-01-28.clover' + apiVersion: '2026-02-25.clover' } ); } diff --git a/apps/api/src/app/user/user.module.ts b/apps/api/src/app/user/user.module.ts index 7ca68d275..3f4e898fc 100644 --- a/apps/api/src/app/user/user.module.ts +++ b/apps/api/src/app/user/user.module.ts @@ -1,4 +1,4 @@ -import { OrderModule } from '@ghostfolio/api/app/order/order.module'; +import { ActivitiesModule } from '@ghostfolio/api/app/activities/activities.module'; import { SubscriptionModule } from '@ghostfolio/api/app/subscription/subscription.module'; import { RedactValuesInResponseModule } from '@ghostfolio/api/interceptors/redact-values-in-response/redact-values-in-response.module'; import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module'; @@ -18,6 +18,7 @@ import { UserService } from './user.service'; controllers: [UserController], exports: [UserService], imports: [ + ActivitiesModule, ConfigurationModule, I18nModule, ImpersonationModule, @@ -25,7 +26,6 @@ import { UserService } from './user.service'; secret: process.env.JWT_SECRET_KEY, signOptions: { expiresIn: '30 days' } }), - OrderModule, PrismaModule, PropertyModule, RedactValuesInResponseModule, diff --git a/apps/api/src/app/user/user.service.ts b/apps/api/src/app/user/user.service.ts index def0b94d9..370f5d422 100644 --- a/apps/api/src/app/user/user.service.ts +++ b/apps/api/src/app/user/user.service.ts @@ -1,4 +1,4 @@ -import { OrderService } from '@ghostfolio/api/app/order/order.service'; +import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.service'; import { SubscriptionService } from '@ghostfolio/api/app/subscription/subscription.service'; import { environment } from '@ghostfolio/api/environments/environment'; import { PortfolioChangedEvent } from '@ghostfolio/api/events/portfolio-changed.event'; @@ -12,7 +12,7 @@ import { CurrencyClusterRiskCurrentInvestment } from '@ghostfolio/api/models/rul import { EconomicMarketClusterRiskDevelopedMarkets } from '@ghostfolio/api/models/rules/economic-market-cluster-risk/developed-markets'; import { EconomicMarketClusterRiskEmergingMarkets } from '@ghostfolio/api/models/rules/economic-market-cluster-risk/emerging-markets'; import { EmergencyFundSetup } from '@ghostfolio/api/models/rules/emergency-fund/emergency-fund-setup'; -import { FeeRatioInitialInvestment } from '@ghostfolio/api/models/rules/fees/fee-ratio-initial-investment'; +import { FeeRatioTotalInvestmentVolume } from '@ghostfolio/api/models/rules/fees/fee-ratio-total-investment-volume'; import { BuyingPower } from '@ghostfolio/api/models/rules/liquidity/buying-power'; import { RegionalMarketClusterRiskAsiaPacific } from '@ghostfolio/api/models/rules/regional-market-cluster-risk/asia-pacific'; import { RegionalMarketClusterRiskEmergingMarkets } from '@ghostfolio/api/models/rules/regional-market-cluster-risk/emerging-markets'; @@ -55,10 +55,10 @@ import { createHmac } from 'node:crypto'; @Injectable() export class UserService { public constructor( + private readonly activitiesService: ActivitiesService, private readonly configurationService: ConfigurationService, private readonly eventEmitter: EventEmitter2, private readonly i18nService: I18nService, - private readonly orderService: OrderService, private readonly prismaService: PrismaService, private readonly propertyService: PropertyService, private readonly subscriptionService: SubscriptionService, @@ -376,7 +376,7 @@ export class UserService { undefined, undefined ).getSettings(user.settings.settings), - FeeRatioInitialInvestment: new FeeRatioInitialInvestment( + FeeRatioTotalInvestmentVolume: new FeeRatioTotalInvestmentVolume( undefined, undefined, undefined, @@ -530,8 +530,14 @@ export class UserService { } } - if (!environment.production && hasRole(user, Role.ADMIN)) { - currentPermissions.push(permissions.impersonateAllUsers); + if (hasRole(user, Role.ADMIN)) { + if (this.configurationService.get('ENABLE_FEATURE_BULL_BOARD')) { + currentPermissions.push(permissions.accessAdminControlBullBoard); + } + + if (!environment.production) { + currentPermissions.push(permissions.impersonateAllUsers); + } } user.accounts = user.accounts.sort((a, b) => { @@ -643,7 +649,7 @@ export class UserService { } catch {} try { - await this.orderService.deleteOrders({ + await this.activitiesService.deleteActivities({ userId: where.id }); } catch {} diff --git a/apps/api/src/assets/cryptocurrencies/cryptocurrencies.json b/apps/api/src/assets/cryptocurrencies/cryptocurrencies.json index e456f6f1d..d00ded6ef 100644 --- a/apps/api/src/assets/cryptocurrencies/cryptocurrencies.json +++ b/apps/api/src/assets/cryptocurrencies/cryptocurrencies.json @@ -421,6 +421,7 @@ "AGS": "Aegis", "AGT": "Alaya Governance Token", "AGURI": "Aguri-Chan", + "AGUSTO": "Agusto", "AGV": "Astra Guild Ventures", "AGVC": "AgaveCoin", "AGVE": "Agave", @@ -662,6 +663,7 @@ "ALN": "Aluna", "ALNV1": "Aluna v1", "ALOHA": "Aloha", + "ALOKA": "ALOKA", "ALON": "Alon", "ALOR": "The Algorix", "ALOT": "Dexalot", @@ -708,6 +710,7 @@ "AMADEUS": "AMADEUS", "AMAL": "AMAL", "AMAPT": "Amnis Finance", + "AMARA": "AMARA", "AMATEN": "Amaten", "AMATO": "AMATO", "AMAZINGTEAM": "AmazingTeamDAO", @@ -1344,6 +1347,7 @@ "AZIT": "Azit", "AZNX": "AstraZeneca xStock", "AZR": "Azure", + "AZTEC": "AZTEC", "AZU": "Azultec", "AZUKI": "Azuki", "AZUKI2": "AZUKI 2.0", @@ -1373,6 +1377,7 @@ "BABI": "Babylons", "BABL": "Babylon Finance", "BABY": "Babylon", + "BABY4": "Baby 4", "BABYANDY": "Baby Andy", "BABYASTER": "Baby Aster", "BABYB": "Baby Bali", @@ -2342,6 +2347,7 @@ "BNPL": "BNPL Pay", "BNR": "BiNeuro", "BNRTX": "BnrtxCoin", + "BNRY": "Binary Coin", "BNS": "BNS token", "BNSAI": "bonsAI Network", "BNSD": "BNSD Finance", @@ -2526,9 +2532,10 @@ "BOSSCOQ": "THE COQFATHER", "BOST": "BoostCoin", "BOSU": "Bosu Inu", - "BOT": "Bot Planet", + "BOT": "HyperBot", "BOTC": "BotChain", "BOTIFY": "BOTIFY", + "BOTPLANET": "Bot Planet", "BOTS": "ArkDAO", "BOTTO": "Botto", "BOTX": "BOTXCOIN", @@ -3201,6 +3208,7 @@ "CATCO": "CatCoin", "CATCOIN": "CatCoin", "CATCOINETH": "Catcoin", + "CATCOINIO": "Catcoin", "CATCOINOFSOL": "Cat Coin", "CATCOINV2": "CatCoin Cash", "CATDOG": "Cat-Dog", @@ -3583,6 +3591,7 @@ "CIC": "Crazy Internet Coin", "CICHAIN": "CIChain", "CIF": "Crypto Improvement Fund", + "CIFRON": "Cipher Mining (Ondo Tokenized)", "CIG": "cig", "CIM": "COINCOME", "CIN": "CinderCoin", @@ -3718,6 +3727,7 @@ "CMPT": "Spatial Computing", "CMPV2": "Caduceus Protocol", "CMQ": "Communique", + "CMR": "U.S Critical Mineral Reserve", "CMS": "COMSA", "CMSN": "The Commission", "CMT": "CyberMiles", @@ -4630,6 +4640,7 @@ "DEFIL": "DeFIL", "DEFILAB": "Defi", "DEFISCALE": "DeFiScale", + "DEFISSI": "DEFI.ssi", "DEFIT": "Digital Fitness", "DEFLA": "Defla", "DEFLCT": "Deflect", @@ -6323,7 +6334,7 @@ "FIFTY": "FIFTYONEFIFTY", "FIG": "FlowCom", "FIGH": "FIGHT FIGHT FIGHT", - "FIGHT": "Fight to MAGA", + "FIGHT2MAGA": "Fight to MAGA", "FIGHTMAGA": "FIGHT MAGA", "FIGHTPEPE": "FIGHT PEPE", "FIGHTRUMP": "FIGHT TRUMP", @@ -8039,6 +8050,7 @@ "HONOR": "HonorLand", "HONX": "Honeywell xStock", "HOODOG": "Hoodog", + "HOODON": "Robinhood Markets (Ondo Tokenized)", "HOODRAT": "Hoodrat Coin", "HOODX": "Robinhood xStock", "HOOF": "Metaderby Hoof", @@ -8395,6 +8407,7 @@ "IMS": "Independent Money System", "IMST": "Imsmart", "IMT": "Immortal Token", + "IMU": "Immunefi", "IMUSIFY": "imusify", "IMVR": "ImmVRse", "IMX": "Immutable X", @@ -8750,6 +8763,7 @@ "JFIVE": "Jonny Five", "JFOX": "JuniperFox AI", "JFP": "JUSTICE FOR PEANUT", + "JGGL": "JGGL Token", "JGLP": "Jones GLP", "JGN": "Juggernaut", "JHH": "Jen-Hsun Huang", @@ -9891,7 +9905,7 @@ "LRN": "Loopring [NEO]", "LRT": "LandRocker", "LSC": "LS Coin", - "LSD": "Pontem Liquidswap", + "LSD": "LSD", "LSDOGE": "LSDoge", "LSETH": "Liquid Staked ETH", "LSHARE": "LSHARE", @@ -10167,8 +10181,7 @@ "MANUSAI": "Manus AI Agent", "MANYU": "Manyu", "MANYUDOG": "MANYU", - "MAO": "MAO", - "MAOMEME": "Mao", + "MAO": "Mao", "MAOW": "MAOW", "MAP": "MAP Protocol", "MAPC": "MapCoin", @@ -10631,6 +10644,7 @@ "MICRO": "Micro GPT", "MICRODOGE": "MicroDoge", "MICROMINES": "Micromines", + "MICROVISION": "MicroVisionChain", "MIDAI": "Midway AI", "MIDAS": "Midas", "MIDASDOLLAR": "Midas Dollar Share", @@ -13146,6 +13160,7 @@ "PONKE": "Ponke", "PONKEBNB": "Ponke BNB", "PONKEI": "Chinese Ponkei the Original", + "PONTEM": "Pontem Liquidswap", "PONYO": "Ponyo Impact", "PONZI": "Ponzi", "PONZIO": "Ponzio The Cat", @@ -13573,6 +13588,7 @@ "QNX": "QueenDex Coin", "QOBI": "Qobit", "QOM": "Shiba Predator", + "QONE": "QONE", "QOOB": "QOOBER", "QORA": "QoraCoin", "QORPO": "QORPO WORLD", @@ -15153,6 +15169,7 @@ "SNAP": "SnapEx", "SNAPCAT": "Snapcat", "SNAPKERO": "SNAP", + "SNAPON": "Snap (Ondo Tokenized)", "SNB": "SynchroBitcoin", "SNC": "SunContract", "SNCT": "SnakeCity", @@ -15380,7 +15397,7 @@ "SP8DE": "Sp8de", "SPA": "Sperax", "SPAC": "SPACE DOGE", - "SPACE": "MicroVisionChain", + "SPACE": "Spacecoin", "SPACECOIN": "SpaceCoin", "SPACED": "SPACE DRAGON", "SPACEHAMSTER": "Space Hamster", @@ -15868,6 +15885,7 @@ "SUPERCYCLE": "Crypto SuperCycle", "SUPERDAPP": "SuperDapp", "SUPERF": "SUPER FLOKI", + "SUPERFL": "Superfluid", "SUPERGROK": "SuperGrok", "SUPEROETHB": "Super OETH", "SUPERT": "Super Trump", @@ -16790,6 +16808,7 @@ "TSLAON": "Tesla (Ondo Tokenized)", "TSLAX": "Tesla xStock", "TSLT": "Tamkin", + "TSMON": "Taiwan Semiconductor Manufacturing (Ondo Tokenized)", "TSN": "Tsunami Exchange Token", "TSO": "Thesirion", "TSOTCHKE": "tsotchke", @@ -17181,8 +17200,10 @@ "USDL": "Lift Dollar", "USDM": "USDM", "USDMA": "USD mars", - "USDN": "Neutral AI", + "USDN": "Ultimate Synthetic Delta Neutral", + "USDNEUTRAL": "Neutral AI", "USDO": "USD Open Dollar", + "USDON": "U.S. Dollar Tokenized Currency (Ondo)", "USDP": "Pax Dollar", "USDPLUS": "Overnight.fi USD+", "USDQ": "Quantoz USDQ", @@ -17456,6 +17477,7 @@ "VIDZ": "PureVidz", "VIEW": "Viewly", "VIG": "TheVig", + "VIGI": "Vigi", "VIK": "VIKTAMA", "VIKITA": "VIKITA", "VIKKY": "VikkyToken", @@ -17513,6 +17535,7 @@ "VLC": "Volcano Uni", "VLDY": "Validity", "VLK": "Vulkania", + "VLR": "Velora", "VLS": "Veles", "VLT": "Veltor", "VLTC": "Venus LTC", @@ -17733,6 +17756,7 @@ "WANUSDT": "wanUSDT", "WAP": "Wet Ass Pussy", "WAR": "WAR", + "WARD": "Warden", "WARP": "WarpCoin", "WARPED": "Warped Games", "WARPIE": "Warpie", @@ -18494,6 +18518,7 @@ "XP": "Xphere", "XPA": "XPA", "XPARTY": "X Party", + "XPASS": "XPASS Token", "XPAT": "Bitnation Pangea", "XPAY": "Wallet Pay", "XPB": "Pebble Coin", @@ -18869,8 +18894,7 @@ "ZEBU": "ZEBU", "ZEC": "ZCash", "ZECD": "ZCashDarkCoin", - "ZED": "ZED Token", - "ZEDCOIN": "ZedCoin", + "ZED": "ZedCoins", "ZEDD": "ZedDex", "ZEDTOKEN": "Zed Token", "ZEDX": "ZEDX Сoin", @@ -19108,6 +19132,7 @@ "币安人生": "币安人生", "恶俗企鹅": "恶俗企鹅", "我踏马来了": "我踏马来了", + "狗屎": "狗屎", "老子": "老子", "雪球": "雪球", "黑马": "黑马" diff --git a/apps/api/src/assets/cryptocurrencies/custom.json b/apps/api/src/assets/cryptocurrencies/custom.json index 814aeec34..a26fc33df 100644 --- a/apps/api/src/assets/cryptocurrencies/custom.json +++ b/apps/api/src/assets/cryptocurrencies/custom.json @@ -4,6 +4,7 @@ "LUNA1": "Terra", "LUNA2": "Terra", "SGB1": "Songbird", + "SKY33038": "Sky", "SMURFCAT": "Real Smurf Cat", "TON11419": "Toncoin", "UNI1": "Uniswap", diff --git a/apps/api/src/events/asset-profile-changed.event.ts b/apps/api/src/events/asset-profile-changed.event.ts index 46a8c5db4..c08fe59f1 100644 --- a/apps/api/src/events/asset-profile-changed.event.ts +++ b/apps/api/src/events/asset-profile-changed.event.ts @@ -8,4 +8,16 @@ export class AssetProfileChangedEvent { public static getName(): string { return 'assetProfile.changed'; } + + public getCurrency() { + return this.data.currency; + } + + public getDataSource() { + return this.data.dataSource; + } + + public getSymbol() { + return this.data.symbol; + } } diff --git a/apps/api/src/events/asset-profile-changed.listener.ts b/apps/api/src/events/asset-profile-changed.listener.ts index ad80ee4a5..cc70edad6 100644 --- a/apps/api/src/events/asset-profile-changed.listener.ts +++ b/apps/api/src/events/asset-profile-changed.listener.ts @@ -1,29 +1,74 @@ -import { OrderService } from '@ghostfolio/api/app/order/order.service'; +import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.service'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { DataGatheringService } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.service'; import { DEFAULT_CURRENCY } from '@ghostfolio/common/config'; +import { getAssetProfileIdentifier } from '@ghostfolio/common/helper'; import { Injectable, Logger } from '@nestjs/common'; import { OnEvent } from '@nestjs/event-emitter'; +import { DataSource } from '@prisma/client'; +import ms from 'ms'; import { AssetProfileChangedEvent } from './asset-profile-changed.event'; @Injectable() export class AssetProfileChangedListener { + private static readonly DEBOUNCE_DELAY = ms('5 seconds'); + + private debounceTimers = new Map(); + public constructor( + private readonly activitiesService: ActivitiesService, private readonly configurationService: ConfigurationService, private readonly dataGatheringService: DataGatheringService, private readonly dataProviderService: DataProviderService, - private readonly exchangeRateDataService: ExchangeRateDataService, - private readonly orderService: OrderService + private readonly exchangeRateDataService: ExchangeRateDataService ) {} @OnEvent(AssetProfileChangedEvent.getName()) - public async handleAssetProfileChanged(event: AssetProfileChangedEvent) { + public handleAssetProfileChanged(event: AssetProfileChangedEvent) { + const currency = event.getCurrency(); + const dataSource = event.getDataSource(); + const symbol = event.getSymbol(); + + const key = getAssetProfileIdentifier({ + dataSource, + symbol + }); + + const existingTimer = this.debounceTimers.get(key); + + if (existingTimer) { + clearTimeout(existingTimer); + } + + this.debounceTimers.set( + key, + setTimeout(() => { + this.debounceTimers.delete(key); + + void this.processAssetProfileChanged({ + currency, + dataSource, + symbol + }); + }, AssetProfileChangedListener.DEBOUNCE_DELAY) + ); + } + + private async processAssetProfileChanged({ + currency, + dataSource, + symbol + }: { + currency: string; + dataSource: DataSource; + symbol: string; + }) { Logger.log( - `Asset profile of ${event.data.symbol} (${event.data.dataSource}) has changed`, + `Asset profile of ${symbol} (${dataSource}) has changed`, 'AssetProfileChangedListener' ); @@ -31,16 +76,16 @@ export class AssetProfileChangedListener { this.configurationService.get( 'ENABLE_FEATURE_GATHER_NEW_EXCHANGE_RATES' ) === false || - event.data.currency === DEFAULT_CURRENCY + currency === DEFAULT_CURRENCY ) { return; } const existingCurrencies = this.exchangeRateDataService.getCurrencies(); - if (!existingCurrencies.includes(event.data.currency)) { + if (!existingCurrencies.includes(currency)) { Logger.log( - `New currency ${event.data.currency} has been detected`, + `New currency ${currency} has been detected`, 'AssetProfileChangedListener' ); @@ -48,13 +93,13 @@ export class AssetProfileChangedListener { } const { dateOfFirstActivity } = - await this.orderService.getStatisticsByCurrency(event.data.currency); + await this.activitiesService.getStatisticsByCurrency(currency); if (dateOfFirstActivity) { await this.dataGatheringService.gatherSymbol({ dataSource: this.dataProviderService.getDataSourceForExchangeRates(), date: dateOfFirstActivity, - symbol: `${DEFAULT_CURRENCY}${event.data.currency}` + symbol: `${DEFAULT_CURRENCY}${currency}` }); } } diff --git a/apps/api/src/events/events.module.ts b/apps/api/src/events/events.module.ts index ece67ebe0..772766945 100644 --- a/apps/api/src/events/events.module.ts +++ b/apps/api/src/events/events.module.ts @@ -1,4 +1,4 @@ -import { OrderModule } from '@ghostfolio/api/app/order/order.module'; +import { ActivitiesModule } from '@ghostfolio/api/app/activities/activities.module'; 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'; @@ -12,11 +12,11 @@ import { PortfolioChangedListener } from './portfolio-changed.listener'; @Module({ imports: [ + ActivitiesModule, ConfigurationModule, DataGatheringModule, DataProviderModule, ExchangeRateDataModule, - OrderModule, RedisCacheModule ], providers: [AssetProfileChangedListener, PortfolioChangedListener] diff --git a/apps/api/src/events/portfolio-changed.listener.ts b/apps/api/src/events/portfolio-changed.listener.ts index d12b9558d..f8e2a9229 100644 --- a/apps/api/src/events/portfolio-changed.listener.ts +++ b/apps/api/src/events/portfolio-changed.listener.ts @@ -2,22 +2,44 @@ import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.s import { Injectable, Logger } from '@nestjs/common'; import { OnEvent } from '@nestjs/event-emitter'; +import ms from 'ms'; import { PortfolioChangedEvent } from './portfolio-changed.event'; @Injectable() export class PortfolioChangedListener { + private static readonly DEBOUNCE_DELAY = ms('5 seconds'); + + private debounceTimers = new Map(); + public constructor(private readonly redisCacheService: RedisCacheService) {} @OnEvent(PortfolioChangedEvent.getName()) handlePortfolioChangedEvent(event: PortfolioChangedEvent) { + const userId = event.getUserId(); + + const existingTimer = this.debounceTimers.get(userId); + + if (existingTimer) { + clearTimeout(existingTimer); + } + + this.debounceTimers.set( + userId, + setTimeout(() => { + this.debounceTimers.delete(userId); + + void this.processPortfolioChanged({ userId }); + }, PortfolioChangedListener.DEBOUNCE_DELAY) + ); + } + + private async processPortfolioChanged({ userId }: { userId: string }) { Logger.log( - `Portfolio of user '${event.getUserId()}' has changed`, + `Portfolio of user '${userId}' has changed`, 'PortfolioChangedListener' ); - this.redisCacheService.removePortfolioSnapshotsByUserId({ - userId: event.getUserId() - }); + await this.redisCacheService.removePortfolioSnapshotsByUserId({ userId }); } } diff --git a/apps/api/src/helper/object.helper.spec.ts b/apps/api/src/helper/object.helper.spec.ts index ed821390f..ba8760c70 100644 --- a/apps/api/src/helper/object.helper.spec.ts +++ b/apps/api/src/helper/object.helper.spec.ts @@ -1540,7 +1540,6 @@ describe('redactAttributes', () => { netPerformanceWithCurrencyEffect: null, totalBuy: null, totalSell: null, - committedFunds: null, currentValueInBaseCurrency: null, dividendInBaseCurrency: null, emergencyFund: null, @@ -1554,6 +1553,7 @@ describe('redactAttributes', () => { items: null, liabilities: null, totalInvestment: null, + totalInvestmentValueWithCurrencyEffect: null, totalValueInBaseCurrency: null, currentNetWorth: null } @@ -3016,7 +3016,6 @@ describe('redactAttributes', () => { netPerformanceWithCurrencyEffect: null, totalBuy: null, totalSell: null, - committedFunds: null, currentValueInBaseCurrency: null, dividendInBaseCurrency: null, emergencyFund: null, @@ -3030,6 +3029,7 @@ describe('redactAttributes', () => { items: null, liabilities: null, totalInvestment: null, + totalInvestmentValueWithCurrencyEffect: null, totalValueInBaseCurrency: null, currentNetWorth: null } diff --git a/apps/api/src/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor.ts b/apps/api/src/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor.ts index eaa6dd08c..57643f76c 100644 --- a/apps/api/src/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor.ts +++ b/apps/api/src/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor.ts @@ -62,10 +62,13 @@ export class TransformDataSourceInResponseInterceptor< valueMap, object: data, paths: [ + 'activities[*].dataSource', 'activities[*].SymbolProfile.dataSource', 'benchmarks[*].dataSource', + 'errors[*].dataSource', 'fearAndGreedIndex.CRYPTOCURRENCIES.dataSource', 'fearAndGreedIndex.STOCKS.dataSource', + 'holdings[*].assetProfile.dataSource', 'holdings[*].dataSource', 'items[*].dataSource', 'SymbolProfile.dataSource', diff --git a/apps/api/src/main.ts b/apps/api/src/main.ts index a8de3dc5e..f08a09a83 100644 --- a/apps/api/src/main.ts +++ b/apps/api/src/main.ts @@ -1,4 +1,5 @@ import { + BULL_BOARD_ROUTE, DEFAULT_HOST, DEFAULT_PORT, STORYBOOK_PATH, @@ -14,6 +15,7 @@ import { import { ConfigService } from '@nestjs/config'; import { NestFactory } from '@nestjs/core'; import type { NestExpressApplication } from '@nestjs/platform-express'; +import cookieParser from 'cookie-parser'; import { NextFunction, Request, Response } from 'express'; import helmet from 'helmet'; @@ -46,6 +48,7 @@ async function bootstrap() { }); app.setGlobalPrefix('api', { exclude: [ + `${BULL_BOARD_ROUTE.substring(1)}{/*wildcard}`, 'sitemap.xml', ...SUPPORTED_LANGUAGE_CODES.map((languageCode) => { // Exclude language-specific routes with an optional wildcard @@ -53,6 +56,7 @@ async function bootstrap() { }) ] }); + app.useGlobalPipes( new ValidationPipe({ forbidNonWhitelisted: true, @@ -64,6 +68,8 @@ async function bootstrap() { // Support 10mb csv/json files for importing activities app.useBodyParser('json', { limit: '10mb' }); + app.use(cookieParser()); + if (configService.get('ENABLE_FEATURE_SUBSCRIPTION') === 'true') { app.use((req: Request, res: Response, next: NextFunction) => { if (req.path.startsWith(STORYBOOK_PATH)) { diff --git a/apps/api/src/middlewares/bull-board-auth.middleware.ts b/apps/api/src/middlewares/bull-board-auth.middleware.ts new file mode 100644 index 000000000..432deb974 --- /dev/null +++ b/apps/api/src/middlewares/bull-board-auth.middleware.ts @@ -0,0 +1,28 @@ +import { BULL_BOARD_COOKIE_NAME } from '@ghostfolio/common/config'; +import { hasPermission, permissions } from '@ghostfolio/common/permissions'; + +import { ForbiddenException, Injectable, NestMiddleware } from '@nestjs/common'; +import { NextFunction, Request, Response } from 'express'; +import passport from 'passport'; + +@Injectable() +export class BullBoardAuthMiddleware implements NestMiddleware { + public use(req: Request, res: Response, next: NextFunction) { + const token = req.cookies?.[BULL_BOARD_COOKIE_NAME]; + + if (token) { + req.headers.authorization = `Bearer ${token}`; + } + + passport.authenticate('jwt', { session: false }, (error, user) => { + if ( + error || + !hasPermission(user?.permissions, permissions.accessAdminControl) + ) { + next(new ForbiddenException()); + } else { + next(); + } + })(req, res, next); + } +} diff --git a/apps/api/src/models/rule.ts b/apps/api/src/models/rule.ts index 9c27e0018..622375b5b 100644 --- a/apps/api/src/models/rule.ts +++ b/apps/api/src/models/rule.ts @@ -57,7 +57,7 @@ export abstract class Rule implements RuleInterface { previousValue + this.exchangeRateDataService.toCurrency( new Big(currentValue.quantity) - .mul(currentValue.marketPrice) + .mul(currentValue.marketPrice ?? 0) .toNumber(), currentValue.currency, baseCurrency diff --git a/apps/api/src/models/rules/fees/fee-ratio-initial-investment.ts b/apps/api/src/models/rules/fees/fee-ratio-total-investment-volume.ts similarity index 78% rename from apps/api/src/models/rules/fees/fee-ratio-initial-investment.ts rename to apps/api/src/models/rules/fees/fee-ratio-total-investment-volume.ts index cb85a73ba..07bf5fa2c 100644 --- a/apps/api/src/models/rules/fees/fee-ratio-initial-investment.ts +++ b/apps/api/src/models/rules/fees/fee-ratio-total-investment-volume.ts @@ -3,35 +3,36 @@ import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate- import { I18nService } from '@ghostfolio/api/services/i18n/i18n.service'; import { RuleSettings, UserSettings } from '@ghostfolio/common/interfaces'; -export class FeeRatioInitialInvestment extends Rule { +export class FeeRatioTotalInvestmentVolume extends Rule { private fees: number; - private totalInvestment: number; + private totalInvestmentVolumeInBaseCurrency: number; public constructor( protected exchangeRateDataService: ExchangeRateDataService, private i18nService: I18nService, languageCode: string, - totalInvestment: number, + totalInvestmentVolumeInBaseCurrency: number, fees: number ) { super(exchangeRateDataService, { languageCode, - key: FeeRatioInitialInvestment.name + key: FeeRatioTotalInvestmentVolume.name }); this.fees = fees; - this.totalInvestment = totalInvestment; + this.totalInvestmentVolumeInBaseCurrency = + totalInvestmentVolumeInBaseCurrency; } public evaluate(ruleSettings: Settings) { - const feeRatio = this.totalInvestment - ? this.fees / this.totalInvestment + const feeRatio = this.totalInvestmentVolumeInBaseCurrency + ? this.fees / this.totalInvestmentVolumeInBaseCurrency : 0; if (feeRatio > ruleSettings.thresholdMax) { return { evaluation: this.i18nService.getTranslation({ - id: 'rule.feeRatioInitialInvestment.false', + id: 'rule.feeRatioTotalInvestmentVolume.false', languageCode: this.getLanguageCode(), placeholders: { feeRatio: (ruleSettings.thresholdMax * 100).toFixed(2), @@ -44,7 +45,7 @@ export class FeeRatioInitialInvestment extends Rule { return { evaluation: this.i18nService.getTranslation({ - id: 'rule.feeRatioInitialInvestment.true', + id: 'rule.feeRatioTotalInvestmentVolume.true', languageCode: this.getLanguageCode(), placeholders: { feeRatio: (feeRatio * 100).toPrecision(3), @@ -76,7 +77,7 @@ export class FeeRatioInitialInvestment extends Rule { public getName() { return this.i18nService.getTranslation({ - id: 'rule.feeRatioInitialInvestment', + id: 'rule.feeRatioTotalInvestmentVolume', languageCode: this.getLanguageCode() }); } diff --git a/apps/api/src/services/configuration/configuration.service.ts b/apps/api/src/services/configuration/configuration.service.ts index 5f9d1055d..ad8e84a99 100644 --- a/apps/api/src/services/configuration/configuration.service.ts +++ b/apps/api/src/services/configuration/configuration.service.ts @@ -30,6 +30,7 @@ export class ConfigurationService { API_KEY_FINANCIAL_MODELING_PREP: str({ default: '' }), API_KEY_OPEN_FIGI: str({ default: '' }), API_KEY_RAPID_API: str({ default: '' }), + BULL_BOARD_IS_READ_ONLY: bool({ default: true }), CACHE_QUOTES_TTL: num({ default: ms('1 minute') }), CACHE_TTL: num({ default: CACHE_TTL_NO_CACHE }), DATA_SOURCE_EXCHANGE_RATES: str({ default: DataSource.YAHOO }), @@ -43,6 +44,7 @@ export class ConfigurationService { ENABLE_FEATURE_AUTH_GOOGLE: bool({ default: false }), ENABLE_FEATURE_AUTH_OIDC: bool({ default: false }), ENABLE_FEATURE_AUTH_TOKEN: bool({ default: true }), + ENABLE_FEATURE_BULL_BOARD: bool({ default: false }), ENABLE_FEATURE_FEAR_AND_GREED_INDEX: bool({ default: false }), ENABLE_FEATURE_GATHER_NEW_EXCHANGE_RATES: bool({ default: true }), ENABLE_FEATURE_READ_ONLY_MODE: bool({ default: false }), diff --git a/apps/api/src/services/cryptocurrency/cryptocurrency.module.ts b/apps/api/src/services/cryptocurrency/cryptocurrency.module.ts index 8820205eb..e882f4da5 100644 --- a/apps/api/src/services/cryptocurrency/cryptocurrency.module.ts +++ b/apps/api/src/services/cryptocurrency/cryptocurrency.module.ts @@ -1,9 +1,12 @@ +import { PropertyModule } from '@ghostfolio/api/services/property/property.module'; + import { Module } from '@nestjs/common'; import { CryptocurrencyService } from './cryptocurrency.service'; @Module({ - providers: [CryptocurrencyService], - exports: [CryptocurrencyService] + exports: [CryptocurrencyService], + imports: [PropertyModule], + providers: [CryptocurrencyService] }) export class CryptocurrencyModule {} diff --git a/apps/api/src/services/cryptocurrency/cryptocurrency.service.ts b/apps/api/src/services/cryptocurrency/cryptocurrency.service.ts index b814fc186..933029ea2 100644 --- a/apps/api/src/services/cryptocurrency/cryptocurrency.service.ts +++ b/apps/api/src/services/cryptocurrency/cryptocurrency.service.ts @@ -1,31 +1,39 @@ -import { DEFAULT_CURRENCY } from '@ghostfolio/common/config'; +import { PropertyService } from '@ghostfolio/api/services/property/property.service'; +import { + DEFAULT_CURRENCY, + PROPERTY_CUSTOM_CRYPTOCURRENCIES +} from '@ghostfolio/common/config'; -import { Injectable } from '@nestjs/common'; +import { Injectable, OnModuleInit } from '@nestjs/common'; const cryptocurrencies = require('../../assets/cryptocurrencies/cryptocurrencies.json'); const customCryptocurrencies = require('../../assets/cryptocurrencies/custom.json'); @Injectable() -export class CryptocurrencyService { +export class CryptocurrencyService implements OnModuleInit { private combinedCryptocurrencies: string[]; + public constructor(private readonly propertyService: PropertyService) {} + + public async onModuleInit() { + const customCryptocurrenciesFromDatabase = + await this.propertyService.getByKey>( + PROPERTY_CUSTOM_CRYPTOCURRENCIES + ); + + this.combinedCryptocurrencies = [ + ...Object.keys(cryptocurrencies), + ...Object.keys(customCryptocurrencies), + ...Object.keys(customCryptocurrenciesFromDatabase ?? {}) + ]; + } + public isCryptocurrency(aSymbol = '') { const cryptocurrencySymbol = aSymbol.substring(0, aSymbol.length - 3); return ( aSymbol.endsWith(DEFAULT_CURRENCY) && - this.getCryptocurrencies().includes(cryptocurrencySymbol) + this.combinedCryptocurrencies.includes(cryptocurrencySymbol) ); } - - private getCryptocurrencies() { - if (!this.combinedCryptocurrencies) { - this.combinedCryptocurrencies = [ - ...Object.keys(cryptocurrencies), - ...Object.keys(customCryptocurrencies) - ]; - } - - return this.combinedCryptocurrencies; - } } diff --git a/apps/api/src/services/data-provider/alpha-vantage/alpha-vantage.service.ts b/apps/api/src/services/data-provider/alpha-vantage/alpha-vantage.service.ts index 6030e62d4..40b45a115 100644 --- a/apps/api/src/services/data-provider/alpha-vantage/alpha-vantage.service.ts +++ b/apps/api/src/services/data-provider/alpha-vantage/alpha-vantage.service.ts @@ -16,7 +16,7 @@ import { LookupResponse } from '@ghostfolio/common/interfaces'; -import { Injectable } from '@nestjs/common'; +import { Injectable, OnModuleInit } from '@nestjs/common'; import { DataSource, SymbolProfile } from '@prisma/client'; import Alphavantage from 'alphavantage'; import { format, isAfter, isBefore, parse } from 'date-fns'; @@ -24,12 +24,16 @@ import { format, isAfter, isBefore, parse } from 'date-fns'; import { AlphaVantageHistoricalResponse } from './interfaces/interfaces'; @Injectable() -export class AlphaVantageService implements DataProviderInterface { +export class AlphaVantageService + implements DataProviderInterface, OnModuleInit +{ public alphaVantage; public constructor( private readonly configurationService: ConfigurationService - ) { + ) {} + + public onModuleInit() { this.alphaVantage = Alphavantage({ key: this.configurationService.get('API_KEY_ALPHA_VANTAGE') }); 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 d0d96acac..d5ed69d06 100644 --- a/apps/api/src/services/data-provider/coingecko/coingecko.service.ts +++ b/apps/api/src/services/data-provider/coingecko/coingecko.service.ts @@ -17,7 +17,7 @@ import { LookupResponse } from '@ghostfolio/common/interfaces'; -import { Injectable, Logger } from '@nestjs/common'; +import { Injectable, Logger, OnModuleInit } from '@nestjs/common'; import { AssetClass, AssetSubClass, @@ -27,13 +27,15 @@ import { import { format, fromUnixTime, getUnixTime } from 'date-fns'; @Injectable() -export class CoinGeckoService implements DataProviderInterface { - private readonly apiUrl: string; - private readonly headers: HeadersInit = {}; +export class CoinGeckoService implements DataProviderInterface, OnModuleInit { + private apiUrl: string; + private headers: HeadersInit = {}; public constructor( private readonly configurationService: ConfigurationService - ) { + ) {} + + public onModuleInit() { const apiKeyDemo = this.configurationService.get('API_KEY_COINGECKO_DEMO'); const apiKeyPro = this.configurationService.get('API_KEY_COINGECKO_PRO'); diff --git a/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.spec.ts b/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.spec.ts index c37a9fe3e..9335d86d0 100644 --- a/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.spec.ts +++ b/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.spec.ts @@ -29,7 +29,7 @@ describe('YahooFinanceDataEnhancerService', () => { let yahooFinanceDataEnhancerService: YahooFinanceDataEnhancerService; beforeAll(async () => { - cryptocurrencyService = new CryptocurrencyService(); + cryptocurrencyService = new CryptocurrencyService(null); yahooFinanceDataEnhancerService = new YahooFinanceDataEnhancerService( cryptocurrencyService diff --git a/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.ts b/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.ts index c83e35503..72136dc04 100644 --- a/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.ts +++ b/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.ts @@ -207,14 +207,16 @@ export class YahooFinanceDataEnhancerService implements DataEnhancerInterface { if (['ETF', 'MUTUALFUND'].includes(assetSubClass)) { response.holdings = - assetProfile.topHoldings?.holdings?.map( - ({ holdingName, holdingPercent }) => { + assetProfile.topHoldings?.holdings + ?.filter(({ holdingName }) => { + return !holdingName?.includes('ETF'); + }) + ?.map(({ holdingName, holdingPercent }) => { return { name: this.formatName({ longName: holdingName }), weight: holdingPercent }; - } - ) ?? []; + }) ?? []; response.sectors = ( assetProfile.topHoldings?.sectorWeightings ?? [] diff --git a/apps/api/src/services/data-provider/data-provider.service.ts b/apps/api/src/services/data-provider/data-provider.service.ts index 5a088c0e4..a6b12cce2 100644 --- a/apps/api/src/services/data-provider/data-provider.service.ts +++ b/apps/api/src/services/data-provider/data-provider.service.ts @@ -1,3 +1,4 @@ +import { ImportDataDto } from '@ghostfolio/api/app/import/import-data.dto'; import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { DataProviderInterface } from '@ghostfolio/api/services/data-provider/interfaces/data-provider.interface'; @@ -10,8 +11,10 @@ import { PROPERTY_API_KEY_GHOSTFOLIO, PROPERTY_DATA_SOURCE_MAPPING } from '@ghostfolio/common/config'; +import { CreateOrderDto } from '@ghostfolio/common/dtos'; import { DATE_FORMAT, + getAssetProfileIdentifier, getCurrencyFromSymbol, getStartOfUtcDate, isCurrency, @@ -27,7 +30,7 @@ import { import type { Granularity, UserWithSettings } from '@ghostfolio/common/types'; import { Inject, Injectable, Logger, OnModuleInit } from '@nestjs/common'; -import { DataSource, MarketData, SymbolProfile } from '@prisma/client'; +import { DataSource, MarketData, Prisma, SymbolProfile } from '@prisma/client'; import { Big } from 'big.js'; import { eachDayOfInterval, format, isValid } from 'date-fns'; import { groupBy, isEmpty, isNumber, uniqWith } from 'lodash'; @@ -185,6 +188,125 @@ export class DataProviderService implements OnModuleInit { return dataSources.sort(); } + public async validateActivities({ + activitiesDto, + assetProfilesWithMarketDataDto, + maxActivitiesToImport, + user + }: { + activitiesDto: Pick< + Partial, + 'currency' | 'dataSource' | 'symbol' | 'type' + >[]; + assetProfilesWithMarketDataDto?: ImportDataDto['assetProfiles']; + maxActivitiesToImport: number; + user: UserWithSettings; + }) { + if (activitiesDto?.length > maxActivitiesToImport) { + throw new Error(`Too many activities (${maxActivitiesToImport} at most)`); + } + + const assetProfiles: { + [assetProfileIdentifier: string]: Partial; + } = {}; + + const dataSources = await this.getDataSources(); + + for (const [ + index, + { currency, dataSource, symbol, type } + ] of activitiesDto.entries()) { + const activityPath = + maxActivitiesToImport === 1 ? 'activity' : `activities.${index}`; + + if (!dataSources.includes(dataSource)) { + throw new Error( + `${activityPath}.dataSource ("${dataSource}") is not valid` + ); + } + + if ( + this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') && + user.subscription.type === 'Basic' + ) { + const dataProvider = this.getDataProvider(DataSource[dataSource]); + + if (dataProvider.getDataProviderInfo().isPremium) { + throw new Error( + `${activityPath}.dataSource ("${dataSource}") is not valid` + ); + } + } + + const assetProfileIdentifier = getAssetProfileIdentifier({ + dataSource, + symbol + }); + + if (!assetProfiles[assetProfileIdentifier]) { + if ( + (dataSource === DataSource.MANUAL && type === 'BUY') || + ['FEE', 'INTEREST', 'LIABILITY'].includes(type) + ) { + const assetProfileInImport = assetProfilesWithMarketDataDto?.find( + (assetProfile) => { + return ( + assetProfile.dataSource === dataSource && + assetProfile.symbol === symbol + ); + } + ); + + assetProfiles[assetProfileIdentifier] = { + currency, + dataSource, + symbol, + name: assetProfileInImport?.name ?? symbol + }; + + continue; + } + + let assetProfile: Partial = { currency }; + + try { + assetProfile = ( + await this.getAssetProfiles([ + { + dataSource, + symbol + } + ]) + )?.[symbol]; + } catch {} + + if (!assetProfile?.name) { + const assetProfileInImport = assetProfilesWithMarketDataDto?.find( + (profile) => { + return ( + profile.dataSource === dataSource && profile.symbol === symbol + ); + } + ); + + if (assetProfileInImport) { + Object.assign(assetProfile, assetProfileInImport); + } + } + + if (!assetProfile?.name) { + throw new Error( + `activities.${index}.symbol ("${symbol}") is not valid for the specified data source ("${dataSource}")` + ); + } + + assetProfiles[assetProfileIdentifier] = assetProfile; + } + } + + return assetProfiles; + } + public async getDividends({ dataSource, from, @@ -225,36 +347,35 @@ export class DataProviderService implements OnModuleInit { const granularityQuery = aGranularity === 'month' - ? `AND (date_part('day', date) = 1 OR date >= TIMESTAMP 'yesterday')` - : ''; + ? Prisma.sql`AND (date_part('day', date) = 1 OR date >= TIMESTAMP 'yesterday')` + : Prisma.empty; const rangeQuery = from && to - ? `AND date >= '${format(from, DATE_FORMAT)}' AND date <= '${format( + ? Prisma.sql`AND date >= ${format(from, DATE_FORMAT)}::timestamp AND date <= ${format( to, DATE_FORMAT - )}'` - : ''; + )}::timestamp` + : Prisma.empty; const dataSources = aItems.map(({ dataSource }) => { return dataSource; }); + const symbols = aItems.map(({ symbol }) => { return symbol; }); try { - const queryRaw = ` - SELECT * - FROM "MarketData" - WHERE "dataSource" IN ('${dataSources.join(`','`)}') - AND "symbol" IN ('${symbols.join( - `','` - )}') ${granularityQuery} ${rangeQuery} - ORDER BY date;`; - - const marketDataByGranularity: MarketData[] = - await this.prismaService.$queryRawUnsafe(queryRaw); + const marketDataByGranularity: MarketData[] = await this.prismaService + .$queryRaw` + SELECT * + FROM "MarketData" + WHERE "dataSource"::text IN (${Prisma.join(dataSources)}) + AND "symbol" IN (${Prisma.join(symbols)}) + ${granularityQuery} + ${rangeQuery} + ORDER BY date;`; response = marketDataByGranularity.reduce((r, marketData) => { const { date, marketPrice, symbol } = marketData; 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 cd20fca44..8c718108c 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 @@ -22,7 +22,7 @@ import { } from '@ghostfolio/common/interfaces'; import { MarketState } from '@ghostfolio/common/types'; -import { Injectable, Logger } from '@nestjs/common'; +import { Injectable, Logger, OnModuleInit } from '@nestjs/common'; import { AssetClass, AssetSubClass, @@ -33,14 +33,18 @@ import { addDays, format, isSameDay, isToday } from 'date-fns'; import { isNumber } from 'lodash'; @Injectable() -export class EodHistoricalDataService implements DataProviderInterface { +export class EodHistoricalDataService + implements DataProviderInterface, OnModuleInit +{ private apiKey: string; private readonly URL = 'https://eodhistoricaldata.com/api'; public constructor( private readonly configurationService: ConfigurationService, private readonly symbolProfileService: SymbolProfileService - ) { + ) {} + + public onModuleInit() { this.apiKey = this.configurationService.get('API_KEY_EOD_HISTORICAL_DATA'); } 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 2b4193af5..27391130e 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 @@ -23,7 +23,7 @@ import { } from '@ghostfolio/common/interfaces'; import { MarketState } from '@ghostfolio/common/types'; -import { Injectable, Logger } from '@nestjs/common'; +import { Injectable, Logger, OnModuleInit } from '@nestjs/common'; import { AssetClass, AssetSubClass, @@ -44,7 +44,9 @@ import { import { uniqBy } from 'lodash'; @Injectable() -export class FinancialModelingPrepService implements DataProviderInterface { +export class FinancialModelingPrepService + implements DataProviderInterface, OnModuleInit +{ private static countriesMapping = { 'Korea (the Republic of)': 'South Korea', 'Russian Federation': 'Russia', @@ -57,7 +59,9 @@ export class FinancialModelingPrepService implements DataProviderInterface { private readonly configurationService: ConfigurationService, private readonly cryptocurrencyService: CryptocurrencyService, private readonly prismaService: PrismaService - ) { + ) {} + + public onModuleInit() { this.apiKey = this.configurationService.get( 'API_KEY_FINANCIAL_MODELING_PREP' ); 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 7392f0914..51e65e631 100644 --- a/apps/api/src/services/data-provider/manual/manual.service.ts +++ b/apps/api/src/services/data-provider/manual/manual.service.ts @@ -105,7 +105,10 @@ export class ManualService implements DataProviderInterface { return {}; } - const value = await this.scrape(symbolProfile.scraperConfiguration); + const value = await this.scrape({ + symbol, + scraperConfiguration: symbolProfile.scraperConfiguration + }); return { [symbol]: { @@ -170,7 +173,10 @@ export class ManualService implements DataProviderInterface { symbolProfilesWithScraperConfigurationAndInstantMode.map( async ({ scraperConfiguration, symbol }) => { try { - const marketPrice = await this.scrape(scraperConfiguration); + const marketPrice = await this.scrape({ + scraperConfiguration, + symbol + }); return { marketPrice, symbol }; } catch (error) { Logger.error( @@ -267,13 +273,23 @@ export class ManualService implements DataProviderInterface { }; } - public async test(scraperConfiguration: ScraperConfiguration) { - return this.scrape(scraperConfiguration); + public async test({ + scraperConfiguration, + symbol + }: { + scraperConfiguration: ScraperConfiguration; + symbol: string; + }) { + return this.scrape({ scraperConfiguration, symbol }); } - private async scrape( - scraperConfiguration: ScraperConfiguration - ): Promise { + private async scrape({ + scraperConfiguration, + symbol + }: { + scraperConfiguration: ScraperConfiguration; + symbol: string; + }): Promise { let locale = scraperConfiguration.locale; const response = await fetch(scraperConfiguration.url, { @@ -283,6 +299,12 @@ export class ManualService implements DataProviderInterface { ) }); + if (!response.ok) { + throw new Error( + `Failed to scrape the market price for ${symbol} (${this.getName()}): ${response.status} ${response.statusText} at ${scraperConfiguration.url}` + ); + } + let value: string; if (response.headers.get('content-type')?.includes('application/json')) { diff --git a/apps/api/src/services/i18n/i18n.service.ts b/apps/api/src/services/i18n/i18n.service.ts index cf340d7c6..1cdb811a9 100644 --- a/apps/api/src/services/i18n/i18n.service.ts +++ b/apps/api/src/services/i18n/i18n.service.ts @@ -1,16 +1,16 @@ import { DEFAULT_LANGUAGE_CODE } from '@ghostfolio/common/config'; -import { Injectable, Logger } from '@nestjs/common'; +import { Injectable, Logger, OnModuleInit } from '@nestjs/common'; import * as cheerio from 'cheerio'; import { readFileSync, readdirSync } from 'node:fs'; import { join } from 'node:path'; @Injectable() -export class I18nService { +export class I18nService implements OnModuleInit { private localesPath = join(__dirname, 'assets', 'locales'); private translations: { [locale: string]: cheerio.CheerioAPI } = {}; - public constructor() { + public onModuleInit() { this.loadFiles(); } diff --git a/apps/api/src/services/interfaces/environment.interface.ts b/apps/api/src/services/interfaces/environment.interface.ts index 57c58898e..9664ae144 100644 --- a/apps/api/src/services/interfaces/environment.interface.ts +++ b/apps/api/src/services/interfaces/environment.interface.ts @@ -10,6 +10,7 @@ export interface Environment extends CleanedEnvAccessors { API_KEY_FINANCIAL_MODELING_PREP: string; API_KEY_OPEN_FIGI: string; API_KEY_RAPID_API: string; + BULL_BOARD_IS_READ_ONLY: boolean; CACHE_QUOTES_TTL: number; CACHE_TTL: number; DATA_SOURCE_EXCHANGE_RATES: string; @@ -19,6 +20,7 @@ export interface Environment extends CleanedEnvAccessors { ENABLE_FEATURE_AUTH_GOOGLE: boolean; ENABLE_FEATURE_AUTH_OIDC: boolean; ENABLE_FEATURE_AUTH_TOKEN: boolean; + ENABLE_FEATURE_BULL_BOARD: boolean; ENABLE_FEATURE_FEAR_AND_GREED_INDEX: boolean; ENABLE_FEATURE_GATHER_NEW_EXCHANGE_RATES: boolean; ENABLE_FEATURE_READ_ONLY_MODE: boolean; diff --git a/apps/api/src/services/queues/data-gathering/data-gathering.module.ts b/apps/api/src/services/queues/data-gathering/data-gathering.module.ts index b51823476..f251c8d0c 100644 --- a/apps/api/src/services/queues/data-gathering/data-gathering.module.ts +++ b/apps/api/src/services/queues/data-gathering/data-gathering.module.ts @@ -9,6 +9,8 @@ import { DataGatheringService } from '@ghostfolio/api/services/queues/data-gathe import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/symbol-profile.module'; import { DATA_GATHERING_QUEUE } from '@ghostfolio/common/config'; +import { BullAdapter } from '@bull-board/api/bullAdapter'; +import { BullBoardModule } from '@bull-board/nestjs'; import { BullModule } from '@nestjs/bull'; import { Module } from '@nestjs/common'; import ms from 'ms'; @@ -17,6 +19,18 @@ import { DataGatheringProcessor } from './data-gathering.processor'; @Module({ imports: [ + ...(process.env.ENABLE_FEATURE_BULL_BOARD === 'true' + ? [ + BullBoardModule.forFeature({ + adapter: BullAdapter, + name: DATA_GATHERING_QUEUE, + options: { + displayName: 'Data Gathering', + readOnlyMode: process.env.BULL_BOARD_IS_READ_ONLY !== 'false' + } + }) + ] + : []), BullModule.registerQueue({ limiter: { duration: ms('4 seconds'), 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 index 958636334..1260f1cf0 100644 --- a/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.module.ts +++ b/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.module.ts @@ -1,5 +1,5 @@ import { AccountBalanceModule } from '@ghostfolio/api/app/account-balance/account-balance.module'; -import { OrderModule } from '@ghostfolio/api/app/order/order.module'; +import { ActivitiesModule } from '@ghostfolio/api/app/activities/activities.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'; @@ -13,6 +13,8 @@ import { PORTFOLIO_SNAPSHOT_COMPUTATION_QUEUE } from '@ghostfolio/common/config'; +import { BullAdapter } from '@bull-board/api/bullAdapter'; +import { BullBoardModule } from '@bull-board/nestjs'; import { BullModule } from '@nestjs/bull'; import { Module } from '@nestjs/common'; @@ -22,6 +24,19 @@ import { PortfolioSnapshotProcessor } from './portfolio-snapshot.processor'; exports: [BullModule, PortfolioSnapshotService], imports: [ AccountBalanceModule, + ActivitiesModule, + ...(process.env.ENABLE_FEATURE_BULL_BOARD === 'true' + ? [ + BullBoardModule.forFeature({ + adapter: BullAdapter, + name: PORTFOLIO_SNAPSHOT_COMPUTATION_QUEUE, + options: { + displayName: 'Portfolio Snapshot Computation', + readOnlyMode: process.env.BULL_BOARD_IS_READ_ONLY !== 'false' + } + }) + ] + : []), BullModule.registerQueue({ name: PORTFOLIO_SNAPSHOT_COMPUTATION_QUEUE, settings: { @@ -36,7 +51,6 @@ import { PortfolioSnapshotProcessor } from './portfolio-snapshot.processor'; DataProviderModule, ExchangeRateDataModule, MarketDataModule, - OrderModule, RedisCacheModule ], providers: [ 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 58a0a8f8a..f3aa6e77e 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 @@ -1,5 +1,5 @@ import { AccountBalanceService } from '@ghostfolio/api/app/account-balance/account-balance.service'; -import { OrderService } from '@ghostfolio/api/app/order/order.service'; +import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.service'; import { 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'; @@ -23,9 +23,9 @@ import { PortfolioSnapshotQueueJob } from './interfaces/portfolio-snapshot-queue export class PortfolioSnapshotProcessor { public constructor( private readonly accountBalanceService: AccountBalanceService, + private readonly activitiesService: ActivitiesService, private readonly calculatorFactory: PortfolioCalculatorFactory, private readonly configurationService: ConfigurationService, - private readonly orderService: OrderService, private readonly redisCacheService: RedisCacheService ) {} @@ -47,7 +47,7 @@ export class PortfolioSnapshotProcessor { ); const { activities } = - await this.orderService.getOrdersForPortfolioCalculator({ + await this.activitiesService.getActivitiesForPortfolioCalculator({ filters: job.data.filters, userCurrency: job.data.userCurrency, userId: job.data.userId, diff --git a/apps/api/src/services/twitter-bot/twitter-bot.service.ts b/apps/api/src/services/twitter-bot/twitter-bot.service.ts index ee951820d..b424f7198 100644 --- a/apps/api/src/services/twitter-bot/twitter-bot.service.ts +++ b/apps/api/src/services/twitter-bot/twitter-bot.service.ts @@ -10,19 +10,21 @@ import { resolveMarketCondition } from '@ghostfolio/common/helper'; -import { Injectable, Logger } from '@nestjs/common'; +import { Injectable, Logger, OnModuleInit } from '@nestjs/common'; import { isWeekend } from 'date-fns'; import { TwitterApi, TwitterApiReadWrite } from 'twitter-api-v2'; @Injectable() -export class TwitterBotService { +export class TwitterBotService implements OnModuleInit { private twitterClient: TwitterApiReadWrite; public constructor( private readonly benchmarkService: BenchmarkService, private readonly configurationService: ConfigurationService, private readonly symbolService: SymbolService - ) { + ) {} + + public onModuleInit() { this.twitterClient = new TwitterApi({ accessSecret: this.configurationService.get( 'TWITTER_ACCESS_TOKEN_SECRET' diff --git a/apps/client/proxy.conf.json b/apps/client/proxy.conf.json index a31371d9f..825965b92 100644 --- a/apps/client/proxy.conf.json +++ b/apps/client/proxy.conf.json @@ -1,4 +1,8 @@ { + "/admin/queues": { + "target": "http://0.0.0.0:3333", + "secure": false + }, "/api": { "target": "http://0.0.0.0:3333", "secure": false diff --git a/apps/client/src/app/app.component.ts b/apps/client/src/app/app.component.ts index a4af01124..201c2f994 100644 --- a/apps/client/src/app/app.component.ts +++ b/apps/client/src/app/app.component.ts @@ -10,12 +10,13 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, + DestroyRef, DOCUMENT, HostBinding, - Inject, - OnDestroy, + inject, OnInit } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatDialog } from '@angular/material/dialog'; import { Title } from '@angular/platform-browser'; import { @@ -30,15 +31,13 @@ import { DataSource } from '@prisma/client'; import { addIcons } from 'ionicons'; import { openOutline } from 'ionicons/icons'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject } from 'rxjs'; -import { filter, takeUntil } from 'rxjs/operators'; +import { filter } from 'rxjs/operators'; import { GfFooterComponent } from './components/footer/footer.component'; import { GfHeaderComponent } from './components/header/header.component'; import { GfHoldingDetailDialogComponent } from './components/holding-detail-dialog/holding-detail-dialog.component'; -import { HoldingDetailDialogParams } from './components/holding-detail-dialog/interfaces/interfaces'; +import { GfAppQueryParams } from './interfaces/interfaces'; import { ImpersonationStorageService } from './services/impersonation-storage.service'; -import { TokenStorageService } from './services/token-storage.service'; import { UserService } from './services/user/user.service'; @Component({ @@ -48,11 +47,7 @@ import { UserService } from './services/user/user.service'; styleUrls: ['./app.component.scss'], templateUrl: './app.component.html' }) -export class GfAppComponent implements OnDestroy, OnInit { - @HostBinding('class.has-info-message') get getHasMessage() { - return this.hasInfoMessage; - } - +export class GfAppComponent implements OnInit { public canCreateAccount: boolean; public currentRoute: string; public currentSubRoute: string; @@ -67,52 +62,54 @@ export class GfAppComponent implements OnDestroy, OnInit { public pageTitle: string; public routerLinkRegister = publicRoutes.register.routerLink; public showFooter = false; - public user: User; - - private unsubscribeSubject = new Subject(); - - public constructor( - private changeDetectorRef: ChangeDetectorRef, - private dataService: DataService, - private deviceService: DeviceDetectorService, - private dialog: MatDialog, - @Inject(DOCUMENT) private document: Document, - private impersonationStorageService: ImpersonationStorageService, - private notificationService: NotificationService, - private route: ActivatedRoute, - private router: Router, - private title: Title, - private tokenStorageService: TokenStorageService, - private userService: UserService - ) { + public user: User | undefined; + + private readonly changeDetectorRef = inject(ChangeDetectorRef); + private readonly dataService = inject(DataService); + private readonly destroyRef = inject(DestroyRef); + private readonly deviceService = inject(DeviceDetectorService); + private readonly dialog = inject(MatDialog); + private readonly document = inject(DOCUMENT); + private readonly impersonationStorageService = inject( + ImpersonationStorageService + ); + private readonly notificationService = inject(NotificationService); + private readonly route = inject(ActivatedRoute); + private readonly router = inject(Router); + private readonly title = inject(Title); + private readonly userService = inject(UserService); + + public constructor() { this.initializeTheme(); this.user = undefined; this.route.queryParams - .pipe(takeUntil(this.unsubscribeSubject)) - .subscribe((params) => { - if ( - params['dataSource'] && - params['holdingDetailDialog'] && - params['symbol'] - ) { - this.openHoldingDetailDialog({ - dataSource: params['dataSource'], - symbol: params['symbol'] - }); + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe( + ({ dataSource, holdingDetailDialog, symbol }: GfAppQueryParams) => { + if (dataSource && holdingDetailDialog && symbol) { + this.openHoldingDetailDialog({ + dataSource, + symbol + }); + } } - }); + ); addIcons({ openOutline }); } + @HostBinding('class.has-info-message') get getHasMessage() { + return this.hasInfoMessage; + } + public ngOnInit() { this.deviceType = this.deviceService.getDeviceInfo().deviceType; this.info = this.dataService.fetchInfo(); this.impersonationStorageService .onChangeHasImpersonation() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((impersonationId) => { this.hasImpersonationId = !!impersonationId; }); @@ -131,7 +128,7 @@ export class GfAppComponent implements OnDestroy, OnInit { !this.currentSubRoute) || (this.currentRoute === internalRoutes.home.path && this.currentSubRoute === - internalRoutes.home.subRoutes.holdings.path) || + internalRoutes.home.subRoutes?.holdings.path) || (this.currentRoute === internalRoutes.portfolio.path && !this.currentSubRoute)) && this.user?.settings?.viewMode !== 'ZEN' @@ -144,18 +141,18 @@ export class GfAppComponent implements OnDestroy, OnInit { if ( (this.currentRoute === internalRoutes.home.path && this.currentSubRoute === - internalRoutes.home.subRoutes.holdings.path) || + internalRoutes.home.subRoutes?.holdings.path) || (this.currentRoute === internalRoutes.portfolio.path && !this.currentSubRoute) || (this.currentRoute === internalRoutes.portfolio.path && this.currentSubRoute === - internalRoutes.portfolio.subRoutes.activities.path) || + internalRoutes.portfolio.subRoutes?.activities.path) || (this.currentRoute === internalRoutes.portfolio.path && this.currentSubRoute === - internalRoutes.portfolio.subRoutes.allocations.path) || + internalRoutes.portfolio.subRoutes?.allocations.path) || (this.currentRoute === internalRoutes.zen.path && this.currentSubRoute === - internalRoutes.home.subRoutes.holdings.path) + internalRoutes.home.subRoutes?.holdings.path) ) { this.hasPermissionToChangeFilters = true; } else { @@ -201,7 +198,7 @@ export class GfAppComponent implements OnDestroy, OnInit { }); this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { this.user = state.user; @@ -226,31 +223,31 @@ export class GfAppComponent implements OnDestroy, OnInit { } public onClickSystemMessage() { - if (this.user.systemMessage.routerLink) { - this.router.navigate(this.user.systemMessage.routerLink); + const systemMessage = this.user?.systemMessage; + + if (!systemMessage) { + return; + } + + if (systemMessage.routerLink) { + void this.router.navigate(systemMessage.routerLink); } else { this.notificationService.alert({ - title: this.user.systemMessage.message + title: systemMessage.message }); } } public onCreateAccount() { - this.tokenStorageService.signOut(); + this.userService.signOut(); } public onSignOut() { - this.tokenStorageService.signOut(); - this.userService.remove(); + this.userService.signOut(); document.location.href = `/${document.documentElement.lang}`; } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private initializeTheme(userPreferredColorScheme?: ColorScheme) { const isDarkTheme = userPreferredColorScheme ? userPreferredColorScheme === 'DARK' @@ -274,14 +271,11 @@ export class GfAppComponent implements OnDestroy, OnInit { }) { this.userService .get() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((user) => { this.user = user; - const dialogRef = this.dialog.open< - GfHoldingDetailDialogComponent, - HoldingDetailDialogParams - >(GfHoldingDetailDialogComponent, { + const dialogRef = this.dialog.open(GfHoldingDetailDialogComponent, { autoFocus: false, data: { dataSource, @@ -296,15 +290,21 @@ export class GfAppComponent implements OnDestroy, OnInit { ), hasPermissionToCreateActivity: !this.hasImpersonationId && - hasPermission(this.user?.permissions, permissions.createOrder) && + hasPermission( + this.user?.permissions, + permissions.createActivity + ) && !this.user?.settings?.isRestrictedView, hasPermissionToReportDataGlitch: hasPermission( this.user?.permissions, permissions.reportDataGlitch ), - hasPermissionToUpdateOrder: + hasPermissionToUpdateActivity: !this.hasImpersonationId && - hasPermission(this.user?.permissions, permissions.updateOrder) && + hasPermission( + this.user?.permissions, + permissions.updateActivity + ) && !this.user?.settings?.isRestrictedView, locale: this.user?.settings?.locale }, @@ -314,9 +314,9 @@ export class GfAppComponent implements OnDestroy, OnInit { dialogRef .afterClosed() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { - this.router.navigate([], { + void this.router.navigate([], { queryParams: { dataSource: null, holdingDetailDialog: null, @@ -342,6 +342,6 @@ export class GfAppComponent implements OnDestroy, OnInit { this.document .querySelector('meta[name="theme-color"]') - .setAttribute('content', themeColor); + ?.setAttribute('content', themeColor); } } 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 cb41904d3..4283d7860 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,7 +39,7 @@ getPublicUrl(element.id) }}
- @if (user?.settings?.isExperimentalFeatures) { + @if (user()?.settings?.isExperimentalFeatures) {
GET {{ baseUrl }}/api/v1/public/{{ @@ -69,7 +69,7 @@ class="no-max-width" xPosition="before" > - @if (user?.settings?.isExperimentalFeatures) { + @if (user()?.settings?.isExperimentalFeatures) { } @if ( - user?.settings?.isExperimentalFeatures || element.type === 'PUBLIC' + user()?.settings?.isExperimentalFeatures || + element.type === 'PUBLIC' ) {
} @@ -100,7 +101,7 @@ - - + +
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 76548c45d..122b4f88b 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 @@ -7,11 +7,12 @@ import { Clipboard, ClipboardModule } from '@angular/cdk/clipboard'; import { ChangeDetectionStrategy, Component, + computed, CUSTOM_ELEMENTS_SCHEMA, - EventEmitter, - Input, - OnChanges, - Output + effect, + inject, + input, + output } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MatMenuModule } from '@angular/material/menu'; @@ -46,23 +47,32 @@ import ms from 'ms'; templateUrl: './access-table.component.html', styleUrls: ['./access-table.component.scss'] }) -export class GfAccessTableComponent implements OnChanges { - @Input() accesses: Access[]; - @Input() showActions: boolean; - @Input() user: User; - - @Output() accessDeleted = new EventEmitter(); - @Output() accessToUpdate = new EventEmitter(); - - public baseUrl = window.location.origin; - public dataSource: MatTableDataSource; - public displayedColumns = []; - - public constructor( - private clipboard: Clipboard, - private notificationService: NotificationService, - private snackBar: MatSnackBar - ) { +export class GfAccessTableComponent { + public readonly accesses = input.required(); + public readonly showActions = input(false); + public readonly user = input.required(); + + public readonly accessDeleted = output(); + public readonly accessToUpdate = output(); + + protected readonly baseUrl = window.location.origin; + protected readonly dataSource = new MatTableDataSource(); + + protected readonly displayedColumns = computed(() => { + const columns = ['alias', 'grantee', 'type', 'details']; + + if (this.showActions()) { + columns.push('actions'); + } + + return columns; + }); + + private readonly clipboard = inject(Clipboard); + private readonly notificationService = inject(NotificationService); + private readonly snackBar = inject(MatSnackBar); + + public constructor() { addIcons({ copyOutline, createOutline, @@ -72,27 +82,19 @@ export class GfAccessTableComponent implements OnChanges { lockOpenOutline, removeCircleOutline }); - } - public ngOnChanges() { - this.displayedColumns = ['alias', 'grantee', 'type', 'details']; - - if (this.showActions) { - this.displayedColumns.push('actions'); - } - - if (this.accesses) { - this.dataSource = new MatTableDataSource(this.accesses); - } + effect(() => { + this.dataSource.data = this.accesses() ?? []; + }); } - public getPublicUrl(aId: string): string { - const languageCode = this.user.settings.language; + protected getPublicUrl(aId: string) { + const languageCode = this.user().settings.language; return `${this.baseUrl}/${languageCode}/${publicRoutes.public.path}/${aId}`; } - public onCopyUrlToClipboard(aId: string): void { + protected onCopyUrlToClipboard(aId: string) { this.clipboard.copy(this.getPublicUrl(aId)); this.snackBar.open( @@ -104,7 +106,7 @@ export class GfAccessTableComponent implements OnChanges { ); } - public onDeleteAccess(aId: string) { + protected onDeleteAccess(aId: string) { this.notificationService.confirm({ confirmFn: () => { this.accessDeleted.emit(aId); @@ -114,7 +116,7 @@ export class GfAccessTableComponent implements OnChanges { }); } - public onUpdateAccess(aId: string) { + protected onUpdateAccess(aId: string) { this.accessToUpdate.emit(aId); } } diff --git a/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.component.ts b/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.component.ts index 380fb69cb..7a3040391 100644 --- a/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.component.ts +++ b/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.component.ts @@ -26,11 +26,12 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, + DestroyRef, Inject, - OnDestroy, OnInit } from '@angular/core'; import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatButtonModule } from '@angular/material/button'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { MatDialogModule } from '@angular/material/dialog'; @@ -49,8 +50,7 @@ import { } from 'ionicons/icons'; import { isNumber } from 'lodash'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; -import { forkJoin, Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; +import { forkJoin } from 'rxjs'; import { AccountDetailDialogParams } from './interfaces/interfaces'; @@ -77,7 +77,7 @@ import { AccountDetailDialogParams } from './interfaces/interfaces'; styleUrls: ['./account-detail-dialog.component.scss'], templateUrl: 'account-detail-dialog.html' }) -export class GfAccountDetailDialogComponent implements OnDestroy, OnInit { +export class GfAccountDetailDialogComponent implements OnInit { public accountBalances: AccountBalancesResponse['balances']; public activities: OrderWithAccount[]; public activitiesCount: number; @@ -104,18 +104,17 @@ export class GfAccountDetailDialogComponent implements OnDestroy, OnInit { public user: User; public valueInBaseCurrency: number; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, @Inject(MAT_DIALOG_DATA) public data: AccountDetailDialogParams, private dataService: DataService, + private destroyRef: DestroyRef, public dialogRef: MatDialogRef, private router: Router, private userService: UserService ) { this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -154,7 +153,7 @@ export class GfAccountDetailDialogComponent implements OnDestroy, OnInit { public onAddAccountBalance(accountBalance: CreateAccountBalanceDto) { this.dataService .postAccountBalance(accountBalance) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.initialize(); }); @@ -163,7 +162,7 @@ export class GfAccountDetailDialogComponent implements OnDestroy, OnInit { public onDeleteAccountBalance(aId: string) { this.dataService .deleteAccountBalance(aId) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.initialize(); }); @@ -176,7 +175,7 @@ export class GfAccountDetailDialogComponent implements OnDestroy, OnInit { this.dataService .fetchExport({ activityIds }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((data) => { downloadAsFile({ content: data, @@ -212,7 +211,7 @@ export class GfAccountDetailDialogComponent implements OnDestroy, OnInit { private fetchAccount() { this.dataService .fetchAccount(this.data.accountId) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe( ({ activitiesCount, @@ -287,7 +286,7 @@ export class GfAccountDetailDialogComponent implements OnDestroy, OnInit { sortColumn: this.sortColumn, sortDirection: this.sortDirection }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ activities, count }) => { this.dataSource = new MatTableDataSource(activities); this.totalItems = count; @@ -304,7 +303,7 @@ export class GfAccountDetailDialogComponent implements OnDestroy, OnInit { forkJoin({ accountBalances: this.dataService .fetchAccountBalances(this.data.accountId) - .pipe(takeUntil(this.unsubscribeSubject)), + .pipe(takeUntilDestroyed(this.destroyRef)), portfolioPerformance: this.dataService .fetchPortfolioPerformance({ filters: [ @@ -317,7 +316,7 @@ export class GfAccountDetailDialogComponent implements OnDestroy, OnInit { withExcludedAccounts: true, withItems: true }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) }).subscribe({ error: () => { this.isLoadingChart = false; @@ -360,7 +359,7 @@ export class GfAccountDetailDialogComponent implements OnDestroy, OnInit { } ] }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ holdings }) => { this.holdings = holdings; @@ -374,9 +373,4 @@ export class GfAccountDetailDialogComponent implements OnDestroy, OnInit { this.fetchChart(); this.fetchPortfolioHoldings(); } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } 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 de70a7b6e..b9f4d590d 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 @@ -1,5 +1,8 @@ +import { TokenStorageService } from '@ghostfolio/client/services/token-storage.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { + BULL_BOARD_COOKIE_NAME, + BULL_BOARD_ROUTE, DATA_GATHERING_QUEUE_PRIORITY_HIGH, DATA_GATHERING_QUEUE_PRIORITY_LOW, DATA_GATHERING_QUEUE_PRIORITY_MEDIUM, @@ -7,6 +10,7 @@ import { } from '@ghostfolio/common/config'; import { getDateWithTimeFormatString } from '@ghostfolio/common/helper'; import { AdminJobs, User } from '@ghostfolio/common/interfaces'; +import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { NotificationService } from '@ghostfolio/ui/notifications'; import { AdminService } from '@ghostfolio/ui/services'; @@ -15,10 +19,11 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, - OnDestroy, + DestroyRef, OnInit, ViewChild } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { FormBuilder, FormGroup, @@ -41,6 +46,7 @@ import { chevronUpCircleOutline, ellipsisHorizontal, ellipsisVertical, + openOutline, pauseOutline, playOutline, removeCircleOutline, @@ -48,8 +54,6 @@ import { } from 'ionicons/icons'; import { get } from 'lodash'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, @@ -69,7 +73,7 @@ import { takeUntil } from 'rxjs/operators'; styleUrls: ['./admin-jobs.scss'], templateUrl: './admin-jobs.html' }) -export class GfAdminJobsComponent implements OnDestroy, OnInit { +export class GfAdminJobsComponent implements OnInit { @ViewChild(MatSort) sort: MatSort; public DATA_GATHERING_QUEUE_PRIORITY_LOW = DATA_GATHERING_QUEUE_PRIORITY_LOW; @@ -81,6 +85,7 @@ export class GfAdminJobsComponent implements OnDestroy, OnInit { public dataSource = new MatTableDataSource(); public defaultDateTimeFormat: string; public filterForm: FormGroup; + public displayedColumns = [ 'index', 'type', @@ -93,21 +98,24 @@ export class GfAdminJobsComponent implements OnDestroy, OnInit { 'status', 'actions' ]; + + public hasPermissionToAccessBullBoard = false; public isLoading = false; public statusFilterOptions = QUEUE_JOB_STATUS_LIST; - public user: User; - private unsubscribeSubject = new Subject(); + private user: User; public constructor( private adminService: AdminService, private changeDetectorRef: ChangeDetectorRef, + private destroyRef: DestroyRef, private formBuilder: FormBuilder, private notificationService: NotificationService, + private tokenStorageService: TokenStorageService, private userService: UserService ) { this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -115,6 +123,11 @@ export class GfAdminJobsComponent implements OnDestroy, OnInit { this.defaultDateTimeFormat = getDateWithTimeFormatString( this.user.settings.locale ); + + this.hasPermissionToAccessBullBoard = hasPermission( + this.user.permissions, + permissions.accessAdminControlBullBoard + ); } }); @@ -126,6 +139,7 @@ export class GfAdminJobsComponent implements OnDestroy, OnInit { chevronUpCircleOutline, ellipsisHorizontal, ellipsisVertical, + openOutline, pauseOutline, playOutline, removeCircleOutline, @@ -139,7 +153,7 @@ export class GfAdminJobsComponent implements OnDestroy, OnInit { }); this.filterForm.valueChanges - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { const currentFilter = this.filterForm.get('status').value; this.fetchJobs(currentFilter ? [currentFilter] : undefined); @@ -151,7 +165,7 @@ export class GfAdminJobsComponent implements OnDestroy, OnInit { public onDeleteJob(aId: string) { this.adminService .deleteJob(aId) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.fetchJobs(); }); @@ -162,7 +176,7 @@ export class GfAdminJobsComponent implements OnDestroy, OnInit { this.adminService .deleteJobs({ status: currentFilter ? [currentFilter] : undefined }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.fetchJobs(currentFilter ? [currentFilter] : undefined); }); @@ -171,12 +185,24 @@ export class GfAdminJobsComponent implements OnDestroy, OnInit { public onExecuteJob(aId: string) { this.adminService .executeJob(aId) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.fetchJobs(); }); } + public onOpenBullBoard() { + const token = this.tokenStorageService.getToken(); + + document.cookie = [ + `${BULL_BOARD_COOKIE_NAME}=${encodeURIComponent(token)}`, + 'path=/', + 'SameSite=Strict' + ].join('; '); + + window.open(BULL_BOARD_ROUTE, '_blank'); + } + public onViewData(aData: AdminJobs['jobs'][0]['data']) { this.notificationService.alert({ title: JSON.stringify(aData, null, ' ') @@ -189,17 +215,12 @@ export class GfAdminJobsComponent implements OnDestroy, OnInit { }); } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private fetchJobs(aStatus?: JobStatus[]) { this.isLoading = true; this.adminService .fetchJobs({ status: aStatus }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ jobs }) => { this.dataSource = new MatTableDataSource(jobs); this.dataSource.sort = this.sort; 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 a82294001..cff80498c 100644 --- a/apps/client/src/app/components/admin-jobs/admin-jobs.html +++ b/apps/client/src/app/components/admin-jobs/admin-jobs.html @@ -1,6 +1,15 @@
+ @if (hasPermissionToAccessBullBoard) { +
+ +
+ } +
diff --git a/apps/client/src/app/components/admin-market-data/admin-market-data.component.ts b/apps/client/src/app/components/admin-market-data/admin-market-data.component.ts index 8f956b782..d3265946f 100644 --- a/apps/client/src/app/components/admin-market-data/admin-market-data.component.ts +++ b/apps/client/src/app/components/admin-market-data/admin-market-data.component.ts @@ -26,10 +26,11 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, - OnDestroy, + DestroyRef, OnInit, ViewChild } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatButtonModule } from '@angular/material/button'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatDialog } from '@angular/material/dialog'; @@ -63,7 +64,7 @@ import { import { DeviceDetectorService } from 'ngx-device-detector'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; import { Subject } from 'rxjs'; -import { distinctUntilChanged, takeUntil } from 'rxjs/operators'; +import { distinctUntilChanged } from 'rxjs/operators'; import { AdminMarketDataService } from './admin-market-data.service'; import { GfAssetProfileDialogComponent } from './asset-profile-dialog/asset-profile-dialog.component'; @@ -95,9 +96,7 @@ import { CreateAssetProfileDialogParams } from './create-asset-profile-dialog/in styleUrls: ['./admin-market-data.scss'], templateUrl: './admin-market-data.html' }) -export class GfAdminMarketDataComponent - implements AfterViewInit, OnDestroy, OnInit -{ +export class GfAdminMarketDataComponent implements AfterViewInit, OnInit { @ViewChild(MatPaginator) paginator: MatPaginator; @ViewChild(MatSort) sort: MatSort; @@ -140,6 +139,11 @@ export class GfAdminMarketDataComponent id: 'ETF_WITHOUT_SECTORS', label: $localize`ETFs without Sectors`, type: 'PRESET_ID' as Filter['type'] + }, + { + id: 'NO_ACTIVITIES', + label: $localize`No Activities`, + type: 'PRESET_ID' as Filter['type'] } ]; public benchmarks: Partial[]; @@ -161,13 +165,12 @@ export class GfAdminMarketDataComponent public totalItems = 0; public user: User; - private unsubscribeSubject = new Subject(); - public constructor( public adminMarketDataService: AdminMarketDataService, private adminService: AdminService, private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private dialog: MatDialog, private route: ActivatedRoute, @@ -204,7 +207,7 @@ export class GfAdminMarketDataComponent this.displayedColumns.push('actions'); this.route.queryParams - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((params) => { if ( params['assetProfileDialog'] && @@ -221,7 +224,7 @@ export class GfAdminMarketDataComponent }); this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -233,7 +236,7 @@ export class GfAdminMarketDataComponent }); this.filters$ - .pipe(distinctUntilChanged(), takeUntil(this.unsubscribeSubject)) + .pipe(distinctUntilChanged(), takeUntilDestroyed(this.destroyRef)) .subscribe((filters) => { this.activeFilters = filters; @@ -297,7 +300,7 @@ export class GfAdminMarketDataComponent public onGather7Days() { this.adminService .gather7Days() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { setTimeout(() => { window.location.reload(); @@ -308,7 +311,7 @@ export class GfAdminMarketDataComponent public onGatherMax() { this.adminService .gatherMax() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { setTimeout(() => { window.location.reload(); @@ -319,7 +322,7 @@ export class GfAdminMarketDataComponent public onGatherProfileData() { this.adminService .gatherProfileData() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); } @@ -329,14 +332,14 @@ export class GfAdminMarketDataComponent }: AssetProfileIdentifier) { this.adminService .gatherProfileDataBySymbol({ dataSource, symbol }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); } public onGatherSymbol({ dataSource, symbol }: AssetProfileIdentifier) { this.adminService .gatherSymbol({ dataSource, symbol }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); } @@ -353,11 +356,6 @@ export class GfAdminMarketDataComponent }); } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private loadData( { pageIndex, @@ -374,7 +372,7 @@ export class GfAdminMarketDataComponent this.pageSize = this.activeFilters.length === 1 && this.activeFilters[0].type === 'PRESET_ID' - ? undefined + ? Number.MAX_SAFE_INTEGER : DEFAULT_PAGE_SIZE; if (pageIndex === 0 && this.paginator) { @@ -394,7 +392,7 @@ export class GfAdminMarketDataComponent skip: pageIndex * this.pageSize, take: this.pageSize }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ count, marketData }) => { this.totalItems = count; @@ -425,7 +423,7 @@ export class GfAdminMarketDataComponent }) { this.userService .get() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((user) => { this.user = user; @@ -447,7 +445,7 @@ export class GfAdminMarketDataComponent dialogRef .afterClosed() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe( (newAssetProfileIdentifier: AssetProfileIdentifier | undefined) => { if (newAssetProfileIdentifier) { @@ -463,7 +461,7 @@ export class GfAdminMarketDataComponent private openCreateAssetProfileDialog() { this.userService .get() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((user) => { this.user = user; @@ -481,7 +479,7 @@ export class GfAdminMarketDataComponent dialogRef .afterClosed() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((result) => { if (!result) { this.router.navigate(['.'], { relativeTo: this.route }); @@ -494,7 +492,7 @@ export class GfAdminMarketDataComponent if (addAssetProfile && dataSource && symbol) { this.adminService .addAssetProfile({ dataSource, symbol }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.loadData(); }); diff --git a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts index cbd8deba3..c0af46e22 100644 --- a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts +++ b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts @@ -5,7 +5,11 @@ import { PROPERTY_IS_DATA_GATHERING_ENABLED } from '@ghostfolio/common/config'; import { UpdateAssetProfileDto } from '@ghostfolio/common/dtos'; -import { DATE_FORMAT } from '@ghostfolio/common/helper'; +import { + DATE_FORMAT, + getCurrencyFromSymbol, + isCurrency +} from '@ghostfolio/common/helper'; import { AdminMarketDataDetails, AssetClassSelectorOption, @@ -33,12 +37,13 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, + DestroyRef, ElementRef, Inject, - OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { AbstractControl, FormBuilder, @@ -83,8 +88,8 @@ import { serverOutline } from 'ionicons/icons'; import ms from 'ms'; -import { EMPTY, Subject } from 'rxjs'; -import { catchError, takeUntil } from 'rxjs/operators'; +import { EMPTY } from 'rxjs'; +import { catchError } from 'rxjs/operators'; import { AssetProfileDialogParams } from './interfaces/interfaces'; @@ -117,7 +122,7 @@ import { AssetProfileDialogParams } from './interfaces/interfaces'; styleUrls: ['./asset-profile-dialog.component.scss'], templateUrl: 'asset-profile-dialog.html' }) -export class GfAssetProfileDialogComponent implements OnDestroy, OnInit { +export class GfAssetProfileDialogComponent implements OnInit { private static readonly HISTORICAL_DATA_TEMPLATE = `date;marketPrice\n${format( new Date(), DATE_FORMAT @@ -138,7 +143,6 @@ export class GfAssetProfileDialogComponent implements OnDestroy, OnInit { }); public assetSubClassOptions: AssetClassSelectorOption[] = []; - public assetProfile: AdminMarketDataDetails['assetProfile']; public assetProfileForm = this.formBuilder.group({ @@ -180,12 +184,14 @@ export class GfAssetProfileDialogComponent implements OnDestroy, OnInit { ); public benchmarks: Partial[]; + public canEditAssetProfile = true; public countries: { [code: string]: { name: string; value: number }; }; public currencies: string[] = []; + public dateRangeOptions = [ { label: $localize`Current week` + ' (' + $localize`WTD` + ')', @@ -236,14 +242,13 @@ export class GfAssetProfileDialogComponent implements OnDestroy, OnInit { public user: User; - private unsubscribeSubject = new Subject(); - public constructor( public adminMarketDataService: AdminMarketDataService, private adminService: AdminService, private changeDetectorRef: ChangeDetectorRef, @Inject(MAT_DIALOG_DATA) public data: AssetProfileDialogParams, private dataService: DataService, + private destroyRef: DestroyRef, public dialogRef: MatDialogRef, private formBuilder: FormBuilder, private notificationService: NotificationService, @@ -260,7 +265,7 @@ export class GfAssetProfileDialogComponent implements OnDestroy, OnInit { } public get canSaveAssetProfileIdentifier() { - return !this.assetProfileForm.dirty; + return !this.assetProfileForm.dirty && this.canEditAssetProfile; } public ngOnInit() { @@ -277,7 +282,7 @@ export class GfAssetProfileDialogComponent implements OnDestroy, OnInit { this.adminService .fetchAdminData() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ settings }) => { this.isDataGatheringEnabled = settings[PROPERTY_IS_DATA_GATHERING_ENABLED] === false ? false : true; @@ -286,7 +291,7 @@ export class GfAssetProfileDialogComponent implements OnDestroy, OnInit { }); this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -295,7 +300,7 @@ export class GfAssetProfileDialogComponent implements OnDestroy, OnInit { this.assetProfileForm .get('assetClass') - .valueChanges.pipe(takeUntil(this.unsubscribeSubject)) + .valueChanges.pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((assetClass) => { const assetSubClasses = ASSET_CLASS_MAPPING.get(assetClass) ?? []; @@ -318,12 +323,17 @@ export class GfAssetProfileDialogComponent implements OnDestroy, OnInit { dataSource: this.data.dataSource, symbol: this.data.symbol }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ assetProfile, marketData }) => { this.assetProfile = assetProfile; this.assetClassLabel = translate(this.assetProfile?.assetClass); this.assetSubClassLabel = translate(this.assetProfile?.assetSubClass); + + this.canEditAssetProfile = !isCurrency( + getCurrencyFromSymbol(this.data.symbol) + ); + this.countries = {}; this.isBenchmark = this.benchmarks.some(({ id }) => { @@ -390,6 +400,10 @@ export class GfAssetProfileDialogComponent implements OnDestroy, OnInit { url: this.assetProfile?.url ?? '' }); + if (!this.canEditAssetProfile) { + this.assetProfileForm.disable(); + } + this.assetProfileForm.markAsPristine(); this.changeDetectorRef.markForCheck(); @@ -399,7 +413,9 @@ export class GfAssetProfileDialogComponent implements OnDestroy, OnInit { public onCancelEditAssetProfileIdentifierMode() { this.isEditAssetProfileIdentifierMode = false; - this.assetProfileForm.enable(); + if (this.canEditAssetProfile) { + this.assetProfileForm.enable(); + } this.assetProfileIdentifierForm.reset(); } @@ -420,7 +436,7 @@ export class GfAssetProfileDialogComponent implements OnDestroy, OnInit { }: AssetProfileIdentifier) { this.adminService .gatherProfileDataBySymbol({ dataSource, symbol }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); } @@ -433,7 +449,7 @@ export class GfAssetProfileDialogComponent implements OnDestroy, OnInit { } & AssetProfileIdentifier) { this.adminService .gatherSymbol({ dataSource, range, symbol }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); } @@ -446,7 +462,7 @@ export class GfAssetProfileDialogComponent implements OnDestroy, OnInit { public onSetBenchmark({ dataSource, symbol }: AssetProfileIdentifier) { this.dataService .postBenchmark({ dataSource, symbol }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.dataService.updateInfo(); @@ -648,7 +664,7 @@ export class GfAssetProfileDialogComponent implements OnDestroy, OnInit { return EMPTY; }), - takeUntil(this.unsubscribeSubject) + takeUntilDestroyed(this.destroyRef) ) .subscribe(() => { const newAssetProfileIdentifier = { @@ -698,7 +714,7 @@ export class GfAssetProfileDialogComponent implements OnDestroy, OnInit { }); return EMPTY; }), - takeUntil(this.unsubscribeSubject) + takeUntilDestroyed(this.destroyRef) ) .subscribe(({ price }) => { this.notificationService.alert({ @@ -729,7 +745,7 @@ export class GfAssetProfileDialogComponent implements OnDestroy, OnInit { public onUnsetBenchmark({ dataSource, symbol }: AssetProfileIdentifier) { this.dataService .deleteBenchmark({ dataSource, symbol }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.dataService.updateInfo(); @@ -739,11 +755,6 @@ export class GfAssetProfileDialogComponent implements OnDestroy, OnInit { }); } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - public onTriggerSubmitAssetProfileForm() { if (this.assetProfileForm.valid) { this.onSubmitAssetProfileForm(); diff --git a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html index a60e10edc..6b3141bfe 100644 --- a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html +++ b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -300,6 +300,7 @@
Data Gathering diff --git a/apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.component.ts b/apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.component.ts index fbf8afa03..35887abb4 100644 --- a/apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.component.ts +++ b/apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.component.ts @@ -10,9 +10,10 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, - OnDestroy, + DestroyRef, OnInit } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { AbstractControl, FormBuilder, @@ -31,7 +32,7 @@ import { MatInputModule } from '@angular/material/input'; import { MatRadioModule } from '@angular/material/radio'; import { DataSource } from '@prisma/client'; import { isISO4217CurrencyCode } from 'class-validator'; -import { Subject, switchMap, takeUntil } from 'rxjs'; +import { switchMap } from 'rxjs'; import { CreateAssetProfileDialogMode } from './interfaces/interfaces'; @@ -52,19 +53,19 @@ import { CreateAssetProfileDialogMode } from './interfaces/interfaces'; styleUrls: ['./create-asset-profile-dialog.component.scss'], templateUrl: 'create-asset-profile-dialog.html' }) -export class GfCreateAssetProfileDialogComponent implements OnDestroy, OnInit { +export class GfCreateAssetProfileDialogComponent implements OnInit { public createAssetProfileForm: FormGroup; public ghostfolioPrefix = `${ghostfolioPrefix}_`; public mode: CreateAssetProfileDialogMode; private customCurrencies: string[]; private dataSourceForExchangeRates: DataSource; - private unsubscribeSubject = new Subject(); public constructor( public readonly adminService: AdminService, private readonly changeDetectorRef: ChangeDetectorRef, private readonly dataService: DataService, + private readonly destroyRef: DestroyRef, public readonly dialogRef: MatDialogRef, public readonly formBuilder: FormBuilder ) {} @@ -125,7 +126,7 @@ export class GfCreateAssetProfileDialogComponent implements OnDestroy, OnInit { symbol: `${DEFAULT_CURRENCY}${currency}` }); }), - takeUntil(this.unsubscribeSubject) + takeUntilDestroyed(this.destroyRef) ) .subscribe(() => { this.dialogRef.close({ @@ -154,11 +155,6 @@ export class GfCreateAssetProfileDialogComponent implements OnDestroy, OnInit { return false; } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private atLeastOneValid(control: AbstractControl): ValidationErrors { const addCurrencyControl = control.get('addCurrency'); const addSymbolControl = control.get('addSymbol'); @@ -189,7 +185,7 @@ export class GfCreateAssetProfileDialogComponent implements OnDestroy, OnInit { private initialize() { this.adminService .fetchAdminData() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ dataProviders, settings }) => { this.customCurrencies = settings[PROPERTY_CURRENCIES] as string[]; diff --git a/apps/client/src/app/components/admin-overview/admin-overview.component.ts b/apps/client/src/app/components/admin-overview/admin-overview.component.ts index c0ccb0f64..5d4e5268e 100644 --- a/apps/client/src/app/components/admin-overview/admin-overview.component.ts +++ b/apps/client/src/app/components/admin-overview/admin-overview.component.ts @@ -22,7 +22,13 @@ import { AdminService, DataService } from '@ghostfolio/ui/services'; import { GfValueComponent } from '@ghostfolio/ui/value'; import { CommonModule } from '@angular/common'; -import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; +import { + ChangeDetectorRef, + Component, + DestroyRef, + OnInit +} from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; @@ -50,8 +56,6 @@ import { trashOutline } from 'ionicons/icons'; import ms, { StringValue } from 'ms'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; @Component({ imports: [ @@ -72,7 +76,7 @@ import { takeUntil } from 'rxjs/operators'; styleUrls: ['./admin-overview.scss'], templateUrl: './admin-overview.html' }) -export class GfAdminOverviewComponent implements OnDestroy, OnInit { +export class GfAdminOverviewComponent implements OnInit { public activitiesCount: number; public couponDuration: StringValue = '14 days'; public coupons: Coupon[]; @@ -88,13 +92,12 @@ export class GfAdminOverviewComponent implements OnDestroy, OnInit { public user: User; public version: string; - private unsubscribeSubject = new Subject(); - public constructor( private adminService: AdminService, private cacheService: CacheService, private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private notificationService: NotificationService, private snackBar: MatSnackBar, private userService: UserService @@ -102,7 +105,7 @@ export class GfAdminOverviewComponent implements OnDestroy, OnInit { this.info = this.dataService.fetchInfo(); this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -219,7 +222,7 @@ export class GfAdminOverviewComponent implements OnDestroy, OnInit { confirmFn: () => { this.cacheService .flush() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { setTimeout(() => { window.location.reload(); @@ -268,7 +271,7 @@ export class GfAdminOverviewComponent implements OnDestroy, OnInit { public onSyncDemoUserAccount() { this.adminService .syncDemoUserAccount() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.snackBar.open( '✅ ' + $localize`Demo user account has been synced.`, @@ -280,15 +283,10 @@ export class GfAdminOverviewComponent implements OnDestroy, OnInit { }); } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private fetchAdminData() { this.adminService .fetchAdminData() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ activitiesCount, settings, userCount, version }) => { this.activitiesCount = activitiesCount; this.coupons = (settings[PROPERTY_COUPONS] as Coupon[]) ?? []; @@ -320,7 +318,7 @@ export class GfAdminOverviewComponent implements OnDestroy, OnInit { .putAdminSetting(key, { value: value || value === false ? JSON.stringify(value) : undefined }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { setTimeout(() => { window.location.reload(); diff --git a/apps/client/src/app/components/admin-platform/admin-platform.component.html b/apps/client/src/app/components/admin-platform/admin-platform.component.html index 367827878..7370a19ae 100644 --- a/apps/client/src/app/components/admin-platform/admin-platform.component.html +++ b/apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -52,7 +52,11 @@ Accounts - {{ element.accountCount }} + diff --git a/apps/client/src/app/components/admin-platform/admin-platform.component.ts b/apps/client/src/app/components/admin-platform/admin-platform.component.ts index 02a2eed64..b8f2af789 100644 --- a/apps/client/src/app/components/admin-platform/admin-platform.component.ts +++ b/apps/client/src/app/components/admin-platform/admin-platform.component.ts @@ -1,18 +1,22 @@ import { UserService } from '@ghostfolio/client/services/user/user.service'; import { CreatePlatformDto, UpdatePlatformDto } from '@ghostfolio/common/dtos'; import { ConfirmationDialogType } from '@ghostfolio/common/enums'; +import { getLocale } from '@ghostfolio/common/helper'; import { GfEntityLogoComponent } from '@ghostfolio/ui/entity-logo'; import { NotificationService } from '@ghostfolio/ui/notifications'; import { AdminService, DataService } from '@ghostfolio/ui/services'; +import { GfValueComponent } from '@ghostfolio/ui/value'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, - OnDestroy, + DestroyRef, + Input, OnInit, ViewChild } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatButtonModule } from '@angular/material/button'; import { MatDialog } from '@angular/material/dialog'; import { MatMenuModule } from '@angular/material/menu'; @@ -29,7 +33,6 @@ import { } from 'ionicons/icons'; import { get } from 'lodash'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject, takeUntil } from 'rxjs'; import { GfCreateOrUpdatePlatformDialogComponent } from './create-or-update-platform-dialog/create-or-update-platform-dialog.component'; import { CreateOrUpdatePlatformDialogParams } from './create-or-update-platform-dialog/interfaces/interfaces'; @@ -38,6 +41,7 @@ import { CreateOrUpdatePlatformDialogParams } from './create-or-update-platform- changeDetection: ChangeDetectionStrategy.OnPush, imports: [ GfEntityLogoComponent, + GfValueComponent, IonIcon, MatButtonModule, MatMenuModule, @@ -49,7 +53,9 @@ import { CreateOrUpdatePlatformDialogParams } from './create-or-update-platform- styleUrls: ['./admin-platform.component.scss'], templateUrl: './admin-platform.component.html' }) -export class GfAdminPlatformComponent implements OnDestroy, OnInit { +export class GfAdminPlatformComponent implements OnInit { + @Input() locale = getLocale(); + @ViewChild(MatSort) sort: MatSort; public dataSource = new MatTableDataSource(); @@ -57,12 +63,11 @@ export class GfAdminPlatformComponent implements OnDestroy, OnInit { public displayedColumns = ['name', 'url', 'accounts', 'actions']; public platforms: Platform[]; - private unsubscribeSubject = new Subject(); - public constructor( private adminService: AdminService, private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private dialog: MatDialog, private notificationService: NotificationService, @@ -71,7 +76,7 @@ export class GfAdminPlatformComponent implements OnDestroy, OnInit { private userService: UserService ) { this.route.queryParams - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((params) => { if (params['createPlatformDialog']) { this.openCreatePlatformDialog(); @@ -113,20 +118,15 @@ export class GfAdminPlatformComponent implements OnDestroy, OnInit { }); } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private deletePlatform(aId: string) { this.adminService .deletePlatform(aId) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe({ next: () => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); this.fetchPlatforms(); @@ -137,7 +137,7 @@ export class GfAdminPlatformComponent implements OnDestroy, OnInit { private fetchPlatforms() { this.adminService .fetchPlatforms() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((platforms) => { this.platforms = platforms; @@ -169,17 +169,17 @@ export class GfAdminPlatformComponent implements OnDestroy, OnInit { dialogRef .afterClosed() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((platform: CreatePlatformDto | null) => { if (platform) { this.adminService .postPlatform(platform) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe({ next: () => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); this.fetchPlatforms(); @@ -217,17 +217,17 @@ export class GfAdminPlatformComponent implements OnDestroy, OnInit { dialogRef .afterClosed() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((platform: UpdatePlatformDto | null) => { if (platform) { this.adminService .putPlatform(platform) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe({ next: () => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); this.fetchPlatforms(); diff --git a/apps/client/src/app/components/admin-platform/create-or-update-platform-dialog/create-or-update-platform-dialog.component.ts b/apps/client/src/app/components/admin-platform/create-or-update-platform-dialog/create-or-update-platform-dialog.component.ts index dfcf300c1..0cfe026a4 100644 --- a/apps/client/src/app/components/admin-platform/create-or-update-platform-dialog/create-or-update-platform-dialog.component.ts +++ b/apps/client/src/app/components/admin-platform/create-or-update-platform-dialog/create-or-update-platform-dialog.component.ts @@ -2,12 +2,7 @@ import { CreatePlatformDto, UpdatePlatformDto } from '@ghostfolio/common/dtos'; import { validateObjectForForm } from '@ghostfolio/common/utils'; import { GfEntityLogoComponent } from '@ghostfolio/ui/entity-logo'; -import { - ChangeDetectionStrategy, - Component, - Inject, - OnDestroy -} from '@angular/core'; +import { ChangeDetectionStrategy, Component, Inject } from '@angular/core'; import { FormBuilder, FormGroup, @@ -23,7 +18,6 @@ import { } from '@angular/material/dialog'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; -import { Subject } from 'rxjs'; import { CreateOrUpdatePlatformDialogParams } from './interfaces/interfaces'; @@ -43,11 +37,9 @@ import { CreateOrUpdatePlatformDialogParams } from './interfaces/interfaces'; styleUrls: ['./create-or-update-platform-dialog.scss'], templateUrl: 'create-or-update-platform-dialog.html' }) -export class GfCreateOrUpdatePlatformDialogComponent implements OnDestroy { +export class GfCreateOrUpdatePlatformDialogComponent { public platformForm: FormGroup; - private unsubscribeSubject = new Subject(); - public constructor( @Inject(MAT_DIALOG_DATA) public data: CreateOrUpdatePlatformDialogParams, public dialogRef: MatDialogRef, @@ -90,9 +82,4 @@ export class GfCreateOrUpdatePlatformDialogComponent implements OnDestroy { console.error(error); } } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/components/admin-settings/admin-settings.component.html b/apps/client/src/app/components/admin-settings/admin-settings.component.html index af64f034b..76af96c4e 100644 --- a/apps/client/src/app/components/admin-settings/admin-settings.component.html +++ b/apps/client/src/app/components/admin-settings/admin-settings.component.html @@ -40,9 +40,21 @@ } - +
- diff --git a/apps/client/src/app/components/admin-tag/admin-tag.component.ts b/apps/client/src/app/components/admin-tag/admin-tag.component.ts index ca7950291..506736156 100644 --- a/apps/client/src/app/components/admin-tag/admin-tag.component.ts +++ b/apps/client/src/app/components/admin-tag/admin-tag.component.ts @@ -1,17 +1,21 @@ import { UserService } from '@ghostfolio/client/services/user/user.service'; import { CreateTagDto, UpdateTagDto } from '@ghostfolio/common/dtos'; import { ConfirmationDialogType } from '@ghostfolio/common/enums'; +import { getLocale } from '@ghostfolio/common/helper'; import { NotificationService } from '@ghostfolio/ui/notifications'; import { DataService } from '@ghostfolio/ui/services'; +import { GfValueComponent } from '@ghostfolio/ui/value'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, - OnDestroy, + DestroyRef, + Input, OnInit, ViewChild } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatButtonModule } from '@angular/material/button'; import { MatDialog } from '@angular/material/dialog'; import { MatMenuModule } from '@angular/material/menu'; @@ -28,7 +32,6 @@ import { } from 'ionicons/icons'; import { get } from 'lodash'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject, takeUntil } from 'rxjs'; import { GfCreateOrUpdateTagDialogComponent } from './create-or-update-tag-dialog/create-or-update-tag-dialog.component'; import { CreateOrUpdateTagDialogParams } from './create-or-update-tag-dialog/interfaces/interfaces'; @@ -36,6 +39,7 @@ import { CreateOrUpdateTagDialogParams } from './create-or-update-tag-dialog/int @Component({ changeDetection: ChangeDetectionStrategy.OnPush, imports: [ + GfValueComponent, IonIcon, MatButtonModule, MatMenuModule, @@ -47,7 +51,9 @@ import { CreateOrUpdateTagDialogParams } from './create-or-update-tag-dialog/int styleUrls: ['./admin-tag.component.scss'], templateUrl: './admin-tag.component.html' }) -export class GfAdminTagComponent implements OnDestroy, OnInit { +export class GfAdminTagComponent implements OnInit { + @Input() locale = getLocale(); + @ViewChild(MatSort) sort: MatSort; public dataSource = new MatTableDataSource(); @@ -55,11 +61,10 @@ export class GfAdminTagComponent implements OnDestroy, OnInit { public displayedColumns = ['name', 'userId', 'activities', 'actions']; public tags: Tag[]; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private dialog: MatDialog, private notificationService: NotificationService, @@ -68,7 +73,7 @@ export class GfAdminTagComponent implements OnDestroy, OnInit { private userService: UserService ) { this.route.queryParams - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((params) => { if (params['createTagDialog']) { this.openCreateTagDialog(); @@ -110,20 +115,15 @@ export class GfAdminTagComponent implements OnDestroy, OnInit { }); } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private deleteTag(aId: string) { this.dataService .deleteTag(aId) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe({ next: () => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); this.fetchTags(); @@ -134,7 +134,7 @@ export class GfAdminTagComponent implements OnDestroy, OnInit { private fetchTags() { this.dataService .fetchTags() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((tags) => { this.tags = tags; @@ -165,17 +165,17 @@ export class GfAdminTagComponent implements OnDestroy, OnInit { dialogRef .afterClosed() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((tag: CreateTagDto | null) => { if (tag) { this.dataService .postTag(tag) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe({ next: () => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); this.fetchTags(); @@ -204,17 +204,17 @@ export class GfAdminTagComponent implements OnDestroy, OnInit { dialogRef .afterClosed() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((tag: UpdateTagDto | null) => { if (tag) { this.dataService .putTag(tag) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe({ next: () => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); this.fetchTags(); diff --git a/apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.component.ts b/apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.component.ts index 323609a48..e22c73478 100644 --- a/apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.component.ts +++ b/apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.component.ts @@ -1,12 +1,7 @@ import { CreateTagDto, UpdateTagDto } from '@ghostfolio/common/dtos'; import { validateObjectForForm } from '@ghostfolio/common/utils'; -import { - ChangeDetectionStrategy, - Component, - Inject, - OnDestroy -} from '@angular/core'; +import { ChangeDetectionStrategy, Component, Inject } from '@angular/core'; import { FormBuilder, FormGroup, @@ -21,7 +16,6 @@ import { } from '@angular/material/dialog'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; -import { Subject } from 'rxjs'; import { CreateOrUpdateTagDialogParams } from './interfaces/interfaces'; @@ -40,11 +34,9 @@ import { CreateOrUpdateTagDialogParams } from './interfaces/interfaces'; styleUrls: ['./create-or-update-tag-dialog.scss'], templateUrl: 'create-or-update-tag-dialog.html' }) -export class GfCreateOrUpdateTagDialogComponent implements OnDestroy { +export class GfCreateOrUpdateTagDialogComponent { public tagForm: FormGroup; - private unsubscribeSubject = new Subject(); - public constructor( @Inject(MAT_DIALOG_DATA) public data: CreateOrUpdateTagDialogParams, public dialogRef: MatDialogRef, @@ -85,9 +77,4 @@ export class GfCreateOrUpdateTagDialogComponent implements OnDestroy { console.error(error); } } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } 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 d479f2037..3b57ba1c8 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 @@ -1,7 +1,6 @@ import { UserDetailDialogParams } from '@ghostfolio/client/components/user-detail-dialog/interfaces/interfaces'; import { GfUserDetailDialogComponent } from '@ghostfolio/client/components/user-detail-dialog/user-detail-dialog.component'; import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service'; -import { TokenStorageService } from '@ghostfolio/client/services/token-storage.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { DEFAULT_PAGE_SIZE } from '@ghostfolio/common/config'; import { ConfirmationDialogType } from '@ghostfolio/common/enums'; @@ -26,10 +25,11 @@ import { CommonModule } from '@angular/common'; import { ChangeDetectorRef, Component, - OnDestroy, + DestroyRef, OnInit, ViewChild } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatButtonModule } from '@angular/material/button'; import { MatDialog } from '@angular/material/dialog'; import { MatMenuModule } from '@angular/material/menu'; @@ -56,8 +56,7 @@ import { } from 'ionicons/icons'; import { DeviceDetectorService } from 'ngx-device-detector'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; -import { Subject } from 'rxjs'; -import { switchMap, takeUntil, tap } from 'rxjs/operators'; +import { switchMap, tap } from 'rxjs/operators'; @Component({ imports: [ @@ -76,7 +75,7 @@ import { switchMap, takeUntil, tap } from 'rxjs/operators'; styleUrls: ['./admin-users.scss'], templateUrl: './admin-users.html' }) -export class GfAdminUsersComponent implements OnDestroy, OnInit { +export class GfAdminUsersComponent implements OnInit { @ViewChild(MatPaginator) paginator: MatPaginator; public dataSource = new MatTableDataSource(); @@ -90,23 +89,21 @@ export class GfAdminUsersComponent implements OnDestroy, OnInit { public isLoading = false; public pageSize = DEFAULT_PAGE_SIZE; public routerLinkAdminControlUsers = - internalRoutes.adminControl.subRoutes.users.routerLink; + internalRoutes.adminControl.subRoutes?.users.routerLink; public totalItems = 0; public user: User; - private unsubscribeSubject = new Subject(); - public constructor( private adminService: AdminService, private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private dialog: MatDialog, private impersonationStorageService: ImpersonationStorageService, private notificationService: NotificationService, private route: ActivatedRoute, private router: Router, - private tokenStorageService: TokenStorageService, private userService: UserService ) { this.deviceType = this.deviceService.getDeviceInfo().deviceType; @@ -141,7 +138,7 @@ export class GfAdminUsersComponent implements OnDestroy, OnInit { this.userService.stateChanged .pipe( - takeUntil(this.unsubscribeSubject), + takeUntilDestroyed(this.destroyRef), tap((state) => { if (state?.user) { this.user = state.user; @@ -206,7 +203,7 @@ export class GfAdminUsersComponent implements OnDestroy, OnInit { confirmFn: () => { this.dataService .deleteUser(aId) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.router.navigate(['..'], { relativeTo: this.route }); }); @@ -224,13 +221,12 @@ export class GfAdminUsersComponent implements OnDestroy, OnInit { confirmFn: () => { this.dataService .updateUserAccessToken(aUserId) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ accessToken }) => { this.notificationService.alert({ discardFn: () => { if (aUserId === this.user.id) { - this.tokenStorageService.signOut(); - this.userService.remove(); + this.userService.signOut(); document.location.href = `/${document.documentElement.lang}`; } @@ -261,11 +257,6 @@ export class GfAdminUsersComponent implements OnDestroy, OnInit { ); } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private fetchUsers({ pageIndex }: { pageIndex: number } = { pageIndex: 0 }) { this.isLoading = true; @@ -278,7 +269,7 @@ export class GfAdminUsersComponent implements OnDestroy, OnInit { skip: pageIndex * this.pageSize, take: this.pageSize }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ count, users }) => { this.dataSource = new MatTableDataSource(users); this.totalItems = count; @@ -308,7 +299,7 @@ export class GfAdminUsersComponent implements OnDestroy, OnInit { dialogRef .afterClosed() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((data) => { if (data?.action === 'delete' && data?.userId) { this.onDeleteUser(data.userId); diff --git a/apps/client/src/app/components/data-provider-status/data-provider-status.component.ts b/apps/client/src/app/components/data-provider-status/data-provider-status.component.ts index e44e81be9..a77d65961 100644 --- a/apps/client/src/app/components/data-provider-status/data-provider-status.component.ts +++ b/apps/client/src/app/components/data-provider-status/data-provider-status.component.ts @@ -4,13 +4,14 @@ import { CommonModule } from '@angular/common'; import { ChangeDetectionStrategy, Component, + DestroyRef, Input, - OnDestroy, OnInit } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import type { DataSource } from '@prisma/client'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; -import { catchError, map, type Observable, of, Subject, takeUntil } from 'rxjs'; +import { catchError, map, type Observable, of } from 'rxjs'; import { DataProviderStatus } from './interfaces/interfaces'; @@ -20,14 +21,15 @@ import { DataProviderStatus } from './interfaces/interfaces'; selector: 'gf-data-provider-status', templateUrl: './data-provider-status.component.html' }) -export class GfDataProviderStatusComponent implements OnDestroy, OnInit { +export class GfDataProviderStatusComponent implements OnInit { @Input() dataSource: DataSource; public status$: Observable; - private unsubscribeSubject = new Subject(); - - public constructor(private dataService: DataService) {} + public constructor( + private dataService: DataService, + private destroyRef: DestroyRef + ) {} public ngOnInit() { this.status$ = this.dataService @@ -39,12 +41,7 @@ export class GfDataProviderStatusComponent implements OnDestroy, OnInit { catchError(() => { return of({ isHealthy: false }); }), - takeUntil(this.unsubscribeSubject) + takeUntilDestroyed(this.destroyRef) ); } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/components/footer/footer.component.ts b/apps/client/src/app/components/footer/footer.component.ts index 48f010565..d06e711b9 100644 --- a/apps/client/src/app/components/footer/footer.component.ts +++ b/apps/client/src/app/components/footer/footer.component.ts @@ -33,13 +33,13 @@ export class GfFooterComponent implements OnChanges { public hasPermissionToAccessFearAndGreedIndex: boolean; public routerLinkAbout = publicRoutes.about.routerLink; public routerLinkAboutChangelog = - publicRoutes.about.subRoutes.changelog.routerLink; + publicRoutes.about.subRoutes?.changelog.routerLink; public routerLinkAboutLicense = - publicRoutes.about.subRoutes.license.routerLink; + publicRoutes.about.subRoutes?.license.routerLink; public routerLinkAboutPrivacyPolicy = - publicRoutes.about.subRoutes.privacyPolicy.routerLink; + publicRoutes.about.subRoutes?.privacyPolicy.routerLink; public routerLinkAboutTermsOfService = - publicRoutes.about.subRoutes.termsOfService.routerLink; + publicRoutes.about.subRoutes?.termsOfService.routerLink; public routerLinkBlog = publicRoutes.blog.routerLink; public routerLinkFaq = publicRoutes.faq.routerLink; public routerLinkFeatures = publicRoutes.features.routerLink; diff --git a/apps/client/src/app/components/header/header.component.ts b/apps/client/src/app/components/header/header.component.ts index 9b003a590..ab329251f 100644 --- a/apps/client/src/app/components/header/header.component.ts +++ b/apps/client/src/app/components/header/header.component.ts @@ -24,6 +24,7 @@ import { ChangeDetectionStrategy, Component, CUSTOM_ELEMENTS_SCHEMA, + DestroyRef, EventEmitter, HostListener, Input, @@ -31,6 +32,7 @@ import { Output, ViewChild } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatBadgeModule } from '@angular/material/badge'; import { MatButtonModule } from '@angular/material/button'; import { MatDialog } from '@angular/material/dialog'; @@ -48,8 +50,8 @@ import { radioButtonOffOutline, radioButtonOnOutline } from 'ionicons/icons'; -import { EMPTY, Subject } from 'rxjs'; -import { catchError, takeUntil } from 'rxjs/operators'; +import { EMPTY } from 'rxjs'; +import { catchError } from 'rxjs/operators'; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, @@ -131,10 +133,9 @@ export class GfHeaderComponent implements OnChanges { public routerLinkRegister = publicRoutes.register.routerLink; public routerLinkResources = publicRoutes.resources.routerLink; - private unsubscribeSubject = new Subject(); - public constructor( private dataService: DataService, + private destroyRef: DestroyRef, private dialog: MatDialog, private impersonationStorageService: ImpersonationStorageService, private layoutService: LayoutService, @@ -146,7 +147,7 @@ export class GfHeaderComponent implements OnChanges { ) { this.impersonationStorageService .onChangeHasImpersonation() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((impersonationId) => { this.hasImpersonationId = !!impersonationId; this.impersonationId = impersonationId; @@ -224,11 +225,11 @@ export class GfHeaderComponent implements OnChanges { public onDateRangeChange(dateRange: DateRange) { this.dataService .putUserSetting({ dateRange }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); }); } @@ -252,11 +253,11 @@ export class GfHeaderComponent implements OnChanges { this.dataService .putUserSetting(userSetting) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); }); } @@ -301,7 +302,7 @@ export class GfHeaderComponent implements OnChanges { dialogRef .afterClosed() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((data) => { if (data?.accessToken) { this.dataService @@ -314,7 +315,7 @@ export class GfHeaderComponent implements OnChanges { return EMPTY; }), - takeUntil(this.unsubscribeSubject) + takeUntilDestroyed(this.destroyRef) ) .subscribe(({ authToken }) => { this.setToken(authToken); @@ -331,7 +332,7 @@ export class GfHeaderComponent implements OnChanges { this.userService .get() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((user) => { const userLanguage = user?.settings?.language; @@ -342,9 +343,4 @@ export class GfHeaderComponent implements OnChanges { } }); } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } 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 427386796..13ded73eb 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 @@ -35,10 +35,11 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, + DestroyRef, Inject, - OnDestroy, OnInit } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { FormBuilder, FormGroup, ReactiveFormsModule } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; import { MatChipsModule } from '@angular/material/chips'; @@ -67,8 +68,7 @@ import { walletOutline } from 'ionicons/icons'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; -import { Subject } from 'rxjs'; -import { switchMap, takeUntil } from 'rxjs/operators'; +import { switchMap } from 'rxjs/operators'; import { HoldingDetailDialogParams } from './interfaces/interfaces'; @@ -102,7 +102,7 @@ import { HoldingDetailDialogParams } from './interfaces/interfaces'; styleUrls: ['./holding-detail-dialog.component.scss'], templateUrl: 'holding-detail-dialog.html' }) -export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { +export class GfHoldingDetailDialogComponent implements OnInit { public activitiesCount: number; public accounts: Account[]; public assetClass: string; @@ -158,11 +158,10 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { public user: User; public value: number; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, public dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public data: HoldingDetailDialogParams, private formBuilder: FormBuilder, @@ -192,7 +191,7 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { this.holdingForm .get('tags') - .valueChanges.pipe(takeUntil(this.unsubscribeSubject)) + .valueChanges.pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((tags: Tag[]) => { const newTag = tags.find(({ id }) => { return id === undefined; @@ -217,7 +216,7 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { switchMap(() => { return this.userService.get(true); }), - takeUntil(this.unsubscribeSubject) + takeUntilDestroyed(this.destroyRef) ) .subscribe(); } else { @@ -227,7 +226,7 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { dataSource: this.data.dataSource, symbol: this.data.symbol }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); } }); @@ -236,7 +235,7 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { .fetchAccounts({ filters }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ accounts }) => { this.accounts = accounts; @@ -249,7 +248,7 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { sortColumn: this.sortColumn, sortDirection: this.sortDirection }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ activities }) => { this.dataSource = new MatTableDataSource(activities); @@ -261,7 +260,7 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { dataSource: this.data.dataSource, symbol: this.data.symbol }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe( ({ activitiesCount, @@ -524,7 +523,7 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { ); this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -581,8 +580,8 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { }; this.dataService - .postOrder(activity) - .pipe(takeUntil(this.unsubscribeSubject)) + .postActivity(activity) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.router.navigate( internalRoutes.portfolio.subRoutes.activities.routerLink @@ -599,7 +598,7 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { this.dataService .fetchExport({ activityIds }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((data) => { downloadAsFile({ content: data, @@ -629,18 +628,13 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { this.dialogRef.close(); } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private fetchMarketData() { this.dataService .fetchMarketDataBySymbol({ dataSource: this.data.dataSource, symbol: this.data.symbol }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ marketData }) => { this.marketDataItems = marketData; 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 86f4676f3..b8cb8dda2 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 @@ -310,6 +310,9 @@ Symbol ISIN diff --git a/apps/client/src/app/components/holding-detail-dialog/interfaces/interfaces.ts b/apps/client/src/app/components/holding-detail-dialog/interfaces/interfaces.ts index aab854384..527b13636 100644 --- a/apps/client/src/app/components/holding-detail-dialog/interfaces/interfaces.ts +++ b/apps/client/src/app/components/holding-detail-dialog/interfaces/interfaces.ts @@ -11,7 +11,7 @@ export interface HoldingDetailDialogParams { hasPermissionToAccessAdminControl: boolean; hasPermissionToCreateActivity: boolean; hasPermissionToReportDataGlitch: boolean; - hasPermissionToUpdateOrder: boolean; + hasPermissionToUpdateActivity: boolean; locale: string; symbol: string; } diff --git a/apps/client/src/app/components/home-holdings/home-holdings.component.ts b/apps/client/src/app/components/home-holdings/home-holdings.component.ts index dc444977d..19a48ccd8 100644 --- a/apps/client/src/app/components/home-holdings/home-holdings.component.ts +++ b/apps/client/src/app/components/home-holdings/home-holdings.component.ts @@ -19,9 +19,10 @@ import { ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA, - OnDestroy, + DestroyRef, OnInit } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; import { MatButtonToggleModule } from '@angular/material/button-toggle'; @@ -30,8 +31,6 @@ import { IonIcon } from '@ionic/angular/standalone'; import { addIcons } from 'ionicons'; import { gridOutline, reorderFourOutline } from 'ionicons/icons'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; @Component({ imports: [ @@ -51,7 +50,7 @@ import { takeUntil } from 'rxjs/operators'; styleUrls: ['./home-holdings.scss'], templateUrl: './home-holdings.html' }) -export class GfHomeHoldingsComponent implements OnDestroy, OnInit { +export class GfHomeHoldingsComponent implements OnInit { public static DEFAULT_HOLDINGS_VIEW_MODE: HoldingsViewMode = 'TABLE'; public deviceType: string; @@ -71,11 +70,10 @@ export class GfHomeHoldingsComponent implements OnDestroy, OnInit { GfHomeHoldingsComponent.DEFAULT_HOLDINGS_VIEW_MODE ); - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private impersonationStorageService: ImpersonationStorageService, private router: Router, @@ -89,13 +87,13 @@ export class GfHomeHoldingsComponent implements OnDestroy, OnInit { this.impersonationStorageService .onChangeHasImpersonation() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((impersonationId) => { this.hasImpersonationId = !!impersonationId; }); this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -107,7 +105,7 @@ export class GfHomeHoldingsComponent implements OnDestroy, OnInit { this.hasPermissionToCreateActivity = hasPermission( this.user.permissions, - permissions.createOrder + permissions.createActivity ); this.initialize(); @@ -117,15 +115,15 @@ export class GfHomeHoldingsComponent implements OnDestroy, OnInit { }); this.viewModeFormControl.valueChanges - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((holdingsViewMode) => { this.dataService .putUserSetting({ holdingsViewMode }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((user) => { this.user = user; @@ -149,11 +147,6 @@ export class GfHomeHoldingsComponent implements OnDestroy, OnInit { } } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private fetchHoldings() { const filters = this.userService.getFilters(); @@ -193,7 +186,7 @@ export class GfHomeHoldingsComponent implements OnDestroy, OnInit { this.holdings = undefined; this.fetchHoldings() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ holdings }) => { this.holdings = holdings; diff --git a/apps/client/src/app/components/home-holdings/home-holdings.html b/apps/client/src/app/components/home-holdings/home-holdings.html index ec131cd39..175c88606 100644 --- a/apps/client/src/app/components/home-holdings/home-holdings.html +++ b/apps/client/src/app/components/home-holdings/home-holdings.html @@ -46,7 +46,6 @@ }
(); - public constructor( private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private userService: UserService ) { @@ -59,7 +57,7 @@ export class GfHomeMarketComponent implements OnDestroy, OnInit { this.info = this.dataService.fetchInfo(); this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -82,7 +80,7 @@ export class GfHomeMarketComponent implements OnDestroy, OnInit { includeHistoricalData: this.numberOfDays, symbol: ghostfolioFearAndGreedIndexSymbol }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ historicalData, marketPrice }) => { this.fearAndGreedIndex = marketPrice; this.historicalDataItems = [ @@ -99,16 +97,11 @@ export class GfHomeMarketComponent implements OnDestroy, OnInit { this.dataService .fetchBenchmarks() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ benchmarks }) => { this.benchmarks = benchmarks; this.changeDetectorRef.markForCheck(); }); } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/components/home-overview/home-overview.component.ts b/apps/client/src/app/components/home-overview/home-overview.component.ts index e9cafe003..ececc7b13 100644 --- a/apps/client/src/app/components/home-overview/home-overview.component.ts +++ b/apps/client/src/app/components/home-overview/home-overview.component.ts @@ -19,14 +19,13 @@ import { ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA, - OnDestroy, + DestroyRef, OnInit } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatButtonModule } from '@angular/material/button'; import { RouterModule } from '@angular/router'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; @Component({ imports: [ @@ -41,7 +40,7 @@ import { takeUntil } from 'rxjs/operators'; styleUrls: ['./home-overview.scss'], templateUrl: './home-overview.html' }) -export class GfHomeOverviewComponent implements OnDestroy, OnInit { +export class GfHomeOverviewComponent implements OnInit { public deviceType: string; public errors: AssetProfileIdentifier[]; public hasError: boolean; @@ -57,32 +56,31 @@ export class GfHomeOverviewComponent implements OnDestroy, OnInit { public routerLinkAccounts = internalRoutes.accounts.routerLink; public routerLinkPortfolio = internalRoutes.portfolio.routerLink; public routerLinkPortfolioActivities = - internalRoutes.portfolio.subRoutes.activities.routerLink; + internalRoutes.portfolio.subRoutes?.activities.routerLink; public showDetails = false; public unit: string; public user: User; private graph_type: string; public graph_unit: string; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private impersonationStorageService: ImpersonationStorageService, private layoutService: LayoutService, private userService: UserService ) { this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; this.hasPermissionToCreateActivity = hasPermission( this.user.permissions, - permissions.createOrder + permissions.createActivity ); this.update(); @@ -106,7 +104,7 @@ export class GfHomeOverviewComponent implements OnDestroy, OnInit { this.impersonationStorageService .onChangeHasImpersonation() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((impersonationId) => { this.hasImpersonationId = !!impersonationId; @@ -114,17 +112,12 @@ export class GfHomeOverviewComponent implements OnDestroy, OnInit { }); this.layoutService.shouldReloadContent$ - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.update(); }); } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private update() { this.historicalDataItems = null; this.isLoadingPerformance = true; @@ -133,7 +126,7 @@ export class GfHomeOverviewComponent implements OnDestroy, OnInit { .fetchPortfolioPerformance({ range: this.user?.settings?.dateRange }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ chart, errors, performance }) => { this.errors = errors; this.performance = performance; diff --git a/apps/client/src/app/components/home-summary/home-summary.component.ts b/apps/client/src/app/components/home-summary/home-summary.component.ts index 454d05689..719cfbd29 100644 --- a/apps/client/src/app/components/home-summary/home-summary.component.ts +++ b/apps/client/src/app/components/home-summary/home-summary.component.ts @@ -13,14 +13,13 @@ import { ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA, - OnDestroy, + DestroyRef, OnInit } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatCardModule } from '@angular/material/card'; import { MatSnackBarRef, TextOnlySnackBar } from '@angular/material/snack-bar'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; @Component({ imports: [GfPortfolioSummaryComponent, MatCardModule], @@ -29,7 +28,7 @@ import { takeUntil } from 'rxjs/operators'; styleUrls: ['./home-summary.scss'], templateUrl: './home-summary.html' }) -export class GfHomeSummaryComponent implements OnDestroy, OnInit { +export class GfHomeSummaryComponent implements OnInit { public deviceType: string; public hasImpersonationId: boolean; public hasPermissionForSubscription: boolean; @@ -40,11 +39,10 @@ export class GfHomeSummaryComponent implements OnDestroy, OnInit { public summary: PortfolioSummary; public user: User; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private impersonationStorageService: ImpersonationStorageService, private userService: UserService @@ -57,7 +55,7 @@ export class GfHomeSummaryComponent implements OnDestroy, OnInit { ); this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -77,7 +75,7 @@ export class GfHomeSummaryComponent implements OnDestroy, OnInit { this.impersonationStorageService .onChangeHasImpersonation() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((impersonationId) => { this.hasImpersonationId = !!impersonationId; }); @@ -86,11 +84,11 @@ export class GfHomeSummaryComponent implements OnDestroy, OnInit { public onChangeEmergencyFund(emergencyFund: number) { this.dataService .putUserSetting({ emergencyFund }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((user) => { this.user = user; @@ -99,17 +97,12 @@ export class GfHomeSummaryComponent implements OnDestroy, OnInit { }); } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private update() { this.isLoading = true; this.dataService .fetchPortfolioDetails() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ summary }) => { this.summary = summary; this.isLoading = false; diff --git a/apps/client/src/app/components/markets/markets.component.ts b/apps/client/src/app/components/markets/markets.component.ts index 4b83e897f..4214ee989 100644 --- a/apps/client/src/app/components/markets/markets.component.ts +++ b/apps/client/src/app/components/markets/markets.component.ts @@ -19,12 +19,11 @@ import { ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA, - OnDestroy, + DestroyRef, OnInit } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, @@ -39,7 +38,7 @@ import { takeUntil } from 'rxjs/operators'; styleUrls: ['./markets.scss'], templateUrl: './markets.html' }) -export class GfMarketsComponent implements OnDestroy, OnInit { +export class GfMarketsComponent implements OnInit { public benchmarks: Benchmark[]; public deviceType: string; public fearAndGreedIndex: number; @@ -55,18 +54,17 @@ export class GfMarketsComponent implements OnDestroy, OnInit { public readonly numberOfDays = 365; public user: User; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private userService: UserService ) { this.deviceType = this.deviceService.getDeviceInfo().deviceType; this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -79,7 +77,7 @@ export class GfMarketsComponent implements OnDestroy, OnInit { public ngOnInit() { this.dataService .fetchMarketDataOfMarkets({ includeHistoricalData: this.numberOfDays }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ fearAndGreedIndex }) => { this.fearAndGreedIndexData = fearAndGreedIndex; @@ -90,7 +88,7 @@ export class GfMarketsComponent implements OnDestroy, OnInit { this.dataService .fetchBenchmarks() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ benchmarks }) => { this.benchmarks = benchmarks; @@ -119,9 +117,4 @@ export class GfMarketsComponent implements OnDestroy, OnInit { this.initialize(); } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html b/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html index 46eb2845c..0e26a49a8 100644 --- a/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html +++ b/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -65,7 +65,11 @@ [locale]="locale" [precision]="precision" [unit]="baseCurrency" - [value]="isLoading ? undefined : summary?.committedFunds" + [value]=" + isLoading + ? undefined + : summary?.totalInvestmentValueWithCurrencyEffect + " />
@@ -180,18 +184,21 @@ [ngClass]="{ 'cursor-pointer': hasPermissionToUpdateUserSettings && + !user?.settings?.isRestrictedView && user?.subscription?.type !== 'Basic' }" (click)=" hasPermissionToUpdateUserSettings && + !user?.settings?.isRestrictedView && user?.subscription?.type !== 'Basic' && onEditEmergencyFund() " > @if ( hasPermissionToUpdateUserSettings && - user?.subscription?.type !== 'Basic' && - !isLoading + !isLoading && + !user?.settings?.isRestrictedView && + user?.subscription?.type !== 'Basic' ) { (); private deviceType: string; - private unsubscribeSubject = new Subject(); - public constructor( + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private dialog: MatDialog ) { @@ -94,7 +94,7 @@ export class GfRuleComponent implements OnInit { dialogRef .afterClosed() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((settings: RuleSettings) => { if (settings) { this.ruleUpdated.emit({ @@ -115,9 +115,4 @@ export class GfRuleComponent implements OnInit { this.ruleUpdated.emit(settings); } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } 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 ef78cccff..4f744a087 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 @@ -1,5 +1,4 @@ import { GfAccessTableComponent } from '@ghostfolio/client/components/access-table/access-table.component'; -import { TokenStorageService } from '@ghostfolio/client/services/token-storage.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { CreateAccessDto } from '@ghostfolio/common/dtos'; import { ConfirmationDialogType } from '@ghostfolio/common/enums'; @@ -76,7 +75,6 @@ export class GfUserAccountAccessComponent implements OnDestroy, OnInit { private notificationService: NotificationService, private route: ActivatedRoute, private router: Router, - private tokenStorageService: TokenStorageService, private userService: UserService ) { const { globalPermissions } = this.dataService.fetchInfo(); @@ -161,8 +159,7 @@ export class GfUserAccountAccessComponent implements OnDestroy, OnInit { .subscribe(({ accessToken }) => { this.notificationService.alert({ discardFn: () => { - this.tokenStorageService.signOut(); - this.userService.remove(); + this.userService.signOut(); document.location.href = `/${document.documentElement.lang}`; }, diff --git a/apps/client/src/app/components/user-account-settings/user-account-settings.component.ts b/apps/client/src/app/components/user-account-settings/user-account-settings.component.ts index 44be30b9a..0cf18df36 100644 --- a/apps/client/src/app/components/user-account-settings/user-account-settings.component.ts +++ b/apps/client/src/app/components/user-account-settings/user-account-settings.component.ts @@ -3,7 +3,6 @@ import { KEY_TOKEN, SettingsStorageService } from '@ghostfolio/client/services/settings-storage.service'; -import { TokenStorageService } from '@ghostfolio/client/services/token-storage.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { WebAuthnService } from '@ghostfolio/client/services/web-authn.service'; import { ConfirmationDialogType } from '@ghostfolio/common/enums'; @@ -108,7 +107,6 @@ export class GfUserAccountSettingsComponent implements OnDestroy, OnInit { private notificationService: NotificationService, private settingsStorageService: SettingsStorageService, private snackBar: MatSnackBar, - private tokenStorageService: TokenStorageService, private userService: UserService, public webAuthnService: WebAuthnService ) { @@ -198,8 +196,7 @@ export class GfUserAccountSettingsComponent implements OnDestroy, OnInit { takeUntil(this.unsubscribeSubject) ) .subscribe(() => { - this.tokenStorageService.signOut(); - this.userService.remove(); + this.userService.signOut(); document.location.href = `/${document.documentElement.lang}`; }); diff --git a/apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html b/apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html index 570dcf4d6..e9af86942 100644 --- a/apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html +++ b/apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -27,7 +27,13 @@
- User ID + User ID
Role diff --git a/apps/client/src/app/core/auth.guard.ts b/apps/client/src/app/core/auth.guard.ts index 123a6169a..3292f0ff7 100644 --- a/apps/client/src/app/core/auth.guard.ts +++ b/apps/client/src/app/core/auth.guard.ts @@ -68,7 +68,7 @@ export class AuthGuard { this.dataService .putUserSetting({ language: document.documentElement.lang }) .subscribe(() => { - this.userService.remove(); + this.userService.reset(); setTimeout(() => { window.location.reload(); diff --git a/apps/client/src/app/core/http-response.interceptor.ts b/apps/client/src/app/core/http-response.interceptor.ts index ab99b440f..315e9d64e 100644 --- a/apps/client/src/app/core/http-response.interceptor.ts +++ b/apps/client/src/app/core/http-response.interceptor.ts @@ -1,4 +1,4 @@ -import { TokenStorageService } from '@ghostfolio/client/services/token-storage.service'; +import { UserService } from '@ghostfolio/client/services/user/user.service'; import { WebAuthnService } from '@ghostfolio/client/services/web-authn.service'; import { InfoItem } from '@ghostfolio/common/interfaces'; import { internalRoutes, publicRoutes } from '@ghostfolio/common/routes/routes'; @@ -32,8 +32,8 @@ export class HttpResponseInterceptor implements HttpInterceptor { public constructor( private dataService: DataService, private router: Router, - private tokenStorageService: TokenStorageService, private snackBar: MatSnackBar, + private userService: UserService, private webAuthnService: WebAuthnService ) { this.info = this.dataService.fetchInfo(); @@ -115,7 +115,7 @@ export class HttpResponseInterceptor implements HttpInterceptor { if (this.webAuthnService.isEnabled()) { this.router.navigate(internalRoutes.webauthn.routerLink); } else { - this.tokenStorageService.signOut(); + this.userService.signOut(); } } } diff --git a/apps/client/src/app/interfaces/interfaces.ts b/apps/client/src/app/interfaces/interfaces.ts new file mode 100644 index 000000000..493eff4ab --- /dev/null +++ b/apps/client/src/app/interfaces/interfaces.ts @@ -0,0 +1,8 @@ +import type { Params } from '@angular/router'; +import type { DataSource } from '@prisma/client'; + +export interface GfAppQueryParams extends Params { + dataSource?: DataSource; + holdingDetailDialog?: string; + symbol?: string; +} diff --git a/apps/client/src/app/pages/about/about-page.component.ts b/apps/client/src/app/pages/about/about-page.component.ts index 5ddb6b2e0..1e749d1cd 100644 --- a/apps/client/src/app/pages/about/about-page.component.ts +++ b/apps/client/src/app/pages/about/about-page.component.ts @@ -8,9 +8,10 @@ import { ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA, - OnDestroy, + DestroyRef, OnInit } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatTabsModule } from '@angular/material/tabs'; import { RouterModule } from '@angular/router'; import { IonIcon } from '@ionic/angular/standalone'; @@ -24,8 +25,6 @@ import { sparklesOutline } from 'ionicons/icons'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; @Component({ host: { class: 'page has-tabs' }, @@ -35,17 +34,16 @@ import { takeUntil } from 'rxjs/operators'; styleUrls: ['./about-page.scss'], templateUrl: './about-page.html' }) -export class AboutPageComponent implements OnDestroy, OnInit { +export class AboutPageComponent implements OnInit { public deviceType: string; public hasPermissionForSubscription: boolean; public tabs: TabConfiguration[] = []; public user: User; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private userService: UserService ) { @@ -57,7 +55,7 @@ export class AboutPageComponent implements OnDestroy, OnInit { ); this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { this.tabs = [ { @@ -118,9 +116,4 @@ export class AboutPageComponent implements OnDestroy, OnInit { public ngOnInit() { this.deviceType = this.deviceService.getDeviceInfo().deviceType; } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/about/about-page.routes.ts b/apps/client/src/app/pages/about/about-page.routes.ts index 4cb13280a..b4466fbab 100644 --- a/apps/client/src/app/pages/about/about-page.routes.ts +++ b/apps/client/src/app/pages/about/about-page.routes.ts @@ -15,29 +15,29 @@ export const routes: Routes = [ import('./overview/about-overview-page.routes').then((m) => m.routes) }, { - path: publicRoutes.about.subRoutes.changelog.path, + path: publicRoutes.about.subRoutes?.changelog.path, loadChildren: () => import('./changelog/changelog-page.routes').then((m) => m.routes) }, { - path: publicRoutes.about.subRoutes.license.path, + path: publicRoutes.about.subRoutes?.license.path, loadChildren: () => import('./license/license-page.routes').then((m) => m.routes) }, { - path: publicRoutes.about.subRoutes.ossFriends.path, + path: publicRoutes.about.subRoutes?.ossFriends.path, loadChildren: () => import('./oss-friends/oss-friends-page.routes').then((m) => m.routes) }, { - path: publicRoutes.about.subRoutes.privacyPolicy.path, + path: publicRoutes.about.subRoutes?.privacyPolicy.path, loadChildren: () => import('./privacy-policy/privacy-policy-page.routes').then( (m) => m.routes ) }, { - path: publicRoutes.about.subRoutes.termsOfService.path, + path: publicRoutes.about.subRoutes?.termsOfService.path, loadChildren: () => import('./terms-of-service/terms-of-service-page.routes').then( (m) => m.routes diff --git a/apps/client/src/app/pages/about/changelog/changelog-page.component.ts b/apps/client/src/app/pages/about/changelog/changelog-page.component.ts index 69b397370..d7f583bd1 100644 --- a/apps/client/src/app/pages/about/changelog/changelog-page.component.ts +++ b/apps/client/src/app/pages/about/changelog/changelog-page.component.ts @@ -1,7 +1,6 @@ -import { Component, OnDestroy } from '@angular/core'; +import { Component } from '@angular/core'; import { MarkdownModule } from 'ngx-markdown'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; -import { Subject } from 'rxjs'; @Component({ imports: [MarkdownModule, NgxSkeletonLoaderModule], @@ -9,17 +8,10 @@ import { Subject } from 'rxjs'; styleUrls: ['./changelog-page.scss'], templateUrl: './changelog-page.html' }) -export class GfChangelogPageComponent implements OnDestroy { +export class GfChangelogPageComponent { public isLoading = true; - private unsubscribeSubject = new Subject(); - public onLoad() { this.isLoading = false; } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/about/changelog/changelog-page.routes.ts b/apps/client/src/app/pages/about/changelog/changelog-page.routes.ts index 523218acc..7b67283e9 100644 --- a/apps/client/src/app/pages/about/changelog/changelog-page.routes.ts +++ b/apps/client/src/app/pages/about/changelog/changelog-page.routes.ts @@ -10,6 +10,6 @@ export const routes: Routes = [ canActivate: [AuthGuard], component: GfChangelogPageComponent, path: '', - title: publicRoutes.about.subRoutes.changelog.title + title: publicRoutes.about.subRoutes?.changelog.title } ]; diff --git a/apps/client/src/app/pages/about/license/license-page.component.ts b/apps/client/src/app/pages/about/license/license-page.component.ts index 0dc5b2f51..d530d0418 100644 --- a/apps/client/src/app/pages/about/license/license-page.component.ts +++ b/apps/client/src/app/pages/about/license/license-page.component.ts @@ -1,6 +1,5 @@ -import { Component, OnDestroy } from '@angular/core'; +import { Component } from '@angular/core'; import { MarkdownModule } from 'ngx-markdown'; -import { Subject } from 'rxjs'; @Component({ imports: [MarkdownModule], @@ -8,11 +7,4 @@ import { Subject } from 'rxjs'; styleUrls: ['./license-page.scss'], templateUrl: './license-page.html' }) -export class GfLicensePageComponent implements OnDestroy { - private unsubscribeSubject = new Subject(); - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } -} +export class GfLicensePageComponent {} diff --git a/apps/client/src/app/pages/about/license/license-page.routes.ts b/apps/client/src/app/pages/about/license/license-page.routes.ts index 1684bb0c5..45de6aaa2 100644 --- a/apps/client/src/app/pages/about/license/license-page.routes.ts +++ b/apps/client/src/app/pages/about/license/license-page.routes.ts @@ -10,6 +10,6 @@ export const routes: Routes = [ canActivate: [AuthGuard], component: GfLicensePageComponent, path: '', - title: publicRoutes.about.subRoutes.license.title + title: publicRoutes.about.subRoutes?.license.title } ]; diff --git a/apps/client/src/app/pages/about/oss-friends/oss-friends-page.component.ts b/apps/client/src/app/pages/about/oss-friends/oss-friends-page.component.ts index bdbbdf9a7..c2e500a52 100644 --- a/apps/client/src/app/pages/about/oss-friends/oss-friends-page.component.ts +++ b/apps/client/src/app/pages/about/oss-friends/oss-friends-page.component.ts @@ -1,10 +1,9 @@ -import { Component, OnDestroy } from '@angular/core'; +import { Component } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; import { IonIcon } from '@ionic/angular/standalone'; import { addIcons } from 'ionicons'; import { arrowForwardOutline } from 'ionicons/icons'; -import { Subject } from 'rxjs'; const ossFriends = require('../../../../assets/oss-friends.json'); @@ -14,17 +13,10 @@ const ossFriends = require('../../../../assets/oss-friends.json'); styleUrls: ['./oss-friends-page.scss'], templateUrl: './oss-friends-page.html' }) -export class GfOpenSourceSoftwareFriendsPageComponent implements OnDestroy { +export class GfOpenSourceSoftwareFriendsPageComponent { public ossFriends = ossFriends.data; - private unsubscribeSubject = new Subject(); - public constructor() { addIcons({ arrowForwardOutline }); } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/about/oss-friends/oss-friends-page.routes.ts b/apps/client/src/app/pages/about/oss-friends/oss-friends-page.routes.ts index 8dbb9d52a..dfe65d962 100644 --- a/apps/client/src/app/pages/about/oss-friends/oss-friends-page.routes.ts +++ b/apps/client/src/app/pages/about/oss-friends/oss-friends-page.routes.ts @@ -10,6 +10,6 @@ export const routes: Routes = [ canActivate: [AuthGuard], component: GfOpenSourceSoftwareFriendsPageComponent, path: '', - title: publicRoutes.about.subRoutes.ossFriends.title + title: publicRoutes.about.subRoutes?.ossFriends.title } ]; 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 bea19a1b9..9c399762b 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 @@ -9,9 +9,10 @@ import { ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA, - OnDestroy, + DestroyRef, OnInit } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatButtonModule } from '@angular/material/button'; import { RouterModule } from '@angular/router'; import { IonIcon } from '@ionic/angular/standalone'; @@ -23,8 +24,6 @@ import { logoX, mail } from 'ionicons/icons'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; @Component({ imports: [CommonModule, IonIcon, MatButtonModule, RouterModule], @@ -33,7 +32,7 @@ import { takeUntil } from 'rxjs/operators'; styleUrls: ['./about-overview-page.scss'], templateUrl: './about-overview-page.html' }) -export class GfAboutOverviewPageComponent implements OnDestroy, OnInit { +export class GfAboutOverviewPageComponent implements OnInit { public hasPermissionForStatistics: boolean; public hasPermissionForSubscription: boolean; public isLoggedIn: boolean; @@ -43,11 +42,10 @@ export class GfAboutOverviewPageComponent implements OnDestroy, OnInit { public routerLinkOpenStartup = publicRoutes.openStartup.routerLink; public user: User; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private userService: UserService ) { const { globalPermissions } = this.dataService.fetchInfo(); @@ -67,7 +65,7 @@ export class GfAboutOverviewPageComponent implements OnDestroy, OnInit { public ngOnInit() { this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -76,9 +74,4 @@ export class GfAboutOverviewPageComponent implements OnDestroy, OnInit { } }); } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/about/privacy-policy/privacy-policy-page.component.ts b/apps/client/src/app/pages/about/privacy-policy/privacy-policy-page.component.ts index 78881cd2c..50e4e3e2f 100644 --- a/apps/client/src/app/pages/about/privacy-policy/privacy-policy-page.component.ts +++ b/apps/client/src/app/pages/about/privacy-policy/privacy-policy-page.component.ts @@ -1,6 +1,5 @@ -import { Component, OnDestroy } from '@angular/core'; +import { Component } from '@angular/core'; import { MarkdownModule } from 'ngx-markdown'; -import { Subject } from 'rxjs'; @Component({ imports: [MarkdownModule], @@ -8,11 +7,4 @@ import { Subject } from 'rxjs'; styleUrls: ['./privacy-policy-page.scss'], templateUrl: './privacy-policy-page.html' }) -export class GfPrivacyPolicyPageComponent implements OnDestroy { - private unsubscribeSubject = new Subject(); - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } -} +export class GfPrivacyPolicyPageComponent {} diff --git a/apps/client/src/app/pages/about/privacy-policy/privacy-policy-page.routes.ts b/apps/client/src/app/pages/about/privacy-policy/privacy-policy-page.routes.ts index e87436c17..934e06289 100644 --- a/apps/client/src/app/pages/about/privacy-policy/privacy-policy-page.routes.ts +++ b/apps/client/src/app/pages/about/privacy-policy/privacy-policy-page.routes.ts @@ -10,6 +10,6 @@ export const routes: Routes = [ canActivate: [AuthGuard], component: GfPrivacyPolicyPageComponent, path: '', - title: publicRoutes.about.subRoutes.privacyPolicy.title + title: publicRoutes.about.subRoutes?.privacyPolicy.title } ]; diff --git a/apps/client/src/app/pages/about/terms-of-service/terms-of-service-page.component.ts b/apps/client/src/app/pages/about/terms-of-service/terms-of-service-page.component.ts index dbf07ef19..7899f0187 100644 --- a/apps/client/src/app/pages/about/terms-of-service/terms-of-service-page.component.ts +++ b/apps/client/src/app/pages/about/terms-of-service/terms-of-service-page.component.ts @@ -1,6 +1,5 @@ -import { Component, OnDestroy } from '@angular/core'; +import { Component } from '@angular/core'; import { MarkdownModule } from 'ngx-markdown'; -import { Subject } from 'rxjs'; @Component({ imports: [MarkdownModule], @@ -8,11 +7,4 @@ import { Subject } from 'rxjs'; styleUrls: ['./terms-of-service-page.scss'], templateUrl: './terms-of-service-page.html' }) -export class GfTermsOfServicePageComponent implements OnDestroy { - private unsubscribeSubject = new Subject(); - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } -} +export class GfTermsOfServicePageComponent {} diff --git a/apps/client/src/app/pages/about/terms-of-service/terms-of-service-page.routes.ts b/apps/client/src/app/pages/about/terms-of-service/terms-of-service-page.routes.ts index 34d7a72d0..caf8751f1 100644 --- a/apps/client/src/app/pages/about/terms-of-service/terms-of-service-page.routes.ts +++ b/apps/client/src/app/pages/about/terms-of-service/terms-of-service-page.routes.ts @@ -10,6 +10,6 @@ export const routes: Routes = [ canActivate: [AuthGuard], component: GfTermsOfServicePageComponent, path: '', - title: publicRoutes.about.subRoutes.termsOfService.title + title: publicRoutes.about.subRoutes?.termsOfService.title } ]; 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 f7e6541b5..fdc78a8c4 100644 --- a/apps/client/src/app/pages/accounts/accounts-page.component.ts +++ b/apps/client/src/app/pages/accounts/accounts-page.component.ts @@ -13,7 +13,13 @@ import { GfAccountsTableComponent } from '@ghostfolio/ui/accounts-table'; import { NotificationService } from '@ghostfolio/ui/notifications'; import { DataService } from '@ghostfolio/ui/services'; -import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; +import { + ChangeDetectorRef, + Component, + DestroyRef, + OnInit +} from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatButtonModule } from '@angular/material/button'; import { MatDialog } from '@angular/material/dialog'; import { ActivatedRoute, Router, RouterModule } from '@angular/router'; @@ -21,8 +27,8 @@ import { Account as AccountModel } from '@prisma/client'; import { addIcons } from 'ionicons'; import { addOutline } from 'ionicons/icons'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { EMPTY, Subject, Subscription } from 'rxjs'; -import { catchError, takeUntil } from 'rxjs/operators'; +import { EMPTY, Subscription } from 'rxjs'; +import { catchError } from 'rxjs/operators'; import { GfCreateOrUpdateAccountDialogComponent } from './create-or-update-account-dialog/create-or-update-account-dialog.component'; import { CreateOrUpdateAccountDialogParams } from './create-or-update-account-dialog/interfaces/interfaces'; @@ -36,7 +42,7 @@ import { GfTransferBalanceDialogComponent } from './transfer-balance/transfer-ba styleUrls: ['./accounts-page.scss'], templateUrl: './accounts-page.html' }) -export class GfAccountsPageComponent implements OnDestroy, OnInit { +export class GfAccountsPageComponent implements OnInit { public accounts: AccountModel[]; public activitiesCount = 0; public deviceType: string; @@ -48,11 +54,10 @@ export class GfAccountsPageComponent implements OnDestroy, OnInit { public totalValueInBaseCurrency = 0; public user: User; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private dialog: MatDialog, private impersonationStorageService: ImpersonationStorageService, @@ -62,7 +67,7 @@ export class GfAccountsPageComponent implements OnDestroy, OnInit { private userService: UserService ) { this.route.queryParams - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((params) => { if (params['accountId'] && params['accountDetailDialog']) { this.openAccountDetailDialog(params['accountId']); @@ -94,13 +99,13 @@ export class GfAccountsPageComponent implements OnDestroy, OnInit { this.impersonationStorageService .onChangeHasImpersonation() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((impersonationId) => { this.hasImpersonationId = !!impersonationId; }); this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -124,7 +129,7 @@ export class GfAccountsPageComponent implements OnDestroy, OnInit { public fetchAccounts() { this.dataService .fetchAccounts() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe( ({ accounts, @@ -151,11 +156,11 @@ export class GfAccountsPageComponent implements OnDestroy, OnInit { this.dataService .deleteAccount(aId) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); this.fetchAccounts(); @@ -204,18 +209,18 @@ export class GfAccountsPageComponent implements OnDestroy, OnInit { dialogRef .afterClosed() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((account: UpdateAccountDto | null) => { if (account) { this.reset(); this.dataService .putAccount(account) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); this.fetchAccounts(); @@ -228,11 +233,6 @@ export class GfAccountsPageComponent implements OnDestroy, OnInit { }); } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private openAccountDetailDialog(aAccountId: string) { const dialogRef = this.dialog.open< GfAccountDetailDialogComponent, @@ -245,7 +245,7 @@ export class GfAccountsPageComponent implements OnDestroy, OnInit { hasImpersonationId: this.hasImpersonationId, hasPermissionToCreateActivity: !this.hasImpersonationId && - hasPermission(this.user?.permissions, permissions.createOrder) && + hasPermission(this.user?.permissions, permissions.createActivity) && !this.user?.settings?.isRestrictedView }, height: this.deviceType === 'mobile' ? '98vh' : '80vh', @@ -254,7 +254,7 @@ export class GfAccountsPageComponent implements OnDestroy, OnInit { dialogRef .afterClosed() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.fetchAccounts(); @@ -284,18 +284,18 @@ export class GfAccountsPageComponent implements OnDestroy, OnInit { dialogRef .afterClosed() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((account: CreateAccountDto | null) => { if (account) { this.reset(); this.dataService .postAccount(account) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); this.fetchAccounts(); @@ -321,7 +321,7 @@ export class GfAccountsPageComponent implements OnDestroy, OnInit { dialogRef .afterClosed() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((data: any) => { if (data) { this.reset(); @@ -343,7 +343,7 @@ export class GfAccountsPageComponent implements OnDestroy, OnInit { return EMPTY; }), - takeUntil(this.unsubscribeSubject) + takeUntilDestroyed(this.destroyRef) ) .subscribe(() => { this.fetchAccounts(); diff --git a/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.component.ts b/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.component.ts index f4c68e70f..6cdd18251 100644 --- a/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.component.ts +++ b/apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.component.ts @@ -5,12 +5,7 @@ import { GfEntityLogoComponent } from '@ghostfolio/ui/entity-logo'; import { DataService } from '@ghostfolio/ui/services'; import { CommonModule, NgClass } from '@angular/common'; -import { - ChangeDetectionStrategy, - Component, - Inject, - OnDestroy -} from '@angular/core'; +import { ChangeDetectionStrategy, Component, Inject } from '@angular/core'; import { AbstractControl, FormBuilder, @@ -30,7 +25,7 @@ import { import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; import { Platform } from '@prisma/client'; -import { Observable, Subject } from 'rxjs'; +import { Observable } from 'rxjs'; import { map, startWith } from 'rxjs/operators'; import { CreateOrUpdateAccountDialogParams } from './interfaces/interfaces'; @@ -55,14 +50,12 @@ import { CreateOrUpdateAccountDialogParams } from './interfaces/interfaces'; styleUrls: ['./create-or-update-account-dialog.scss'], templateUrl: 'create-or-update-account-dialog.html' }) -export class GfCreateOrUpdateAccountDialogComponent implements OnDestroy { +export class GfCreateOrUpdateAccountDialogComponent { public accountForm: FormGroup; public currencies: string[] = []; public filteredPlatforms: Observable; public platforms: Platform[] = []; - private unsubscribeSubject = new Subject(); - public constructor( @Inject(MAT_DIALOG_DATA) public data: CreateOrUpdateAccountDialogParams, private dataService: DataService, @@ -170,11 +163,6 @@ export class GfCreateOrUpdateAccountDialogComponent implements OnDestroy { } } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private autocompleteObjectValidator(): ValidatorFn { return (control: AbstractControl) => { if (control.value && typeof control.value === 'string') { diff --git a/apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.component.ts b/apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.component.ts index 85d2e60bf..34a66b156 100644 --- a/apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.component.ts +++ b/apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.component.ts @@ -1,12 +1,7 @@ import { TransferBalanceDto } from '@ghostfolio/common/dtos'; import { GfEntityLogoComponent } from '@ghostfolio/ui/entity-logo'; -import { - ChangeDetectionStrategy, - Component, - Inject, - OnDestroy -} from '@angular/core'; +import { ChangeDetectionStrategy, Component, Inject } from '@angular/core'; import { AbstractControl, FormBuilder, @@ -25,7 +20,6 @@ import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; import { MatSelectModule } from '@angular/material/select'; import { Account } from '@prisma/client'; -import { Subject } from 'rxjs'; import { TransferBalanceDialogParams } from './interfaces/interfaces'; @@ -45,13 +39,11 @@ import { TransferBalanceDialogParams } from './interfaces/interfaces'; styleUrls: ['./transfer-balance-dialog.scss'], templateUrl: 'transfer-balance-dialog.html' }) -export class GfTransferBalanceDialogComponent implements OnDestroy { +export class GfTransferBalanceDialogComponent { public accounts: Account[] = []; public currency: string; public transferBalanceForm: FormGroup; - private unsubscribeSubject = new Subject(); - public constructor( @Inject(MAT_DIALOG_DATA) public data: TransferBalanceDialogParams, public dialogRef: MatDialogRef, @@ -93,11 +85,6 @@ export class GfTransferBalanceDialogComponent implements OnDestroy { this.dialogRef.close({ account }); } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private compareAccounts(control: AbstractControl): ValidationErrors { const accountFrom = control.get('fromAccount'); const accountTo = control.get('toAccount'); diff --git a/apps/client/src/app/pages/admin/admin-page.component.ts b/apps/client/src/app/pages/admin/admin-page.component.ts index b9243dcb9..284d3c41d 100644 --- a/apps/client/src/app/pages/admin/admin-page.component.ts +++ b/apps/client/src/app/pages/admin/admin-page.component.ts @@ -1,7 +1,7 @@ import { TabConfiguration } from '@ghostfolio/common/interfaces'; import { internalRoutes } from '@ghostfolio/common/routes/routes'; -import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { MatTabsModule } from '@angular/material/tabs'; import { RouterModule } from '@angular/router'; import { IonIcon } from '@ionic/angular/standalone'; @@ -14,7 +14,6 @@ import { settingsOutline } from 'ionicons/icons'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject } from 'rxjs'; @Component({ host: { class: 'page has-tabs' }, @@ -23,12 +22,10 @@ import { Subject } from 'rxjs'; styleUrls: ['./admin-page.scss'], templateUrl: './admin-page.html' }) -export class AdminPageComponent implements OnDestroy, OnInit { +export class AdminPageComponent implements OnInit { public deviceType: string; public tabs: TabConfiguration[] = []; - private unsubscribeSubject = new Subject(); - public constructor(private deviceService: DeviceDetectorService) { addIcons({ flashOutline, @@ -74,9 +71,4 @@ export class AdminPageComponent implements OnDestroy, OnInit { } ]; } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/admin/admin-page.routes.ts b/apps/client/src/app/pages/admin/admin-page.routes.ts index c5309edbb..08fce248c 100644 --- a/apps/client/src/app/pages/admin/admin-page.routes.ts +++ b/apps/client/src/app/pages/admin/admin-page.routes.ts @@ -20,29 +20,29 @@ export const routes: Routes = [ title: internalRoutes.adminControl.title }, { - path: internalRoutes.adminControl.subRoutes.jobs.path, + path: internalRoutes.adminControl.subRoutes?.jobs.path, component: GfAdminJobsComponent, - title: internalRoutes.adminControl.subRoutes.jobs.title + title: internalRoutes.adminControl.subRoutes?.jobs.title }, { - path: internalRoutes.adminControl.subRoutes.marketData.path, + path: internalRoutes.adminControl.subRoutes?.marketData.path, component: GfAdminMarketDataComponent, - title: internalRoutes.adminControl.subRoutes.marketData.title + title: internalRoutes.adminControl.subRoutes?.marketData.title }, { - path: internalRoutes.adminControl.subRoutes.settings.path, + path: internalRoutes.adminControl.subRoutes?.settings.path, component: GfAdminSettingsComponent, - title: internalRoutes.adminControl.subRoutes.settings.title + title: internalRoutes.adminControl.subRoutes?.settings.title }, { - path: internalRoutes.adminControl.subRoutes.users.path, + path: internalRoutes.adminControl.subRoutes?.users.path, component: GfAdminUsersComponent, - title: internalRoutes.adminControl.subRoutes.users.title + title: internalRoutes.adminControl.subRoutes?.users.title }, { - path: `${internalRoutes.adminControl.subRoutes.users.path}/:userId`, + path: `${internalRoutes.adminControl.subRoutes?.users.path}/:userId`, component: GfAdminUsersComponent, - title: internalRoutes.adminControl.subRoutes.users.title + title: internalRoutes.adminControl.subRoutes?.users.title } ], component: AdminPageComponent, diff --git a/apps/client/src/app/pages/auth/auth-page.component.ts b/apps/client/src/app/pages/auth/auth-page.component.ts index 082401d6d..1b0b4a67c 100644 --- a/apps/client/src/app/pages/auth/auth-page.component.ts +++ b/apps/client/src/app/pages/auth/auth-page.component.ts @@ -4,20 +4,18 @@ import { } from '@ghostfolio/client/services/settings-storage.service'; import { TokenStorageService } from '@ghostfolio/client/services/token-storage.service'; -import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Component, DestroyRef, OnInit } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { ActivatedRoute, Router } from '@angular/router'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'gf-auth-page', styleUrls: ['./auth-page.scss'], templateUrl: './auth-page.html' }) -export class GfAuthPageComponent implements OnDestroy, OnInit { - private unsubscribeSubject = new Subject(); - +export class GfAuthPageComponent implements OnInit { public constructor( + private destroyRef: DestroyRef, private route: ActivatedRoute, private router: Router, private settingsStorageService: SettingsStorageService, @@ -26,7 +24,7 @@ export class GfAuthPageComponent implements OnDestroy, OnInit { public ngOnInit() { this.route.params - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((params) => { const jwt = params['jwt']; @@ -38,9 +36,4 @@ export class GfAuthPageComponent implements OnDestroy, OnInit { this.router.navigate(['/']); }); } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } 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 c5a9cf178..4b62e4449 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 @@ -12,6 +12,6 @@ import { RouterModule } from '@angular/router'; }) export class GhostfolioJoinsOssFriendsPageComponent { public routerLinkAboutOssFriends = - publicRoutes.about.subRoutes.ossFriends.routerLink; + publicRoutes.about.subRoutes?.ossFriends.routerLink; public routerLinkBlog = publicRoutes.blog.routerLink; } diff --git a/apps/client/src/app/pages/blog/blog-page.component.ts b/apps/client/src/app/pages/blog/blog-page.component.ts index 8a379a7e4..7f2c56d2d 100644 --- a/apps/client/src/app/pages/blog/blog-page.component.ts +++ b/apps/client/src/app/pages/blog/blog-page.component.ts @@ -1,13 +1,12 @@ import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { DataService } from '@ghostfolio/ui/services'; -import { Component, CUSTOM_ELEMENTS_SCHEMA, OnDestroy } from '@angular/core'; +import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { MatCardModule } from '@angular/material/card'; import { RouterModule } from '@angular/router'; import { IonIcon } from '@ionic/angular/standalone'; import { addIcons } from 'ionicons'; import { chevronForwardOutline } from 'ionicons/icons'; -import { Subject } from 'rxjs'; @Component({ host: { class: 'page' }, @@ -17,11 +16,9 @@ import { Subject } from 'rxjs'; styleUrls: ['./blog-page.scss'], templateUrl: './blog-page.html' }) -export class GfBlogPageComponent implements OnDestroy { +export class GfBlogPageComponent { public hasPermissionForSubscription: boolean; - private unsubscribeSubject = new Subject(); - public constructor(private dataService: DataService) { const info = this.dataService.fetchInfo(); @@ -32,9 +29,4 @@ export class GfBlogPageComponent implements OnDestroy { addIcons({ chevronForwardOutline }); } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/demo/demo-page.component.ts b/apps/client/src/app/pages/demo/demo-page.component.ts index 5b94fd541..235805dcc 100644 --- a/apps/client/src/app/pages/demo/demo-page.component.ts +++ b/apps/client/src/app/pages/demo/demo-page.component.ts @@ -3,9 +3,8 @@ import { InfoItem } from '@ghostfolio/common/interfaces'; import { NotificationService } from '@ghostfolio/ui/notifications'; import { DataService } from '@ghostfolio/ui/services'; -import { Component, OnDestroy } from '@angular/core'; +import { Component } from '@angular/core'; import { Router } from '@angular/router'; -import { Subject } from 'rxjs'; @Component({ host: { class: 'page' }, @@ -13,11 +12,9 @@ import { Subject } from 'rxjs'; standalone: true, templateUrl: './demo-page.html' }) -export class GfDemoPageComponent implements OnDestroy { +export class GfDemoPageComponent { public info: InfoItem; - private unsubscribeSubject = new Subject(); - public constructor( private dataService: DataService, private notificationService: NotificationService, @@ -40,9 +37,4 @@ export class GfDemoPageComponent implements OnDestroy { this.router.navigate(['/']); } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/faq/faq-page.component.ts b/apps/client/src/app/pages/faq/faq-page.component.ts index caf4217ca..83171254a 100644 --- a/apps/client/src/app/pages/faq/faq-page.component.ts +++ b/apps/client/src/app/pages/faq/faq-page.component.ts @@ -3,19 +3,13 @@ import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { publicRoutes } from '@ghostfolio/common/routes/routes'; import { DataService } from '@ghostfolio/ui/services'; -import { - CUSTOM_ELEMENTS_SCHEMA, - Component, - OnDestroy, - OnInit -} from '@angular/core'; +import { CUSTOM_ELEMENTS_SCHEMA, Component, OnInit } from '@angular/core'; import { MatTabsModule } from '@angular/material/tabs'; import { RouterModule } from '@angular/router'; import { IonIcon } from '@ionic/angular/standalone'; import { addIcons } from 'ionicons'; import { cloudyOutline, readerOutline, serverOutline } from 'ionicons/icons'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject } from 'rxjs'; @Component({ host: { class: 'page has-tabs' }, @@ -25,13 +19,11 @@ import { Subject } from 'rxjs'; styleUrls: ['./faq-page.scss'], templateUrl: './faq-page.html' }) -export class GfFaqPageComponent implements OnDestroy, OnInit { +export class GfFaqPageComponent implements OnInit { public deviceType: string; public hasPermissionForSubscription: boolean; public tabs: TabConfiguration[] = []; - private unsubscribeSubject = new Subject(); - public constructor( private dataService: DataService, private deviceService: DeviceDetectorService @@ -68,9 +60,4 @@ export class GfFaqPageComponent implements OnDestroy, OnInit { public ngOnInit() { this.deviceType = this.deviceService.getDeviceInfo().deviceType; } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/faq/faq-page.routes.ts b/apps/client/src/app/pages/faq/faq-page.routes.ts index 2999e3c80..f80304a08 100644 --- a/apps/client/src/app/pages/faq/faq-page.routes.ts +++ b/apps/client/src/app/pages/faq/faq-page.routes.ts @@ -15,12 +15,12 @@ export const routes: Routes = [ import('./overview/faq-overview-page.routes').then((m) => m.routes) }, { - path: publicRoutes.faq.subRoutes.saas.path, + path: publicRoutes.faq.subRoutes?.saas.path, loadChildren: () => import('./saas/saas-page.routes').then((m) => m.routes) }, { - path: publicRoutes.faq.subRoutes.selfHosting.path, + path: publicRoutes.faq.subRoutes?.selfHosting.path, loadChildren: () => import('./self-hosting/self-hosting-page.routes').then( (m) => m.routes 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 b47d45fe2..4429fe492 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 @@ -25,7 +25,7 @@ export class GfSaasPageComponent implements OnDestroy { public pricingUrl = `https://ghostfol.io/${document.documentElement.lang}/${publicRoutes.pricing.path}`; public routerLinkAccount = internalRoutes.account.routerLink; public routerLinkAccountMembership = - internalRoutes.account.subRoutes.membership.routerLink; + internalRoutes.account.subRoutes?.membership.routerLink; public routerLinkMarkets = publicRoutes.markets.routerLink; public routerLinkRegister = publicRoutes.register.routerLink; public user: User; diff --git a/apps/client/src/app/pages/faq/saas/saas-page.routes.ts b/apps/client/src/app/pages/faq/saas/saas-page.routes.ts index dcb574c38..d68893640 100644 --- a/apps/client/src/app/pages/faq/saas/saas-page.routes.ts +++ b/apps/client/src/app/pages/faq/saas/saas-page.routes.ts @@ -10,6 +10,6 @@ export const routes: Routes = [ canActivate: [AuthGuard], component: GfSaasPageComponent, path: '', - title: `${publicRoutes.faq.subRoutes.saas.title} - ${publicRoutes.faq.title}` + title: `${publicRoutes.faq.subRoutes?.saas.title} - ${publicRoutes.faq.title}` } ]; diff --git a/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.component.ts b/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.component.ts index ed1d74395..f2468c7d4 100644 --- a/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.component.ts +++ b/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.component.ts @@ -1,10 +1,9 @@ import { publicRoutes } from '@ghostfolio/common/routes/routes'; import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator'; -import { CUSTOM_ELEMENTS_SCHEMA, Component, OnDestroy } from '@angular/core'; +import { CUSTOM_ELEMENTS_SCHEMA, Component } from '@angular/core'; import { MatCardModule } from '@angular/material/card'; import { RouterModule } from '@angular/router'; -import { Subject } from 'rxjs'; @Component({ host: { class: 'page' }, @@ -14,13 +13,6 @@ import { Subject } from 'rxjs'; styleUrls: ['./self-hosting-page.scss'], templateUrl: './self-hosting-page.html' }) -export class GfSelfHostingPageComponent implements OnDestroy { +export class GfSelfHostingPageComponent { public pricingUrl = `https://ghostfol.io/${document.documentElement.lang}/${publicRoutes.pricing.path}`; - - private unsubscribeSubject = new Subject(); - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.html b/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.html index 42e810eb0..ef88df9aa 100644 --- a/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.html +++ b/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.html @@ -93,6 +93,10 @@ dialog +

+ For derived currencies (e.g. GBp), ensure that you + gather the data for the parent currency (e.g. GBP). +

diff --git a/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.routes.ts b/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.routes.ts index d08cdb312..ccf034421 100644 --- a/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.routes.ts +++ b/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.routes.ts @@ -10,6 +10,6 @@ export const routes: Routes = [ canActivate: [AuthGuard], component: GfSelfHostingPageComponent, path: '', - title: `${publicRoutes.faq.subRoutes.selfHosting.title} - ${publicRoutes.faq.title}` + title: `${publicRoutes.faq.subRoutes?.selfHosting.title} - ${publicRoutes.faq.title}` } ]; 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 b9eb91fe2..cef90f2e5 100644 --- a/apps/client/src/app/pages/features/features-page.component.ts +++ b/apps/client/src/app/pages/features/features-page.component.ts @@ -5,11 +5,11 @@ import { publicRoutes } from '@ghostfolio/common/routes/routes'; import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator'; import { DataService } from '@ghostfolio/ui/services'; -import { ChangeDetectorRef, Component, OnDestroy } from '@angular/core'; +import { ChangeDetectorRef, Component, DestroyRef } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; import { RouterModule } from '@angular/router'; -import { Subject, takeUntil } from 'rxjs'; @Component({ host: { class: 'page' }, @@ -23,7 +23,7 @@ import { Subject, takeUntil } from 'rxjs'; styleUrls: ['./features-page.scss'], templateUrl: './features-page.html' }) -export class GfFeaturesPageComponent implements OnDestroy { +export class GfFeaturesPageComponent { public hasPermissionForSubscription: boolean; public hasPermissionToCreateUser: boolean; public info: InfoItem; @@ -31,11 +31,10 @@ export class GfFeaturesPageComponent implements OnDestroy { public routerLinkResources = publicRoutes.resources.routerLink; public user: User; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private userService: UserService ) { this.info = this.dataService.fetchInfo(); @@ -43,7 +42,7 @@ export class GfFeaturesPageComponent implements OnDestroy { public ngOnInit() { this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -62,9 +61,4 @@ export class GfFeaturesPageComponent implements OnDestroy { permissions.createUserAccount ); } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/home/home-page.component.ts b/apps/client/src/app/pages/home/home-page.component.ts index fd860ced5..5130c8166 100644 --- a/apps/client/src/app/pages/home/home-page.component.ts +++ b/apps/client/src/app/pages/home/home-page.component.ts @@ -8,9 +8,10 @@ import { ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA, - OnDestroy, + DestroyRef, OnInit } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatTabsModule } from '@angular/material/tabs'; import { RouterModule } from '@angular/router'; import { IonIcon } from '@ionic/angular/standalone'; @@ -23,8 +24,6 @@ import { readerOutline } from 'ionicons/icons'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; @Component({ host: { class: 'page has-tabs' }, @@ -34,22 +33,21 @@ import { takeUntil } from 'rxjs/operators'; styleUrls: ['./home-page.scss'], templateUrl: './home-page.html' }) -export class GfHomePageComponent implements OnDestroy, OnInit { +export class GfHomePageComponent implements OnInit { public deviceType: string; public hasImpersonationId: boolean; public tabs: TabConfiguration[] = []; public user: User; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private impersonationStorageService: ImpersonationStorageService, private userService: UserService ) { this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -110,14 +108,9 @@ export class GfHomePageComponent implements OnDestroy, OnInit { this.impersonationStorageService .onChangeHasImpersonation() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((impersonationId) => { this.hasImpersonationId = !!impersonationId; }); } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/home/home-page.routes.ts b/apps/client/src/app/pages/home/home-page.routes.ts index 82ef1e521..436826674 100644 --- a/apps/client/src/app/pages/home/home-page.routes.ts +++ b/apps/client/src/app/pages/home/home-page.routes.ts @@ -20,29 +20,29 @@ export const routes: Routes = [ component: GfHomeOverviewComponent }, { - path: internalRoutes.home.subRoutes.holdings.path, + path: internalRoutes.home.subRoutes?.holdings.path, component: GfHomeHoldingsComponent, - title: internalRoutes.home.subRoutes.holdings.title + title: internalRoutes.home.subRoutes?.holdings.title }, { - path: internalRoutes.home.subRoutes.summary.path, + path: internalRoutes.home.subRoutes?.summary.path, component: GfHomeSummaryComponent, - title: internalRoutes.home.subRoutes.summary.title + title: internalRoutes.home.subRoutes?.summary.title }, { - path: internalRoutes.home.subRoutes.markets.path, + path: internalRoutes.home.subRoutes?.markets.path, component: GfHomeMarketComponent, - title: internalRoutes.home.subRoutes.markets.title + title: internalRoutes.home.subRoutes?.markets.title }, { - path: internalRoutes.home.subRoutes.marketsPremium.path, + path: internalRoutes.home.subRoutes?.marketsPremium.path, component: GfMarketsComponent, - title: internalRoutes.home.subRoutes.marketsPremium.title + title: internalRoutes.home.subRoutes?.marketsPremium.title }, { - path: internalRoutes.home.subRoutes.watchlist.path, + path: internalRoutes.home.subRoutes?.watchlist.path, component: GfHomeWatchlistComponent, - title: internalRoutes.home.subRoutes.watchlist.title + title: internalRoutes.home.subRoutes?.watchlist.title } ], component: GfHomePageComponent, diff --git a/apps/client/src/app/pages/i18n/i18n-page.component.ts b/apps/client/src/app/pages/i18n/i18n-page.component.ts index 19ecd222e..76d123914 100644 --- a/apps/client/src/app/pages/i18n/i18n-page.component.ts +++ b/apps/client/src/app/pages/i18n/i18n-page.component.ts @@ -1,5 +1,4 @@ import { Component } from '@angular/core'; -import { Subject } from 'rxjs'; @Component({ host: { class: 'page' }, @@ -8,11 +7,4 @@ import { Subject } from 'rxjs'; styleUrls: ['./i18n-page.scss'], templateUrl: './i18n-page.html' }) -export class GfI18nPageComponent { - private unsubscribeSubject = new Subject(); - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } -} +export class GfI18nPageComponent {} diff --git a/apps/client/src/app/pages/i18n/i18n-page.html b/apps/client/src/app/pages/i18n/i18n-page.html index b4297d5ac..99ef3039e 100644 --- a/apps/client/src/app/pages/i18n/i18n-page.html +++ b/apps/client/src/app/pages/i18n/i18n-page.html @@ -149,14 +149,14 @@
  • An emergency fund has been set up
  • -
  • Fee Ratio
  • -
  • - The fees do exceed ${thresholdMax}% of your initial investment - (${feeRatio}%) -
  • -
  • - The fees do not exceed ${thresholdMax}% of your initial - investment (${feeRatio}%) +
  • Fee Ratio
  • +
  • + The fees do exceed ${thresholdMax}% of your total investment + volume (${feeRatio}%) +
  • +
  • + The fees do not exceed ${thresholdMax}% of your total + investment volume (${feeRatio}%)
  • Fees
  • 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 25fb2d6e7..9ee9cceb4 100644 --- a/apps/client/src/app/pages/landing/landing-page.component.ts +++ b/apps/client/src/app/pages/landing/landing-page.component.ts @@ -9,7 +9,7 @@ import { GfValueComponent } from '@ghostfolio/ui/value'; import { GfWorldMapChartComponent } from '@ghostfolio/ui/world-map-chart'; import { CommonModule } from '@angular/common'; -import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; import { RouterModule } from '@angular/router'; @@ -21,7 +21,6 @@ import { starOutline } from 'ionicons/icons'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject } from 'rxjs'; @Component({ host: { class: 'page' }, @@ -40,7 +39,7 @@ import { Subject } from 'rxjs'; styleUrls: ['./landing-page.scss'], templateUrl: './landing-page.html' }) -export class GfLandingPageComponent implements OnDestroy, OnInit { +export class GfLandingPageComponent implements OnInit { public countriesOfSubscribersMap: { [code: string]: { value: number }; } = {}; @@ -107,8 +106,6 @@ export class GfLandingPageComponent implements OnDestroy, OnInit { } ]; - private unsubscribeSubject = new Subject(); - public constructor( private dataService: DataService, private deviceService: DeviceDetectorService @@ -155,9 +152,4 @@ export class GfLandingPageComponent implements OnDestroy, OnInit { public ngOnInit() { this.deviceType = this.deviceService.getDeviceInfo().deviceType; } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/open/open-page.component.ts b/apps/client/src/app/pages/open/open-page.component.ts index 6284c41f4..090588d7d 100644 --- a/apps/client/src/app/pages/open/open-page.component.ts +++ b/apps/client/src/app/pages/open/open-page.component.ts @@ -7,11 +7,11 @@ import { ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA, - OnDestroy, + DestroyRef, OnInit } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatCardModule } from '@angular/material/card'; -import { Subject, takeUntil } from 'rxjs'; @Component({ host: { class: 'page' }, @@ -21,15 +21,14 @@ import { Subject, takeUntil } from 'rxjs'; styleUrls: ['./open-page.scss'], templateUrl: './open-page.html' }) -export class GfOpenPageComponent implements OnDestroy, OnInit { +export class GfOpenPageComponent implements OnInit { public statistics: Statistics; public user: User; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private userService: UserService ) { const { statistics } = this.dataService.fetchInfo(); @@ -39,7 +38,7 @@ export class GfOpenPageComponent implements OnDestroy, OnInit { public ngOnInit() { this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -48,9 +47,4 @@ export class GfOpenPageComponent implements OnDestroy, OnInit { } }); } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } 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 cf7a41215..b9dc9077c 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 @@ -10,10 +10,17 @@ import { User } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; +import { DateRange } from '@ghostfolio/common/types'; import { GfActivitiesTableComponent } from '@ghostfolio/ui/activities-table'; import { DataService } from '@ghostfolio/ui/services'; -import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; +import { + ChangeDetectorRef, + Component, + DestroyRef, + OnInit +} from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatButtonModule } from '@angular/material/button'; import { MatDialog } from '@angular/material/dialog'; import { PageEvent } from '@angular/material/paginator'; @@ -26,8 +33,7 @@ import { format, parseISO } from 'date-fns'; import { addIcons } from 'ionicons'; import { addOutline } from 'ionicons/icons'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject, Subscription } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; +import { Subscription } from 'rxjs'; import { GfCreateOrUpdateActivityDialogComponent } from './create-or-update-activity-dialog/create-or-update-activity-dialog.component'; import { CreateOrUpdateActivityDialogParams } from './create-or-update-activity-dialog/interfaces/interfaces'; @@ -47,7 +53,7 @@ import { ImportActivitiesDialogParams } from './import-activities-dialog/interfa styleUrls: ['./activities-page.scss'], templateUrl: './activities-page.html' }) -export class GfActivitiesPageComponent implements OnDestroy, OnInit { +export class GfActivitiesPageComponent implements OnInit { public dataSource: MatTableDataSource; public deviceType: string; public hasImpersonationId: boolean; @@ -61,11 +67,10 @@ export class GfActivitiesPageComponent implements OnDestroy, OnInit { public totalItems: number; public user: User; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private dialog: MatDialog, private icsService: IcsService, @@ -75,13 +80,13 @@ export class GfActivitiesPageComponent implements OnDestroy, OnInit { private userService: UserService ) { this.routeQueryParams = route.queryParams - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((params) => { if (params['createDialog']) { if (params['activityId']) { this.dataService .fetchActivity(params['activityId']) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((activity) => { this.openCreateActivityDialog(activity); }); @@ -92,7 +97,7 @@ export class GfActivitiesPageComponent implements OnDestroy, OnInit { if (params['activityId']) { this.dataService .fetchActivity(params['activityId']) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((activity) => { this.openUpdateActivityDialog(activity); }); @@ -110,13 +115,13 @@ export class GfActivitiesPageComponent implements OnDestroy, OnInit { this.impersonationStorageService .onChangeHasImpersonation() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((impersonationId) => { this.hasImpersonationId = !!impersonationId; }); this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.updateUser(state.user); @@ -129,15 +134,20 @@ export class GfActivitiesPageComponent implements OnDestroy, OnInit { } public fetchActivities() { + const dateRange = this.user?.settings?.dateRange; + + const range = this.isCalendarYear(dateRange) ? dateRange : undefined; + this.dataService .fetchActivities({ + range, filters: this.userService.getFilters(), skip: this.pageIndex * this.pageSize, sortColumn: this.sortColumn, sortDirection: this.sortDirection, take: this.pageSize }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ activities, count }) => { this.dataSource = new MatTableDataSource(activities); this.totalItems = count; @@ -178,11 +188,11 @@ export class GfActivitiesPageComponent implements OnDestroy, OnInit { .deleteActivities({ filters: this.userService.getFilters() }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); this.fetchActivities(); @@ -192,11 +202,11 @@ export class GfActivitiesPageComponent implements OnDestroy, OnInit { public onDeleteActivity(aId: string) { this.dataService .deleteActivity(aId) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); this.fetchActivities(); @@ -212,7 +222,7 @@ export class GfActivitiesPageComponent implements OnDestroy, OnInit { this.dataService .fetchExport(fetchExportParams) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((data) => { for (const activity of data.activities) { delete activity.id; @@ -232,7 +242,7 @@ export class GfActivitiesPageComponent implements OnDestroy, OnInit { public onExportDrafts(activityIds?: string[]) { this.dataService .fetchExport({ activityIds }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((data) => { downloadAsFile({ content: this.icsService.transformActivitiesToIcsContent( @@ -262,11 +272,11 @@ export class GfActivitiesPageComponent implements OnDestroy, OnInit { dialogRef .afterClosed() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); this.fetchActivities(); @@ -289,11 +299,11 @@ export class GfActivitiesPageComponent implements OnDestroy, OnInit { dialogRef .afterClosed() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); this.fetchActivities(); @@ -330,12 +340,12 @@ export class GfActivitiesPageComponent implements OnDestroy, OnInit { dialogRef .afterClosed() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((activity: UpdateOrderDto) => { if (activity) { this.dataService - .putOrder(activity) - .pipe(takeUntil(this.unsubscribeSubject)) + .putActivity(activity) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe({ next: () => { this.fetchActivities(); @@ -347,15 +357,18 @@ export class GfActivitiesPageComponent implements OnDestroy, OnInit { }); } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); + private isCalendarYear(dateRange: DateRange) { + if (!dateRange) { + return false; + } + + return /^\d{4}$/.test(dateRange); } private openCreateActivityDialog(aActivity?: Activity) { this.userService .get() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((user) => { this.updateUser(user); @@ -382,14 +395,14 @@ export class GfActivitiesPageComponent implements OnDestroy, OnInit { dialogRef .afterClosed() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((transaction: CreateOrderDto | null) => { if (transaction) { - this.dataService.postOrder(transaction).subscribe({ + this.dataService.postActivity(transaction).subscribe({ next: () => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); this.fetchActivities(); @@ -407,9 +420,9 @@ export class GfActivitiesPageComponent implements OnDestroy, OnInit { this.hasPermissionToCreateActivity = !this.hasImpersonationId && - hasPermission(this.user.permissions, permissions.createOrder); + hasPermission(this.user.permissions, permissions.createActivity); this.hasPermissionToDeleteActivity = !this.hasImpersonationId && - hasPermission(this.user.permissions, permissions.deleteOrder); + hasPermission(this.user.permissions, permissions.deleteActivity); } } diff --git a/apps/client/src/app/pages/portfolio/activities/activities-page.routes.ts b/apps/client/src/app/pages/portfolio/activities/activities-page.routes.ts index c96c8a558..e1c75f6cc 100644 --- a/apps/client/src/app/pages/portfolio/activities/activities-page.routes.ts +++ b/apps/client/src/app/pages/portfolio/activities/activities-page.routes.ts @@ -10,6 +10,6 @@ export const routes: Routes = [ canActivate: [AuthGuard], component: GfActivitiesPageComponent, path: '', - title: internalRoutes.portfolio.subRoutes.activities.title + title: internalRoutes.portfolio.subRoutes?.activities.title } ]; diff --git a/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts b/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts index 8695f04ed..9cc312b25 100644 --- a/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts +++ b/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts @@ -20,9 +20,10 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, - Inject, - OnDestroy + DestroyRef, + Inject } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { FormBuilder, FormGroup, @@ -46,8 +47,8 @@ import { AssetClass, Tag, Type } from '@prisma/client'; import { isAfter, isToday } from 'date-fns'; import { addIcons } from 'ionicons'; import { calendarClearOutline, refreshOutline } from 'ionicons/icons'; -import { EMPTY, Subject } from 'rxjs'; -import { catchError, delay, takeUntil } from 'rxjs/operators'; +import { EMPTY } from 'rxjs'; +import { catchError, delay } from 'rxjs/operators'; import { CreateOrUpdateActivityDialogParams } from './interfaces/interfaces'; import { ActivityType } from './types/activity-type.type'; @@ -75,7 +76,7 @@ import { ActivityType } from './types/activity-type.type'; styleUrls: ['./create-or-update-activity-dialog.scss'], templateUrl: 'create-or-update-activity-dialog.html' }) -export class GfCreateOrUpdateActivityDialogComponent implements OnDestroy { +export class GfCreateOrUpdateActivityDialogComponent { public activityForm: FormGroup; public assetClassOptions: AssetClassSelectorOption[] = Object.keys(AssetClass) @@ -101,13 +102,12 @@ export class GfCreateOrUpdateActivityDialogComponent implements OnDestroy { public typesTranslationMap = new Map(); public Validators = Validators; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, @Inject(MAT_DIALOG_DATA) public data: CreateOrUpdateActivityDialogParams, private dataService: DataService, private dateAdapter: DateAdapter, + private destroyRef: DestroyRef, public dialogRef: MatDialogRef, private formBuilder: FormBuilder, @Inject(MAT_DATE_LOCALE) private locale: string, @@ -133,7 +133,7 @@ export class GfCreateOrUpdateActivityDialogComponent implements OnDestroy { this.dataService .fetchPortfolioHoldings() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ holdings }) => { this.defaultLookupItems = holdings .filter(({ assetSubClass }) => { @@ -188,8 +188,7 @@ export class GfCreateOrUpdateActivityDialogComponent implements OnDestroy { !this.data.activity?.accountId && this.mode === 'create' ? this.data.accounts[0].id - : this.data.activity?.accountId, - Validators.required + : this.data.activity?.accountId ], assetClass: [this.data.activity?.SymbolProfile?.assetClass], assetSubClass: [this.data.activity?.SymbolProfile?.assetSubClass], @@ -238,7 +237,7 @@ export class GfCreateOrUpdateActivityDialogComponent implements OnDestroy { // Slightly delay until the more specific form control value changes have // completed delay(300), - takeUntil(this.unsubscribeSubject) + takeUntilDestroyed(this.destroyRef) ) .subscribe(async () => { if ( @@ -285,7 +284,7 @@ export class GfCreateOrUpdateActivityDialogComponent implements OnDestroy { this.activityForm .get('assetClass') - .valueChanges.pipe(takeUntil(this.unsubscribeSubject)) + .valueChanges.pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((assetClass) => { const assetSubClasses = ASSET_CLASS_MAPPING.get(assetClass) ?? []; @@ -336,7 +335,7 @@ export class GfCreateOrUpdateActivityDialogComponent implements OnDestroy { if (newTag && this.hasPermissionToCreateOwnTag) { this.dataService .postTag({ ...newTag, userId: this.data.user.id }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((tag) => { this.activityForm.get('tags').setValue( tags.map((currentTag) => { @@ -350,7 +349,7 @@ export class GfCreateOrUpdateActivityDialogComponent implements OnDestroy { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); }); } @@ -358,18 +357,13 @@ export class GfCreateOrUpdateActivityDialogComponent implements OnDestroy { this.activityForm .get('type') - .valueChanges.pipe(takeUntil(this.unsubscribeSubject)) + .valueChanges.pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((type: ActivityType) => { if ( type === 'VALUABLE' || (this.activityForm.get('dataSource').value === 'MANUAL' && type === 'BUY') ) { - this.activityForm - .get('accountId') - .removeValidators(Validators.required); - this.activityForm.get('accountId').updateValueAndValidity(); - const currency = this.data.accounts.find(({ id }) => { return id === this.activityForm.get('accountId').value; @@ -397,11 +391,6 @@ export class GfCreateOrUpdateActivityDialogComponent implements OnDestroy { this.activityForm.get('updateAccountBalance').disable(); this.activityForm.get('updateAccountBalance').setValue(false); } else if (['FEE', 'INTEREST', 'LIABILITY'].includes(type)) { - this.activityForm - .get('accountId') - .removeValidators(Validators.required); - this.activityForm.get('accountId').updateValueAndValidity(); - const currency = this.data.accounts.find(({ id }) => { return id === this.activityForm.get('accountId').value; @@ -447,8 +436,6 @@ export class GfCreateOrUpdateActivityDialogComponent implements OnDestroy { this.activityForm.get('updateAccountBalance').setValue(false); } } else { - this.activityForm.get('accountId').setValidators(Validators.required); - this.activityForm.get('accountId').updateValueAndValidity(); this.activityForm .get('dataSource') .setValidators(Validators.required); @@ -478,7 +465,7 @@ export class GfCreateOrUpdateActivityDialogComponent implements OnDestroy { dataSource: this.data.activity?.SymbolProfile?.dataSource, symbol: this.data.activity?.SymbolProfile?.symbol }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ marketPrice }) => { this.currentMarketPrice = marketPrice; @@ -514,11 +501,12 @@ export class GfCreateOrUpdateActivityDialogComponent implements OnDestroy { comment: this.activityForm.get('comment').value || null, currency: this.activityForm.get('currency').value, customCurrency: this.activityForm.get('currencyOfUnitPrice').value, + dataSource: ['FEE', 'INTEREST', 'LIABILITY', 'VALUABLE'].includes( + this.activityForm.get('type').value + ) + ? 'MANUAL' + : this.activityForm.get('dataSource').value, date: this.activityForm.get('date').value, - dataSource: - this.activityForm.get('type').value === 'VALUABLE' - ? 'MANUAL' - : this.activityForm.get('dataSource').value, fee: this.activityForm.get('fee').value, quantity: this.activityForm.get('quantity').value, symbol: @@ -569,11 +557,6 @@ export class GfCreateOrUpdateActivityDialogComponent implements OnDestroy { } } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private updateAssetProfile() { this.isLoading = true; this.changeDetectorRef.markForCheck(); @@ -593,7 +576,7 @@ export class GfCreateOrUpdateActivityDialogComponent implements OnDestroy { return EMPTY; }), - takeUntil(this.unsubscribeSubject) + takeUntilDestroyed(this.destroyRef) ) .subscribe(({ currency, dataSource, marketPrice }) => { if (this.mode === 'create') { diff --git a/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html b/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html index 42fbd0ebf..278ddcbbd 100644 --- a/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html +++ b/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -84,12 +84,8 @@ > Account - @if ( - !activityForm.get('accountId').hasValidator(Validators.required) || - (!activityForm.get('accountId').value && mode === 'update') - ) { - - } + + @for (account of data.accounts; track account) {
    diff --git a/apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts b/apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts index 1a84e9f31..00f0508fe 100644 --- a/apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts +++ b/apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts @@ -21,9 +21,10 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, - Inject, - OnDestroy + DestroyRef, + Inject } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { FormBuilder, FormGroup, @@ -52,7 +53,6 @@ import { cloudUploadOutline, warningOutline } from 'ionicons/icons'; import { isArray, sortBy } from 'lodash'; import ms from 'ms'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject, takeUntil } from 'rxjs'; import { ImportStep } from './enums/import-step'; import { ImportActivitiesDialogParams } from './interfaces/interfaces'; @@ -81,7 +81,7 @@ import { ImportActivitiesDialogParams } from './interfaces/interfaces'; styleUrls: ['./import-activities-dialog.scss'], templateUrl: 'import-activities-dialog.html' }) -export class GfImportActivitiesDialogComponent implements OnDestroy { +export class GfImportActivitiesDialogComponent { public accounts: CreateAccountWithBalancesDto[] = []; public activities: Activity[] = []; public assetProfileForm: FormGroup; @@ -104,12 +104,11 @@ export class GfImportActivitiesDialogComponent implements OnDestroy { public tags: CreateTagDto[] = []; public totalItems: number; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, @Inject(MAT_DIALOG_DATA) public data: ImportActivitiesDialogParams, private dataService: DataService, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private formBuilder: FormBuilder, public dialogRef: MatDialogRef, @@ -152,7 +151,7 @@ export class GfImportActivitiesDialogComponent implements OnDestroy { ], range: 'max' }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ holdings }) => { this.holdings = sortBy(holdings, ({ name }) => { return name.toLowerCase(); @@ -237,7 +236,7 @@ export class GfImportActivitiesDialogComponent implements OnDestroy { dataSource, symbol }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ activities }) => { this.activities = activities; this.dataSource = new MatTableDataSource(activities.reverse()); @@ -284,11 +283,6 @@ export class GfImportActivitiesDialogComponent implements OnDestroy { }); } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private async handleFile({ file, stepper diff --git a/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts b/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts index 70fa09eb1..367716d2d 100644 --- a/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts +++ b/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts @@ -22,7 +22,13 @@ import { GfValueComponent } from '@ghostfolio/ui/value'; import { GfWorldMapChartComponent } from '@ghostfolio/ui/world-map-chart'; import { NgClass } from '@angular/common'; -import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; +import { + ChangeDetectorRef, + Component, + DestroyRef, + OnInit +} from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatCardModule } from '@angular/material/card'; import { MatDialog } from '@angular/material/dialog'; import { MatProgressBarModule } from '@angular/material/progress-bar'; @@ -36,8 +42,6 @@ import { } from '@prisma/client'; import { isNumber } from 'lodash'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; @Component({ imports: [ @@ -54,7 +58,7 @@ import { takeUntil } from 'rxjs/operators'; styleUrls: ['./allocations-page.scss'], templateUrl: './allocations-page.html' }) -export class GfAllocationsPageComponent implements OnDestroy, OnInit { +export class GfAllocationsPageComponent implements OnInit { public accounts: { [id: string]: Pick & { id: string; @@ -119,11 +123,10 @@ export class GfAllocationsPageComponent implements OnDestroy, OnInit { public user: User; public worldMapChartFormat: string; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private dialog: MatDialog, private impersonationStorageService: ImpersonationStorageService, @@ -132,7 +135,7 @@ export class GfAllocationsPageComponent implements OnDestroy, OnInit { private userService: UserService ) { this.route.queryParams - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((params) => { if (params['accountId'] && params['accountDetailDialog']) { this.openAccountDetailDialog(params['accountId']); @@ -145,13 +148,13 @@ export class GfAllocationsPageComponent implements OnDestroy, OnInit { this.impersonationStorageService .onChangeHasImpersonation() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((impersonationId) => { this.hasImpersonationId = !!impersonationId; }); this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -166,7 +169,7 @@ export class GfAllocationsPageComponent implements OnDestroy, OnInit { this.initialize(); this.fetchPortfolioDetails() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((portfolioDetails) => { this.initialize(); @@ -202,11 +205,6 @@ export class GfAllocationsPageComponent implements OnDestroy, OnInit { } } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private extractEtfProvider({ assetSubClass, name @@ -407,17 +405,22 @@ export class GfAllocationsPageComponent implements OnDestroy, OnInit { } if (position.holdings.length > 0) { - for (const holding of position.holdings) { - const { allocationInPercentage, name, valueInBaseCurrency } = - holding; - - if (this.topHoldingsMap[name]?.value) { - this.topHoldingsMap[name].value += isNumber(valueInBaseCurrency) + for (const { + allocationInPercentage, + name, + valueInBaseCurrency + } of position.holdings) { + const normalizedAssetName = this.normalizeAssetName(name); + + if (this.topHoldingsMap[normalizedAssetName]?.value) { + this.topHoldingsMap[normalizedAssetName].value += isNumber( + valueInBaseCurrency + ) ? valueInBaseCurrency : allocationInPercentage * this.portfolioDetails.holdings[symbol].valueInPercentage; } else { - this.topHoldingsMap[name] = { + this.topHoldingsMap[normalizedAssetName] = { name, value: isNumber(valueInBaseCurrency) ? valueInBaseCurrency @@ -520,7 +523,10 @@ export class GfAllocationsPageComponent implements OnDestroy, OnInit { if (holding.holdings.length > 0) { const currentParentHolding = holding.holdings.find( (parentHolding) => { - return parentHolding.name === name; + return ( + this.normalizeAssetName(parentHolding.name) === + this.normalizeAssetName(name) + ); } ); @@ -557,6 +563,14 @@ export class GfAllocationsPageComponent implements OnDestroy, OnInit { } } + private normalizeAssetName(name: string) { + if (!name) { + return ''; + } + + return name.trim().toLowerCase(); + } + private openAccountDetailDialog(aAccountId: string) { const dialogRef = this.dialog.open< GfAccountDetailDialogComponent, @@ -569,7 +583,7 @@ export class GfAllocationsPageComponent implements OnDestroy, OnInit { hasImpersonationId: this.hasImpersonationId, hasPermissionToCreateActivity: !this.hasImpersonationId && - hasPermission(this.user?.permissions, permissions.createOrder) && + hasPermission(this.user?.permissions, permissions.createActivity) && !this.user?.settings?.isRestrictedView }, height: this.deviceType === 'mobile' ? '98vh' : '80vh', @@ -578,7 +592,7 @@ export class GfAllocationsPageComponent implements OnDestroy, OnInit { dialogRef .afterClosed() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.router.navigate(['.'], { relativeTo: this.route }); }); diff --git a/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts b/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts index 5cd24777c..47845ea6f 100644 --- a/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts +++ b/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts @@ -24,10 +24,11 @@ import { Clipboard } from '@angular/cdk/clipboard'; import { ChangeDetectorRef, Component, - OnDestroy, + DestroyRef, OnInit, ViewChild } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; import { MatMenuModule, MatMenuTrigger } from '@angular/material/menu'; @@ -42,8 +43,6 @@ import { isNumber, sortBy } from 'lodash'; import ms from 'ms'; import { DeviceDetectorService } from 'ngx-device-detector'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; @Component({ imports: [ @@ -64,7 +63,7 @@ import { takeUntil } from 'rxjs/operators'; styleUrls: ['./analysis-page.scss'], templateUrl: './analysis-page.html' }) -export class GfAnalysisPageComponent implements OnDestroy, OnInit { +export class GfAnalysisPageComponent implements OnInit { @ViewChild(MatMenuTrigger) actionsMenuButton!: MatMenuTrigger; public benchmark: Partial; @@ -102,12 +101,11 @@ export class GfAnalysisPageComponent implements OnDestroy, OnInit { public unitLongestStreak: string; public user: User; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, private clipboard: Clipboard, private dataService: DataService, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private impersonationStorageService: ImpersonationStorageService, private snackBar: MatSnackBar, @@ -135,13 +133,13 @@ export class GfAnalysisPageComponent implements OnDestroy, OnInit { this.impersonationStorageService .onChangeHasImpersonation() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((impersonationId) => { this.hasImpersonationId = !!impersonationId; }); this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -163,11 +161,11 @@ export class GfAnalysisPageComponent implements OnDestroy, OnInit { public onChangeBenchmark(symbolProfileId: string) { this.dataService .putUserSetting({ benchmark: symbolProfileId }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((user) => { this.user = user; @@ -193,7 +191,7 @@ export class GfAnalysisPageComponent implements OnDestroy, OnInit { mode, filters: this.userService.getFilters() }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ prompt }) => { this.clipboard.copy(prompt); @@ -207,7 +205,7 @@ export class GfAnalysisPageComponent implements OnDestroy, OnInit { snackBarRef .onAction() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { window.open('https://duck.ai', '_blank'); }); @@ -222,11 +220,6 @@ export class GfAnalysisPageComponent implements OnDestroy, OnInit { }); } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private fetchDividendsAndInvestments() { this.isLoadingDividendTimelineChart = true; this.isLoadingInvestmentTimelineChart = true; @@ -237,7 +230,7 @@ export class GfAnalysisPageComponent implements OnDestroy, OnInit { groupBy: this.mode, range: this.user?.settings?.dateRange }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ dividends }) => { this.dividendsByGroup = dividends; @@ -252,7 +245,7 @@ export class GfAnalysisPageComponent implements OnDestroy, OnInit { groupBy: this.mode, range: this.user?.settings?.dateRange }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ investments, streaks }) => { this.investmentsByGroup = investments; this.streaks = streaks; @@ -287,7 +280,7 @@ export class GfAnalysisPageComponent implements OnDestroy, OnInit { filters: this.userService.getFilters(), range: this.user?.settings?.dateRange }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ chart, firstOrderDate, performance }) => { this.firstOrderDate = firstOrderDate ?? new Date(); @@ -346,7 +339,7 @@ export class GfAnalysisPageComponent implements OnDestroy, OnInit { filters: this.userService.getFilters(), range: this.user?.settings?.dateRange }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ holdings }) => { const holdingsSorted = sortBy( holdings.filter(({ netPerformancePercentWithCurrencyEffect }) => { @@ -397,7 +390,7 @@ export class GfAnalysisPageComponent implements OnDestroy, OnInit { range: this.user?.settings?.dateRange, startDate: this.firstOrderDate }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ marketData }) => { this.benchmarkDataItems = marketData.map(({ date, value }) => { return { diff --git a/apps/client/src/app/pages/portfolio/analysis/analysis-page.routes.ts b/apps/client/src/app/pages/portfolio/analysis/analysis-page.routes.ts index 91cf4c91b..343d6ced5 100644 --- a/apps/client/src/app/pages/portfolio/analysis/analysis-page.routes.ts +++ b/apps/client/src/app/pages/portfolio/analysis/analysis-page.routes.ts @@ -10,6 +10,6 @@ export const routes: Routes = [ canActivate: [AuthGuard], component: GfAnalysisPageComponent, path: '', - title: internalRoutes.portfolio.subRoutes.analysis.title + title: internalRoutes.portfolio.subRoutes?.analysis.title } ]; diff --git a/apps/client/src/app/pages/portfolio/fire/fire-page.component.ts b/apps/client/src/app/pages/portfolio/fire/fire-page.component.ts index 27db6c76e..2f7568982 100644 --- a/apps/client/src/app/pages/portfolio/fire/fire-page.component.ts +++ b/apps/client/src/app/pages/portfolio/fire/fire-page.component.ts @@ -12,14 +12,18 @@ import { DataService } from '@ghostfolio/ui/services'; import { GfValueComponent } from '@ghostfolio/ui/value'; import { CommonModule, NgStyle } from '@angular/common'; -import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; +import { + ChangeDetectorRef, + Component, + DestroyRef, + OnInit +} from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { FormControl } from '@angular/forms'; import { Big } from 'big.js'; import { DeviceDetectorService } from 'ngx-device-detector'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; @Component({ imports: [ @@ -36,7 +40,7 @@ import { takeUntil } from 'rxjs/operators'; styleUrls: ['./fire-page.scss'], templateUrl: './fire-page.html' }) -export class GfFirePageComponent implements OnDestroy, OnInit { +export class GfFirePageComponent implements OnInit { public deviceType: string; public fireWealth: FireWealth; public hasImpersonationId: boolean; @@ -52,11 +56,10 @@ export class GfFirePageComponent implements OnDestroy, OnInit { public withdrawalRatePerYear: Big; public withdrawalRatePerYearProjected: Big; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private impersonationStorageService: ImpersonationStorageService, private userService: UserService @@ -68,7 +71,7 @@ export class GfFirePageComponent implements OnDestroy, OnInit { this.dataService .fetchPortfolioDetails() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ summary }) => { this.fireWealth = { today: { @@ -92,19 +95,19 @@ export class GfFirePageComponent implements OnDestroy, OnInit { this.impersonationStorageService .onChangeHasImpersonation() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((impersonationId) => { this.hasImpersonationId = !!impersonationId; }); this.safeWithdrawalRateControl.valueChanges - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((value) => { this.onSafeWithdrawalRateChange(Number(value)); }); this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -132,11 +135,11 @@ export class GfFirePageComponent implements OnDestroy, OnInit { public onAnnualInterestRateChange(annualInterestRate: number) { this.dataService .putUserSetting({ annualInterestRate }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((user) => { this.user = user; @@ -163,11 +166,11 @@ export class GfFirePageComponent implements OnDestroy, OnInit { retirementDate: retirementDate.toISOString(), projectedTotalAmount: null }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((user) => { this.user = user; @@ -179,11 +182,11 @@ export class GfFirePageComponent implements OnDestroy, OnInit { public onSafeWithdrawalRateChange(safeWithdrawalRate: number) { this.dataService .putUserSetting({ safeWithdrawalRate }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((user) => { this.user = user; @@ -198,11 +201,11 @@ export class GfFirePageComponent implements OnDestroy, OnInit { public onSavingsRateChange(savingsRate: number) { this.dataService .putUserSetting({ savingsRate }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((user) => { this.user = user; @@ -217,11 +220,11 @@ export class GfFirePageComponent implements OnDestroy, OnInit { projectedTotalAmount, retirementDate: null }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((user) => { this.user = user; @@ -230,11 +233,6 @@ export class GfFirePageComponent implements OnDestroy, OnInit { }); } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private calculateWithdrawalRates() { if (this.fireWealth && this.user?.settings?.safeWithdrawalRate) { this.withdrawalRatePerYear = new Big( diff --git a/apps/client/src/app/pages/portfolio/portfolio-page.component.ts b/apps/client/src/app/pages/portfolio/portfolio-page.component.ts index 387e3fd0f..eb4935127 100644 --- a/apps/client/src/app/pages/portfolio/portfolio-page.component.ts +++ b/apps/client/src/app/pages/portfolio/portfolio-page.component.ts @@ -2,7 +2,13 @@ import { UserService } from '@ghostfolio/client/services/user/user.service'; import { TabConfiguration, User } from '@ghostfolio/common/interfaces'; import { internalRoutes } from '@ghostfolio/common/routes/routes'; -import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; +import { + ChangeDetectorRef, + Component, + DestroyRef, + OnInit +} from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatTabsModule } from '@angular/material/tabs'; import { RouterModule } from '@angular/router'; import { addIcons } from 'ionicons'; @@ -14,8 +20,6 @@ import { swapVerticalOutline } from 'ionicons/icons'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; @Component({ host: { class: 'page has-tabs' }, @@ -24,20 +28,19 @@ import { takeUntil } from 'rxjs/operators'; styleUrls: ['./portfolio-page.scss'], templateUrl: './portfolio-page.html' }) -export class PortfolioPageComponent implements OnDestroy, OnInit { +export class PortfolioPageComponent implements OnInit { public deviceType: string; public tabs: TabConfiguration[] = []; public user: User; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private userService: UserService ) { this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.tabs = [ @@ -87,9 +90,4 @@ export class PortfolioPageComponent implements OnDestroy, OnInit { public ngOnInit() { this.deviceType = this.deviceService.getDeviceInfo().deviceType; } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/portfolio/portfolio-page.routes.ts b/apps/client/src/app/pages/portfolio/portfolio-page.routes.ts index aeebf4a6b..a4fdc3f61 100644 --- a/apps/client/src/app/pages/portfolio/portfolio-page.routes.ts +++ b/apps/client/src/app/pages/portfolio/portfolio-page.routes.ts @@ -15,22 +15,22 @@ export const routes: Routes = [ import('./analysis/analysis-page.routes').then((m) => m.routes) }, { - path: internalRoutes.portfolio.subRoutes.activities.path, + path: internalRoutes.portfolio.subRoutes?.activities.path, loadChildren: () => import('./activities/activities-page.routes').then((m) => m.routes) }, { - path: internalRoutes.portfolio.subRoutes.allocations.path, + path: internalRoutes.portfolio.subRoutes?.allocations.path, loadChildren: () => import('./allocations/allocations-page.routes').then((m) => m.routes) }, { - path: internalRoutes.portfolio.subRoutes.fire.path, + path: internalRoutes.portfolio.subRoutes?.fire.path, loadChildren: () => import('./fire/fire-page.routes').then((m) => m.routes) }, { - path: internalRoutes.portfolio.subRoutes.xRay.path, + path: internalRoutes.portfolio.subRoutes?.xRay.path, loadChildren: () => import('./x-ray/x-ray-page.routes').then((m) => m.routes) } diff --git a/apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.ts b/apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.ts index 70b748b10..e97fd4876 100644 --- a/apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.ts +++ b/apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.ts @@ -12,7 +12,8 @@ import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator'; import { DataService } from '@ghostfolio/ui/services'; import { NgClass } from '@angular/common'; -import { ChangeDetectorRef, Component } from '@angular/core'; +import { ChangeDetectorRef, Component, DestroyRef } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { IonIcon } from '@ionic/angular/standalone'; import { addIcons } from 'ionicons'; import { @@ -21,7 +22,6 @@ import { warningOutline } from 'ionicons/icons'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; -import { Subject, takeUntil } from 'rxjs'; @Component({ imports: [ @@ -48,11 +48,10 @@ export class GfXRayPageComponent { public statistics: PortfolioReportResponse['xRay']['statistics']; public user: User; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private impersonationStorageService: ImpersonationStorageService, private userService: UserService ) { @@ -62,13 +61,13 @@ export class GfXRayPageComponent { public ngOnInit() { this.impersonationStorageService .onChangeHasImpersonation() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((impersonationId) => { this.hasImpersonationId = !!impersonationId; }); this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -91,28 +90,23 @@ export class GfXRayPageComponent { public onRulesUpdated(event: UpdateUserSettingDto) { this.dataService .putUserSetting(event) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); this.initializePortfolioReport(); }); } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private initializePortfolioReport() { this.isLoading = true; this.dataService .fetchPortfolioReport() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ xRay: { categories, statistics } }) => { this.categories = categories; this.inactiveRules = this.mergeInactiveRules(categories); 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 fe4b295db..9ccbbf52e 100644 --- a/apps/client/src/app/pages/public/public-page.component.ts +++ b/apps/client/src/app/pages/public/public-page.component.ts @@ -19,8 +19,10 @@ import { ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA, + DestroyRef, OnInit } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; import { MatTableDataSource } from '@angular/material/table'; @@ -29,8 +31,8 @@ import { AssetClass } from '@prisma/client'; import { StatusCodes } from 'http-status-codes'; import { isNumber } from 'lodash'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { EMPTY, Subject } from 'rxjs'; -import { catchError, takeUntil } from 'rxjs/operators'; +import { EMPTY } from 'rxjs'; +import { catchError } from 'rxjs/operators'; @Component({ host: { class: 'page' }, @@ -83,12 +85,12 @@ export class GfPublicPageComponent implements OnInit { public UNKNOWN_KEY = UNKNOWN_KEY; private accessId: string; - private unsubscribeSubject = new Subject(); public constructor( private activatedRoute: ActivatedRoute, private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private router: Router ) { @@ -110,7 +112,7 @@ export class GfPublicPageComponent implements OnInit { this.dataService .fetchPublicPortfolio(this.accessId) .pipe( - takeUntil(this.unsubscribeSubject), + takeUntilDestroyed(this.destroyRef), catchError((error) => { if (error.status === StatusCodes.NOT_FOUND) { console.error(error); @@ -246,9 +248,4 @@ export class GfPublicPageComponent implements OnInit { }; } } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/register/register-page.component.ts b/apps/client/src/app/pages/register/register-page.component.ts index 21b26944e..db199143f 100644 --- a/apps/client/src/app/pages/register/register-page.component.ts +++ b/apps/client/src/app/pages/register/register-page.component.ts @@ -1,4 +1,5 @@ import { TokenStorageService } from '@ghostfolio/client/services/token-storage.service'; +import { UserService } from '@ghostfolio/client/services/user/user.service'; import { InfoItem, LineChartItem } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { GfLogoComponent } from '@ghostfolio/ui/logo'; @@ -7,15 +8,14 @@ import { DataService } from '@ghostfolio/ui/services'; import { Component, CUSTOM_ELEMENTS_SCHEMA, - OnDestroy, + DestroyRef, OnInit } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatButtonModule } from '@angular/material/button'; import { MatDialog } from '@angular/material/dialog'; import { Router, RouterModule } from '@angular/router'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; import { UserAccountRegistrationDialogParams } from './user-account-registration-dialog/interfaces/interfaces'; import { GfUserAccountRegistrationDialogComponent } from './user-account-registration-dialog/user-account-registration-dialog.component'; @@ -28,7 +28,7 @@ import { GfUserAccountRegistrationDialogComponent } from './user-account-registr styleUrls: ['./register-page.scss'], templateUrl: './register-page.html' }) -export class GfRegisterPageComponent implements OnDestroy, OnInit { +export class GfRegisterPageComponent implements OnInit { public deviceType: string; public hasPermissionForAuthGoogle: boolean; public hasPermissionForAuthToken: boolean; @@ -37,18 +37,18 @@ export class GfRegisterPageComponent implements OnDestroy, OnInit { public historicalDataItems: LineChartItem[]; public info: InfoItem; - private unsubscribeSubject = new Subject(); - public constructor( private dataService: DataService, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private dialog: MatDialog, private router: Router, - private tokenStorageService: TokenStorageService + private tokenStorageService: TokenStorageService, + private userService: UserService ) { this.info = this.dataService.fetchInfo(); - this.tokenStorageService.signOut(); + this.userService.signOut(); } public ngOnInit() { @@ -93,7 +93,7 @@ export class GfRegisterPageComponent implements OnDestroy, OnInit { dialogRef .afterClosed() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((authToken) => { if (authToken) { this.tokenStorageService.saveToken(authToken, true); @@ -102,9 +102,4 @@ export class GfRegisterPageComponent implements OnDestroy, OnInit { } }); } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.component.ts b/apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.component.ts index a7707ad3b..cbbe2d29c 100644 --- a/apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.component.ts +++ b/apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.component.ts @@ -8,9 +8,11 @@ import { ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA, + DestroyRef, Inject, ViewChild } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; import { MatCheckboxModule } from '@angular/material/checkbox'; @@ -26,8 +28,6 @@ import { checkmarkOutline, copyOutline } from 'ionicons/icons'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; import { UserAccountRegistrationDialogParams } from './interfaces/interfaces'; @@ -63,12 +63,11 @@ export class GfUserAccountRegistrationDialogComponent { public routerLinkAboutTermsOfService = publicRoutes.about.subRoutes.termsOfService.routerLink; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, @Inject(MAT_DIALOG_DATA) public data: UserAccountRegistrationDialogParams, - private dataService: DataService + private dataService: DataService, + private destroyRef: DestroyRef ) { addIcons({ arrowForwardOutline, checkmarkOutline, copyOutline }); } @@ -76,7 +75,7 @@ export class GfUserAccountRegistrationDialogComponent { public createAccount() { this.dataService .postUser() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ accessToken, authToken, role }) => { this.accessToken = accessToken; this.authToken = authToken; diff --git a/apps/client/src/app/pages/resources/glossary/resources-glossary.component.ts b/apps/client/src/app/pages/resources/glossary/resources-glossary.component.ts index 112619239..9c86f2c83 100644 --- a/apps/client/src/app/pages/resources/glossary/resources-glossary.component.ts +++ b/apps/client/src/app/pages/resources/glossary/resources-glossary.component.ts @@ -16,7 +16,7 @@ export class ResourcesGlossaryPageComponent implements OnInit { public hasPermissionForSubscription: boolean; public info: InfoItem; public routerLinkResourcesPersonalFinanceTools = - publicRoutes.resources.subRoutes.personalFinanceTools.routerLink; + publicRoutes.resources.subRoutes?.personalFinanceTools.routerLink; public constructor(private dataService: DataService) { this.info = this.dataService.fetchInfo(); diff --git a/apps/client/src/app/pages/resources/glossary/resources-glossary.routes.ts b/apps/client/src/app/pages/resources/glossary/resources-glossary.routes.ts index 2f864155a..4096dfecd 100644 --- a/apps/client/src/app/pages/resources/glossary/resources-glossary.routes.ts +++ b/apps/client/src/app/pages/resources/glossary/resources-glossary.routes.ts @@ -8,6 +8,6 @@ export const routes: Routes = [ { component: ResourcesGlossaryPageComponent, path: '', - title: publicRoutes.resources.subRoutes.glossary.title + title: publicRoutes.resources.subRoutes?.glossary.title } ]; diff --git a/apps/client/src/app/pages/resources/guides/resources-guides.routes.ts b/apps/client/src/app/pages/resources/guides/resources-guides.routes.ts index f9f65f44a..eb8c39e24 100644 --- a/apps/client/src/app/pages/resources/guides/resources-guides.routes.ts +++ b/apps/client/src/app/pages/resources/guides/resources-guides.routes.ts @@ -8,6 +8,6 @@ export const routes: Routes = [ { component: ResourcesGuidesComponent, path: '', - title: publicRoutes.resources.subRoutes.guides.title + title: publicRoutes.resources.subRoutes?.guides.title } ]; diff --git a/apps/client/src/app/pages/resources/markets/resources-markets.routes.ts b/apps/client/src/app/pages/resources/markets/resources-markets.routes.ts index 4bcb66789..a56dc7cf7 100644 --- a/apps/client/src/app/pages/resources/markets/resources-markets.routes.ts +++ b/apps/client/src/app/pages/resources/markets/resources-markets.routes.ts @@ -8,6 +8,6 @@ export const routes: Routes = [ { component: ResourcesMarketsComponent, path: '', - title: publicRoutes.resources.subRoutes.markets.title + title: publicRoutes.resources.subRoutes?.markets.title } ]; diff --git a/apps/client/src/app/pages/resources/overview/resources-overview.component.html b/apps/client/src/app/pages/resources/overview/resources-overview.component.html index 3a6f18d40..86a334c79 100644 --- a/apps/client/src/app/pages/resources/overview/resources-overview.component.html +++ b/apps/client/src/app/pages/resources/overview/resources-overview.component.html @@ -7,7 +7,9 @@

    {{ item.title }}

    {{ item.description }}

    - Explore {{ item.title }} → + Explore {{ item.title }}
    }
    diff --git a/apps/client/src/app/pages/resources/overview/resources-overview.component.ts b/apps/client/src/app/pages/resources/overview/resources-overview.component.ts index 81338200f..310f16a5e 100644 --- a/apps/client/src/app/pages/resources/overview/resources-overview.component.ts +++ b/apps/client/src/app/pages/resources/overview/resources-overview.component.ts @@ -20,20 +20,20 @@ export class ResourcesOverviewComponent { { description: 'Explore our guides to help you get started with investing and managing your finances.', - routerLink: publicRoutes.resources.subRoutes.guides.routerLink, - title: publicRoutes.resources.subRoutes.guides.title + routerLink: publicRoutes.resources.subRoutes?.guides.routerLink, + title: publicRoutes.resources.subRoutes?.guides.title }, { description: 'Access various market resources and tools to stay informed about financial markets.', - routerLink: publicRoutes.resources.subRoutes.markets.routerLink, - title: publicRoutes.resources.subRoutes.markets.title + routerLink: publicRoutes.resources.subRoutes?.markets.routerLink, + title: publicRoutes.resources.subRoutes?.markets.title }, { description: 'Learn key financial terms and concepts in our comprehensive glossary.', - routerLink: publicRoutes.resources.subRoutes.glossary.routerLink, - title: publicRoutes.resources.subRoutes.glossary.title + routerLink: publicRoutes.resources.subRoutes?.glossary.routerLink, + title: publicRoutes.resources.subRoutes?.glossary.title } ]; } 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 c4cfd184e..bb4ae3889 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 @@ -1,13 +1,12 @@ import { personalFinanceTools } from '@ghostfolio/common/personal-finance-tools'; import { publicRoutes } from '@ghostfolio/common/routes/routes'; -import { Component, OnDestroy } from '@angular/core'; +import { Component } from '@angular/core'; import { MatCardModule } from '@angular/material/card'; import { RouterModule } from '@angular/router'; import { IonIcon } from '@ionic/angular/standalone'; import { addIcons } from 'ionicons'; import { chevronForwardOutline } from 'ionicons/icons'; -import { Subject } from 'rxjs'; @Component({ host: { class: 'page' }, @@ -16,7 +15,7 @@ import { Subject } from 'rxjs'; styleUrls: ['./personal-finance-tools-page.scss'], templateUrl: './personal-finance-tools-page.html' }) -export class PersonalFinanceToolsPageComponent implements OnDestroy { +export class PersonalFinanceToolsPageComponent { public pathAlternativeTo = publicRoutes.resources.subRoutes.personalFinanceTools.subRoutes.product .path + '-'; @@ -28,14 +27,7 @@ export class PersonalFinanceToolsPageComponent implements OnDestroy { }); public routerLinkAbout = publicRoutes.about.routerLink; - private unsubscribeSubject = new Subject(); - public constructor() { addIcons({ chevronForwardOutline }); } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.routes.ts b/apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.routes.ts index 9081f6b28..081c34000 100644 --- a/apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.routes.ts +++ b/apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.routes.ts @@ -11,7 +11,7 @@ export const routes: Routes = [ canActivate: [AuthGuard], component: PersonalFinanceToolsPageComponent, path: '', - title: publicRoutes.resources.subRoutes.personalFinanceTools.title + title: publicRoutes.resources.subRoutes?.personalFinanceTools.title }, ...personalFinanceTools.map(({ alias, key, name }) => { return { @@ -23,8 +23,8 @@ export const routes: Routes = [ return GfProductPageComponent; } ), - path: `${publicRoutes.resources.subRoutes.personalFinanceTools.subRoutes.product.path}-${alias ?? key}`, - title: `${publicRoutes.resources.subRoutes.personalFinanceTools.subRoutes.product.title} ${name}` + path: `${publicRoutes.resources.subRoutes?.personalFinanceTools.subRoutes?.product.path}-${alias ?? key}`, + title: `${publicRoutes.resources.subRoutes?.personalFinanceTools.subRoutes?.product.title} ${name}` }; }) ]; 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 9db996f57..c25ef00d6 100644 --- a/apps/client/src/app/pages/resources/resources-page.component.ts +++ b/apps/client/src/app/pages/resources/resources-page.component.ts @@ -13,7 +13,6 @@ import { readerOutline } from 'ionicons/icons'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject } from 'rxjs'; @Component({ host: { class: 'page has-tabs' }, @@ -47,8 +46,6 @@ export class ResourcesPageComponent implements OnInit { } ]; - private unsubscribeSubject = new Subject(); - public constructor(private deviceService: DeviceDetectorService) { addIcons({ bookOutline, libraryOutline, newspaperOutline, readerOutline }); } @@ -56,9 +53,4 @@ export class ResourcesPageComponent implements OnInit { public ngOnInit() { this.deviceType = this.deviceService.getDeviceInfo().deviceType; } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/resources/resources-page.routes.ts b/apps/client/src/app/pages/resources/resources-page.routes.ts index 107988238..6e59f0995 100644 --- a/apps/client/src/app/pages/resources/resources-page.routes.ts +++ b/apps/client/src/app/pages/resources/resources-page.routes.ts @@ -16,22 +16,22 @@ export const routes: Routes = [ import('./overview/resources-overview.routes').then((m) => m.routes) }, { - path: publicRoutes.resources.subRoutes.glossary.path, + path: publicRoutes.resources.subRoutes?.glossary.path, loadChildren: () => import('./glossary/resources-glossary.routes').then((m) => m.routes) }, { - path: publicRoutes.resources.subRoutes.guides.path, + path: publicRoutes.resources.subRoutes?.guides.path, loadChildren: () => import('./guides/resources-guides.routes').then((m) => m.routes) }, { - path: publicRoutes.resources.subRoutes.markets.path, + path: publicRoutes.resources.subRoutes?.markets.path, loadChildren: () => import('./markets/resources-markets.routes').then((m) => m.routes) }, { - path: publicRoutes.resources.subRoutes.personalFinanceTools.path, + path: publicRoutes.resources.subRoutes?.personalFinanceTools.path, loadChildren: () => import('./personal-finance-tools/personal-finance-tools-page.routes').then( (m) => m.routes diff --git a/apps/client/src/app/pages/user-account/user-account-page.component.ts b/apps/client/src/app/pages/user-account/user-account-page.component.ts index 7341660f2..24c150408 100644 --- a/apps/client/src/app/pages/user-account/user-account-page.component.ts +++ b/apps/client/src/app/pages/user-account/user-account-page.component.ts @@ -6,16 +6,16 @@ import { ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA, - OnDestroy, + DestroyRef, OnInit } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatTabsModule } from '@angular/material/tabs'; import { RouterModule } from '@angular/router'; import { IonIcon } from '@ionic/angular/standalone'; import { addIcons } from 'ionicons'; import { diamondOutline, keyOutline, settingsOutline } from 'ionicons/icons'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject, takeUntil } from 'rxjs'; @Component({ host: { class: 'page has-tabs' }, @@ -25,20 +25,19 @@ import { Subject, takeUntil } from 'rxjs'; styleUrls: ['./user-account-page.scss'], templateUrl: './user-account-page.html' }) -export class GfUserAccountPageComponent implements OnDestroy, OnInit { +export class GfUserAccountPageComponent implements OnInit { public deviceType: string; public tabs: TabConfiguration[] = []; public user: User; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private userService: UserService ) { this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -73,9 +72,4 @@ export class GfUserAccountPageComponent implements OnDestroy, OnInit { public ngOnInit() { this.deviceType = this.deviceService.getDeviceInfo().deviceType; } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/user-account/user-account-page.routes.ts b/apps/client/src/app/pages/user-account/user-account-page.routes.ts index 5d0f5b202..7eac1298e 100644 --- a/apps/client/src/app/pages/user-account/user-account-page.routes.ts +++ b/apps/client/src/app/pages/user-account/user-account-page.routes.ts @@ -18,14 +18,14 @@ export const routes: Routes = [ title: internalRoutes.account.title }, { - path: internalRoutes.account.subRoutes.membership.path, + path: internalRoutes.account.subRoutes?.membership.path, component: GfUserAccountMembershipComponent, - title: internalRoutes.account.subRoutes.membership.title + title: internalRoutes.account.subRoutes?.membership.title }, { - path: internalRoutes.account.subRoutes.access.path, + path: internalRoutes.account.subRoutes?.access.path, component: GfUserAccountAccessComponent, - title: internalRoutes.account.subRoutes.access.title + title: internalRoutes.account.subRoutes?.access.title } ], component: GfUserAccountPageComponent, diff --git a/apps/client/src/app/pages/webauthn/webauthn-page.component.ts b/apps/client/src/app/pages/webauthn/webauthn-page.component.ts index 74631eeca..8e7e58fd1 100644 --- a/apps/client/src/app/pages/webauthn/webauthn-page.component.ts +++ b/apps/client/src/app/pages/webauthn/webauthn-page.component.ts @@ -2,12 +2,16 @@ import { TokenStorageService } from '@ghostfolio/client/services/token-storage.s import { WebAuthnService } from '@ghostfolio/client/services/web-authn.service'; import { GfLogoComponent } from '@ghostfolio/ui/logo'; -import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; +import { + ChangeDetectorRef, + Component, + DestroyRef, + OnInit +} from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatButtonModule } from '@angular/material/button'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { Router } from '@angular/router'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; @Component({ host: { class: 'page' }, @@ -16,13 +20,12 @@ import { takeUntil } from 'rxjs/operators'; styleUrls: ['./webauthn-page.scss'], templateUrl: './webauthn-page.html' }) -export class GfWebauthnPageComponent implements OnDestroy, OnInit { +export class GfWebauthnPageComponent implements OnInit { public hasError = false; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, + private destroyRef: DestroyRef, private router: Router, private tokenStorageService: TokenStorageService, private webAuthnService: WebAuthnService @@ -35,7 +38,7 @@ export class GfWebauthnPageComponent implements OnDestroy, OnInit { public deregisterDevice() { this.webAuthnService .deregister() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.router.navigate(['/']); }); @@ -46,7 +49,7 @@ export class GfWebauthnPageComponent implements OnDestroy, OnInit { this.webAuthnService .login() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe( ({ authToken }) => { this.tokenStorageService.saveToken(authToken, false); @@ -59,9 +62,4 @@ export class GfWebauthnPageComponent implements OnDestroy, OnInit { } ); } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/zen/zen-page.component.ts b/apps/client/src/app/pages/zen/zen-page.component.ts index 280f33c25..633f15885 100644 --- a/apps/client/src/app/pages/zen/zen-page.component.ts +++ b/apps/client/src/app/pages/zen/zen-page.component.ts @@ -2,15 +2,19 @@ import { UserService } from '@ghostfolio/client/services/user/user.service'; import { TabConfiguration, User } from '@ghostfolio/common/interfaces'; import { internalRoutes } from '@ghostfolio/common/routes/routes'; -import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; +import { + ChangeDetectorRef, + Component, + DestroyRef, + OnInit +} from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatTabsModule } from '@angular/material/tabs'; import { RouterModule } from '@angular/router'; import { IonIcon } from '@ionic/angular/standalone'; import { addIcons } from 'ionicons'; import { albumsOutline, analyticsOutline } from 'ionicons/icons'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; @Component({ host: { class: 'page has-tabs' }, @@ -19,20 +23,19 @@ import { takeUntil } from 'rxjs/operators'; styleUrls: ['./zen-page.scss'], templateUrl: './zen-page.html' }) -export class GfZenPageComponent implements OnDestroy, OnInit { +export class GfZenPageComponent implements OnInit { public deviceType: string; public tabs: TabConfiguration[] = []; public user: User; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private userService: UserService ) { this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.tabs = [ @@ -59,9 +62,4 @@ export class GfZenPageComponent implements OnDestroy, OnInit { public ngOnInit() { this.deviceType = this.deviceService.getDeviceInfo().deviceType; } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/zen/zen-page.routes.ts b/apps/client/src/app/pages/zen/zen-page.routes.ts index 60e163ca4..38929dc85 100644 --- a/apps/client/src/app/pages/zen/zen-page.routes.ts +++ b/apps/client/src/app/pages/zen/zen-page.routes.ts @@ -16,9 +16,9 @@ export const routes: Routes = [ component: GfHomeOverviewComponent }, { - path: internalRoutes.zen.subRoutes.holdings.path, + path: internalRoutes.zen.subRoutes?.holdings.path, component: GfHomeHoldingsComponent, - title: internalRoutes.home.subRoutes.holdings.title + title: internalRoutes.home.subRoutes?.holdings.title } ], component: GfZenPageComponent, diff --git a/apps/client/src/app/services/import-activities.service.ts b/apps/client/src/app/services/import-activities.service.ts index 94d8470f7..55b5c44d5 100644 --- a/apps/client/src/app/services/import-activities.service.ts +++ b/apps/client/src/app/services/import-activities.service.ts @@ -97,9 +97,7 @@ export class ImportActivitiesService { isin: null, marketData: [], name: symbol, - scraperConfiguration: null, sectors: [], - symbolMapping: {}, url: null }); } diff --git a/apps/client/src/app/services/token-storage.service.ts b/apps/client/src/app/services/token-storage.service.ts index 5b9a29a08..f54aab828 100644 --- a/apps/client/src/app/services/token-storage.service.ts +++ b/apps/client/src/app/services/token-storage.service.ts @@ -1,19 +1,11 @@ -import { WebAuthnService } from '@ghostfolio/client/services/web-authn.service'; - import { Injectable } from '@angular/core'; import { KEY_TOKEN } from './settings-storage.service'; -import { UserService } from './user/user.service'; @Injectable({ providedIn: 'root' }) export class TokenStorageService { - public constructor( - private userService: UserService, - private webAuthnService: WebAuthnService - ) {} - public getToken(): string { return ( window.sessionStorage.getItem(KEY_TOKEN) || @@ -25,23 +17,7 @@ export class TokenStorageService { if (staySignedIn) { window.localStorage.setItem(KEY_TOKEN, token); } - window.sessionStorage.setItem(KEY_TOKEN, token); - } - - public signOut() { - const utmSource = window.localStorage.getItem('utm_source'); - if (this.webAuthnService.isEnabled()) { - this.webAuthnService.deregister().subscribe(); - } - - window.localStorage.clear(); - window.sessionStorage.clear(); - - this.userService.remove(); - - if (utmSource) { - window.localStorage.setItem('utm_source', utmSource); - } + window.sessionStorage.setItem(KEY_TOKEN, token); } } diff --git a/apps/client/src/app/services/user/user.service.ts b/apps/client/src/app/services/user/user.service.ts index bd9d7d04c..44b63e056 100644 --- a/apps/client/src/app/services/user/user.service.ts +++ b/apps/client/src/app/services/user/user.service.ts @@ -1,3 +1,4 @@ +import { WebAuthnService } from '@ghostfolio/client/services/web-authn.service'; import { Filter, User } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; @@ -26,7 +27,8 @@ export class UserService extends ObservableStore { public constructor( private deviceService: DeviceDetectorService, private dialog: MatDialog, - private http: HttpClient + private http: HttpClient, + private webAuthnService: WebAuthnService ) { super({ trackStateHistory: true }); @@ -93,10 +95,40 @@ export class UserService extends ObservableStore { return this.getFilters().length > 0; } - public remove() { + public reset() { this.setState({ user: null }, UserStoreActions.RemoveUser); } + public signOut() { + const utmSource = window.localStorage.getItem('utm_source'); + + if (this.webAuthnService.isEnabled()) { + this.webAuthnService.deregister().subscribe(); + } + + window.localStorage.clear(); + window.sessionStorage.clear(); + + void this.clearAllCookies(); + + this.reset(); + + if (utmSource) { + window.localStorage.setItem('utm_source', utmSource); + } + } + + private async clearAllCookies() { + if (!('cookieStore' in window)) { + console.warn('Cookie Store API not available in this browser'); + return; + } + + const cookies = await cookieStore.getAll(); + + await Promise.all(cookies.map(({ name }) => cookieStore.delete(name))); + } + private fetchUser(): Observable { return this.http.get('/api/v1/user').pipe( map((user) => { diff --git a/apps/client/src/locales/messages.ca.xlf b/apps/client/src/locales/messages.ca.xlf index a6bec7df3..566d91cc7 100644 --- a/apps/client/src/locales/messages.ca.xlf +++ b/apps/client/src/locales/messages.ca.xlf @@ -38,7 +38,7 @@ apps/client/src/app/components/header/header.component.ts - 297 + 298 apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html @@ -403,7 +403,7 @@ Balanç de Caixa apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 148 + 146 @@ -427,7 +427,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 309 + 310 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -439,7 +439,7 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 46 + 58 apps/client/src/app/components/admin-tag/admin-tag.component.html @@ -455,7 +455,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 139 + 135 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -499,7 +499,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 316 + 317 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -511,7 +511,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 145 + 141 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -531,15 +531,15 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 205 + 201 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 208 + 204 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 211 + 207 libs/ui/src/lib/account-balances/account-balances.component.html @@ -587,11 +587,11 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 74 + 78 apps/client/src/app/components/admin-tag/admin-tag.component.html - 67 + 71 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -619,11 +619,15 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 85 + 89 apps/client/src/app/components/admin-tag/admin-tag.component.html - 78 + 82 + + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 22 libs/ui/src/lib/account-balances/account-balances.component.html @@ -647,7 +651,7 @@ Realment vol suprimir aquest compte? libs/ui/src/lib/accounts-table/accounts-table.component.ts - 150 + 148 @@ -655,7 +659,7 @@ Tipus apps/client/src/app/components/admin-jobs/admin-jobs.html - 48 + 57 apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html @@ -675,7 +679,7 @@ Perfil d’Actiu apps/client/src/app/components/admin-jobs/admin-jobs.html - 52 + 61 @@ -683,11 +687,11 @@ Dades Històriques de Mercat apps/client/src/app/components/admin-jobs/admin-jobs.html - 54 + 63 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 448 + 451 @@ -695,7 +699,7 @@ Origen de les Dades apps/client/src/app/components/admin-jobs/admin-jobs.html - 82 + 91 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -707,7 +711,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 155 + 151 libs/ui/src/lib/i18n.ts @@ -719,7 +723,7 @@ Prioritat apps/client/src/app/components/admin-jobs/admin-jobs.html - 96 + 105 @@ -727,7 +731,7 @@ Intents apps/client/src/app/components/admin-jobs/admin-jobs.html - 120 + 129 @@ -735,7 +739,7 @@ Creat apps/client/src/app/components/admin-jobs/admin-jobs.html - 134 + 143 @@ -743,7 +747,7 @@ Finalitzat apps/client/src/app/components/admin-jobs/admin-jobs.html - 143 + 152 @@ -751,11 +755,11 @@ Estat apps/client/src/app/components/admin-jobs/admin-jobs.html - 152 + 161 apps/client/src/app/components/admin-settings/admin-settings.component.html - 92 + 104 @@ -771,7 +775,7 @@ Aturar Processos apps/client/src/app/components/admin-jobs/admin-jobs.html - 193 + 202 @@ -779,7 +783,7 @@ Veure les Dades apps/client/src/app/components/admin-jobs/admin-jobs.html - 208 + 217 @@ -787,7 +791,7 @@ Veure Stacktrace apps/client/src/app/components/admin-jobs/admin-jobs.html - 216 + 225 @@ -795,7 +799,7 @@ Executar Procés apps/client/src/app/components/admin-jobs/admin-jobs.html - 220 + 229 @@ -803,7 +807,7 @@ Suprimir Procés apps/client/src/app/components/admin-jobs/admin-jobs.html - 224 + 233 @@ -819,7 +823,7 @@ Data apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 161 + 157 libs/ui/src/lib/account-balances/account-balances.component.html @@ -855,7 +859,7 @@ Punts de referència apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 126 + 125 @@ -863,11 +867,11 @@ Divises apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 131 + 130 apps/client/src/app/pages/public/public-page.html - 96 + 95 @@ -875,7 +879,7 @@ ETFs sense País apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 136 + 135 @@ -883,7 +887,7 @@ ETFs sense Sector apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 141 + 140 @@ -891,7 +895,7 @@ Filtra per... apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 385 + 383 @@ -931,7 +935,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 44 + 40 @@ -999,7 +1003,7 @@ Oooh! No s’han pogut recopilar les dades históriques. libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.ts - 262 + 284 @@ -1007,7 +1011,7 @@ El preu de mercat actual és apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 706 + 722 @@ -1031,7 +1035,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 71 + 67 @@ -1063,7 +1067,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 53 + 72 @@ -1075,7 +1079,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 396 + 399 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -1083,7 +1087,7 @@ apps/client/src/app/pages/public/public-page.html - 114 + 113 @@ -1095,7 +1099,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 407 + 410 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -1107,7 +1111,7 @@ Mapatge de Símbols apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 384 + 387 @@ -1123,7 +1127,7 @@ Configuració del Proveïdor de Dades apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 471 + 474 @@ -1131,7 +1135,7 @@ Prova apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 568 + 571 @@ -1139,11 +1143,11 @@ Url apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 419 + 422 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 550 + 553 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -1159,7 +1163,7 @@ Asset profile has been saved apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 578 + 594 @@ -1167,7 +1171,7 @@ Notes apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 432 + 435 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1175,7 +1179,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 275 + 271 @@ -1219,7 +1223,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 124 + 120 @@ -1227,7 +1231,7 @@ Està segur qeu vol eliminar aquest cupó? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 193 + 196 @@ -1235,7 +1239,7 @@ Està segur que vol eliminar aquest missatge del sistema? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 206 + 209 @@ -1243,7 +1247,7 @@ Està segur que vol depurar el cache? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 230 + 233 @@ -1251,7 +1255,7 @@ Si us plau, afegeixi el seu missatge del sistema: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 250 + 253 @@ -1315,7 +1319,7 @@ Recollida de Dades apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 587 + 594 apps/client/src/app/components/admin-overview/admin-overview.html @@ -1387,7 +1391,15 @@ Està segur que vol eliminar aquesta plataforma? apps/client/src/app/components/admin-platform/admin-platform.component.ts - 106 + 111 + + + + Explore + Explore + + apps/client/src/app/pages/resources/overview/resources-overview.component.html + 11 @@ -1411,7 +1423,7 @@ Current year apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 199 + 205 @@ -1427,7 +1439,7 @@ Plataformes apps/client/src/app/components/admin-settings/admin-settings.component.html - 195 + 212 @@ -1435,7 +1447,7 @@ Etiquetes apps/client/src/app/components/admin-settings/admin-settings.component.html - 201 + 218 libs/ui/src/lib/tags-selector/tags-selector.component.html @@ -1459,7 +1471,7 @@ Està segur que vol eliminar aquesta etiqueta? apps/client/src/app/components/admin-tag/admin-tag.component.ts - 103 + 108 @@ -1519,7 +1531,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 89 + 108 @@ -1551,11 +1563,11 @@ Could not validate form apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 554 + 570 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 557 + 573 @@ -1603,7 +1615,7 @@ Punt de Referència apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 376 + 379 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -1679,15 +1691,15 @@ Oooh! El testimoni de seguretat és incorrecte. apps/client/src/app/components/header/header.component.ts - 312 + 313 apps/client/src/app/components/user-account-access/user-account-access.component.ts - 154 + 152 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 193 + 191 @@ -1715,7 +1727,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 189 + 185 libs/ui/src/lib/activities-table/activities-table.component.html @@ -1743,7 +1755,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 88 + 92 @@ -1767,7 +1779,7 @@ Informar d’un Problema amb les Dades apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 451 + 456 @@ -1775,7 +1787,7 @@ en Actiiu apps/client/src/app/components/home-holdings/home-holdings.component.ts - 64 + 63 @@ -1783,7 +1795,7 @@ Finalitzat apps/client/src/app/components/home-holdings/home-holdings.component.ts - 65 + 64 @@ -1807,7 +1819,7 @@ Gestionar Activitats apps/client/src/app/components/home-holdings/home-holdings.html - 67 + 64 @@ -1815,11 +1827,11 @@ Por apps/client/src/app/components/home-market/home-market.component.ts - 42 + 41 apps/client/src/app/components/markets/markets.component.ts - 47 + 46 libs/ui/src/lib/i18n.ts @@ -1831,11 +1843,11 @@ Cobdícia apps/client/src/app/components/home-market/home-market.component.ts - 43 + 42 apps/client/src/app/components/markets/markets.component.ts - 48 + 47 libs/ui/src/lib/i18n.ts @@ -1939,7 +1951,7 @@ Current week apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 191 + 197 @@ -1959,7 +1971,7 @@ Import total apps/client/src/app/components/investment-chart/investment-chart.component.ts - 143 + 146 @@ -2095,7 +2107,7 @@ Rendiment brut absolut apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 73 + 77 @@ -2103,7 +2115,7 @@ Rendiment net absolut apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 107 + 111 apps/client/src/app/pages/portfolio/analysis/analysis-page.html @@ -2115,7 +2127,7 @@ Rendiment net apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 123 + 127 apps/client/src/app/pages/portfolio/analysis/analysis-page.html @@ -2127,7 +2139,7 @@ Actius totals apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 149 + 153 @@ -2135,7 +2147,7 @@ Actius apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 233 @@ -2143,7 +2155,7 @@ Poder adquisitiu apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 241 + 248 @@ -2151,7 +2163,7 @@ Exclòs de l’anàlisi apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 267 + 274 @@ -2159,7 +2171,7 @@ Passius apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 295 + 302 apps/client/src/app/pages/features/features-page.html @@ -2171,7 +2183,7 @@ Valor net apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 317 + 324 @@ -2179,7 +2191,7 @@ Rendiment anualitzat apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 331 + 338 @@ -2339,7 +2351,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 363 + 362 @@ -2347,11 +2359,11 @@ YTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 199 + 205 libs/ui/src/lib/assistant/assistant.component.ts - 375 + 374 @@ -2359,11 +2371,11 @@ 1 any apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 203 + 209 libs/ui/src/lib/assistant/assistant.component.ts - 385 + 384 @@ -2371,11 +2383,11 @@ 5 anys apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 207 + 213 libs/ui/src/lib/assistant/assistant.component.ts - 409 + 408 @@ -2391,11 +2403,11 @@ Màx apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 211 + 217 libs/ui/src/lib/assistant/assistant.component.ts - 415 + 414 @@ -2451,7 +2463,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 11 + 30 @@ -2535,7 +2547,7 @@ Automàtic apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 70 + 69 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -2547,7 +2559,7 @@ De debò vols tancar el teu compte de Ghostfolio? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 208 + 205 @@ -2555,7 +2567,7 @@ De debò vols eliminar aquest mètode d’inici de sessió? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 282 + 279 @@ -2563,7 +2575,7 @@ Include in apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 374 + 377 @@ -2571,7 +2583,7 @@ Ups! Hi ha hagut un error en configurar l’autenticació biomètrica. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 336 + 333 @@ -2619,7 +2631,7 @@ Localització apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 512 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -2763,7 +2775,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 195 + 194 @@ -2783,7 +2795,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 193 + 192 @@ -2799,7 +2811,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 196 + 195 @@ -2935,11 +2947,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 375 + 381 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 66 + 85 apps/client/src/app/pages/accounts/accounts-page.html @@ -3039,7 +3051,7 @@ Dades de mercat apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 398 + 403 libs/common/src/lib/routes/routes.ts @@ -3073,6 +3085,10 @@ Overview Visió general + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 7 + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 114 @@ -3091,11 +3107,11 @@ apps/client/src/app/pages/admin/admin-page.component.ts - 48 + 45 apps/client/src/app/pages/resources/resources-page.component.ts - 30 + 29 libs/common/src/lib/routes/routes.ts @@ -3219,11 +3235,11 @@ Could not parse scraper configuration apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 509 + 525 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 512 + 528 @@ -3239,7 +3255,7 @@ Com que ja has iniciat sessió, no pots accedir al compte de demostració. apps/client/src/app/pages/demo/demo-page.component.ts - 35 + 32 @@ -3267,7 +3283,7 @@ General apps/client/src/app/pages/faq/faq-page.component.ts - 49 + 41 @@ -3275,7 +3291,7 @@ Núvol apps/client/src/app/pages/faq/faq-page.component.ts - 54 + 46 libs/common/src/lib/routes/routes.ts @@ -3287,7 +3303,7 @@ Autoallotjament apps/client/src/app/pages/faq/faq-page.component.ts - 60 + 52 libs/common/src/lib/routes/routes.ts @@ -3436,7 +3452,7 @@ apps/client/src/app/pages/public/public-page.html - 242 + 241 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -3488,7 +3504,7 @@ Mercats apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 378 + 381 apps/client/src/app/components/footer/footer.component.html @@ -3512,7 +3528,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 40 + 39 libs/common/src/lib/routes/routes.ts @@ -3960,7 +3976,7 @@ Job ID apps/client/src/app/components/admin-jobs/admin-jobs.html - 34 + 43 @@ -3996,7 +4012,7 @@ apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 115 + 113 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -4016,11 +4032,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 342 + 348 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 75 + 94 apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -4100,7 +4116,7 @@ Actualitzar el saldo d’efectiu apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 112 + 108 @@ -4108,7 +4124,7 @@ Preu unitari apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 214 + 210 libs/ui/src/lib/activities-table/activities-table.component.html @@ -4136,7 +4152,7 @@ Importar dividends apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 137 + 136 libs/ui/src/lib/activities-table/activities-table.component.html @@ -4152,7 +4168,7 @@ S’estan important dades... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 175 + 174 @@ -4160,7 +4176,7 @@ La importació s’ha completat apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 185 + 184 @@ -4176,7 +4192,7 @@ S’estan validant les dades... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 299 + 293 @@ -4348,7 +4364,7 @@ apps/client/src/app/pages/public/public-page.html - 151 + 150 @@ -4372,7 +4388,7 @@ apps/client/src/app/pages/public/public-page.html - 168 + 167 @@ -4380,7 +4396,7 @@ Latest activities apps/client/src/app/pages/public/public-page.html - 211 + 210 @@ -4392,7 +4408,7 @@ apps/client/src/app/pages/public/public-page.html - 177 + 176 @@ -4404,7 +4420,7 @@ apps/client/src/app/pages/public/public-page.html - 186 + 185 @@ -4480,7 +4496,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 365 + 372 apps/client/src/app/pages/features/features-page.html @@ -4488,11 +4504,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 202 + 198 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 76 + 75 libs/ui/src/lib/i18n.ts @@ -4512,11 +4528,11 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 81 + 80 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 97 + 96 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -4536,7 +4552,7 @@ Mensualment apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 91 + 90 @@ -4544,7 +4560,7 @@ Anualment apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 92 + 91 @@ -4552,7 +4568,7 @@ Close Holding apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 442 + 447 @@ -4848,11 +4864,11 @@ Could not save asset profile apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 588 + 604 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 591 + 607 @@ -4876,7 +4892,7 @@ Continents apps/client/src/app/pages/public/public-page.html - 132 + 131 @@ -4884,7 +4900,7 @@ Vols refinar la teva estratègia d’inversió personal? apps/client/src/app/pages/public/public-page.html - 234 + 233 @@ -4900,7 +4916,7 @@ Ghostfolio us permet fer un seguiment de la vostra riquesa. apps/client/src/app/pages/public/public-page.html - 238 + 237 @@ -4930,6 +4946,10 @@ apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html 88 + + libs/ui/src/lib/value/value.component.html + 18 + Personal Finance Tools @@ -5273,7 +5293,7 @@ Pertinença apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 48 + 67 libs/common/src/lib/routes/routes.ts @@ -5341,7 +5361,7 @@ Realment voleu eliminar el saldo d’aquest compte? libs/ui/src/lib/account-balances/account-balances.component.ts - 120 + 113 @@ -5405,7 +5425,7 @@ De veritat vols suprimir aquestes activitats? libs/ui/src/lib/activities-table/activities-table.component.ts - 278 + 282 @@ -5413,7 +5433,7 @@ Realment vols suprimir aquesta activitat? libs/ui/src/lib/activities-table/activities-table.component.ts - 288 + 292 @@ -5421,7 +5441,7 @@ Setmana fins avui libs/ui/src/lib/assistant/assistant.component.ts - 367 + 366 @@ -5429,11 +5449,11 @@ WTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 191 + 197 libs/ui/src/lib/assistant/assistant.component.ts - 367 + 366 @@ -5441,7 +5461,7 @@ Mes fins a la data libs/ui/src/lib/assistant/assistant.component.ts - 371 + 370 @@ -5449,11 +5469,11 @@ MTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 195 + 201 libs/ui/src/lib/assistant/assistant.component.ts - 371 + 370 @@ -5461,7 +5481,7 @@ Any fins a la data libs/ui/src/lib/assistant/assistant.component.ts - 375 + 374 @@ -5469,7 +5489,7 @@ any apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 203 + 209 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -5481,7 +5501,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 385 + 384 @@ -5489,11 +5509,11 @@ anys apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 207 + 213 libs/ui/src/lib/assistant/assistant.component.ts - 409 + 408 @@ -5501,7 +5521,7 @@ Perfils d’actius apps/client/src/app/components/admin-settings/admin-settings.component.html - 106 + 123 libs/ui/src/lib/assistant/assistant.html @@ -5641,7 +5661,7 @@ Dipòsit libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 377 + 404 @@ -5653,11 +5673,11 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 352 + 359 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 387 + 414 libs/ui/src/lib/i18n.ts @@ -5669,7 +5689,7 @@ Estalvi libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 397 + 424 @@ -5697,7 +5717,7 @@ Mostra-ho tot libs/ui/src/lib/holdings-table/holdings-table.component.html - 216 + 212 @@ -5741,7 +5761,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 326 + 327 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -5749,7 +5769,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 290 + 286 libs/ui/src/lib/i18n.ts @@ -5773,7 +5793,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 342 + 343 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -5781,7 +5801,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 309 + 305 libs/ui/src/lib/i18n.ts @@ -5833,7 +5853,7 @@ Fons d’emergència apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 164 + 168 apps/client/src/app/pages/features/features-page.html @@ -5909,7 +5929,7 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 437 + 451 @@ -5920,6 +5940,14 @@ 27 + + No Activities + No Activities + + apps/client/src/app/components/admin-market-data/admin-market-data.component.ts + 145 + + Retirement Provision Provisió de jubilació @@ -5949,7 +5977,7 @@ Símbol apps/client/src/app/components/admin-jobs/admin-jobs.html - 68 + 77 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -5965,7 +5993,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 315 + 318 libs/ui/src/lib/i18n.ts @@ -6037,7 +6065,7 @@ Comissió apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 262 + 258 libs/ui/src/lib/activities-table/activities-table.component.html @@ -6081,7 +6109,7 @@ Efectiu apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 212 + 219 libs/ui/src/lib/i18n.ts @@ -6137,7 +6165,7 @@ Authentication apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 35 + 54 @@ -6281,7 +6309,7 @@ Vàlid fins a apps/client/src/app/components/admin-settings/admin-settings.component.html - 74 + 86 libs/ui/src/lib/membership-card/membership-card.component.html @@ -6305,7 +6333,7 @@ apps/client/src/app/pages/public/public-page.html - 196 + 195 libs/ui/src/lib/benchmark/benchmark.component.html @@ -6313,11 +6341,11 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 439 + 453 libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 452 + 467 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -6661,7 +6689,7 @@ Error apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 697 + 713 @@ -6713,7 +6741,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 592 + 599 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6745,7 +6773,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 345 + 341 apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html @@ -6753,7 +6781,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 46 + 47 libs/ui/src/lib/i18n.ts @@ -6765,7 +6793,7 @@ Close apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 594 + 601 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6791,13 +6819,17 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 68 + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 127 + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html 107 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 347 + 343 libs/ui/src/lib/i18n.ts @@ -6809,7 +6841,7 @@ Role apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 14 + 33 @@ -6833,7 +6865,7 @@ Portfolio Snapshot apps/client/src/app/components/admin-jobs/admin-jobs.html - 56 + 65 @@ -6900,6 +6932,14 @@ 42 + + has been copied to the clipboard + has been copied to the clipboard + + libs/ui/src/lib/value/value.component.ts + 180 + + From the beginning From the beginning @@ -7065,7 +7105,7 @@ Set API key apps/client/src/app/components/admin-settings/admin-settings.component.html - 171 + 188 @@ -7101,7 +7141,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 45 + 44 libs/common/src/lib/routes/routes.ts @@ -7117,7 +7157,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 34 + 33 libs/common/src/lib/routes/routes.ts @@ -7171,7 +7211,7 @@ of apps/client/src/app/components/admin-settings/admin-settings.component.html - 135 + 152 @@ -7179,7 +7219,7 @@ daily requests apps/client/src/app/components/admin-settings/admin-settings.component.html - 137 + 154 @@ -7187,7 +7227,7 @@ Remove API key apps/client/src/app/components/admin-settings/admin-settings.component.html - 161 + 178 @@ -7195,7 +7235,7 @@ Do you really want to delete the API key? apps/client/src/app/components/admin-settings/admin-settings.component.ts - 127 + 133 @@ -7215,7 +7255,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 98 + 117 @@ -7287,7 +7327,7 @@ Save apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 603 + 610 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7323,11 +7363,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 356 + 352 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 48 + 49 @@ -7339,7 +7379,7 @@ apps/client/src/app/components/user-account-access/user-account-access.component.ts - 260 + 257 @@ -7363,7 +7403,7 @@ Please enter your Ghostfolio API key. apps/client/src/app/components/admin-settings/admin-settings.component.ts - 146 + 152 @@ -7379,7 +7419,7 @@ AI prompt has been copied to the clipboard apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 201 + 199 @@ -7395,7 +7435,7 @@ Lazy apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 225 + 231 @@ -7403,7 +7443,7 @@ Instant apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 229 + 235 @@ -7411,7 +7451,7 @@ Default Market Price apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 481 + 484 @@ -7419,7 +7459,7 @@ Mode apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 518 + 521 @@ -7427,7 +7467,7 @@ Selector apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 534 + 537 @@ -7435,7 +7475,7 @@ HTTP Request Headers apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 494 + 497 @@ -7443,7 +7483,7 @@ end of day apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 225 + 231 @@ -7451,7 +7491,7 @@ real-time apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 229 + 235 @@ -7459,7 +7499,7 @@ Open Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 202 + 200 @@ -7479,7 +7519,7 @@ libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 377 @@ -7491,7 +7531,7 @@ apps/client/src/app/components/home-overview/home-overview.component.ts - 55 + 54 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -7499,11 +7539,11 @@ libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 377 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 381 + 390 @@ -7607,11 +7647,11 @@ Security token apps/client/src/app/components/admin-users/admin-users.component.ts - 236 + 235 apps/client/src/app/components/user-account-access/user-account-access.component.ts - 170 + 167 @@ -7619,7 +7659,7 @@ Do you really want to generate a new security token for this user? apps/client/src/app/components/admin-users/admin-users.component.ts - 241 + 240 @@ -7627,7 +7667,7 @@ Find account, holding or page... libs/ui/src/lib/assistant/assistant.component.ts - 151 + 115 @@ -7692,7 +7732,7 @@ () is already in use. apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 633 + 649 @@ -7700,7 +7740,7 @@ An error occurred while updating to (). apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 641 + 657 @@ -7764,7 +7804,7 @@ someone apps/client/src/app/pages/public/public-page.component.ts - 59 + 61 @@ -7796,7 +7836,7 @@ Do you really want to delete this item? libs/ui/src/lib/benchmark/benchmark.component.ts - 144 + 139 @@ -7837,7 +7877,7 @@ Demo user account has been synced. apps/client/src/app/components/admin-overview/admin-overview.component.ts - 274 + 277 @@ -7872,7 +7912,7 @@ 150 - + Fee Ratio Fee Ratio @@ -7880,17 +7920,17 @@ 152 - - The fees do exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - The fees do exceed ${thresholdMax}% of your initial investment (${feeRatio}%) + + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 154 - - The fees do not exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - The fees do not exceed ${thresholdMax}% of your initial investment (${feeRatio}%) + + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 158 @@ -8051,7 +8091,7 @@ Current month apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 195 + 201 @@ -8059,11 +8099,11 @@ new apps/client/src/app/components/admin-settings/admin-settings.component.html - 67 + 79 apps/client/src/app/pages/admin/admin-page.component.ts - 56 + 53 @@ -8220,7 +8260,7 @@ Do you really want to generate a new security token? apps/client/src/app/components/user-account-access/user-account-access.component.ts - 175 + 172 @@ -8244,7 +8284,7 @@ Stocks apps/client/src/app/components/markets/markets.component.ts - 52 + 51 apps/client/src/app/pages/features/features-page.html @@ -8256,7 +8296,7 @@ Cryptocurrencies apps/client/src/app/components/markets/markets.component.ts - 53 + 52 apps/client/src/app/pages/features/features-page.html @@ -8276,7 +8316,7 @@ Manage Asset Profile apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 466 + 471 @@ -8696,7 +8736,7 @@ Registration Date apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 26 + 45 diff --git a/apps/client/src/locales/messages.de.xlf b/apps/client/src/locales/messages.de.xlf index 44ee607c3..ff12aebcb 100644 --- a/apps/client/src/locales/messages.de.xlf +++ b/apps/client/src/locales/messages.de.xlf @@ -50,7 +50,7 @@ Typ apps/client/src/app/components/admin-jobs/admin-jobs.html - 48 + 57 apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html @@ -106,7 +106,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 309 + 310 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -118,7 +118,7 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 46 + 58 apps/client/src/app/components/admin-tag/admin-tag.component.html @@ -134,7 +134,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 139 + 135 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -178,15 +178,15 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 205 + 201 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 208 + 204 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 211 + 207 libs/ui/src/lib/account-balances/account-balances.component.html @@ -234,11 +234,11 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 74 + 78 apps/client/src/app/components/admin-tag/admin-tag.component.html - 67 + 71 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -266,11 +266,15 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 85 + 89 apps/client/src/app/components/admin-tag/admin-tag.component.html - 78 + 82 + + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 22 libs/ui/src/lib/account-balances/account-balances.component.html @@ -294,7 +298,7 @@ Möchtest du dieses Konto wirklich löschen? libs/ui/src/lib/accounts-table/accounts-table.component.ts - 150 + 148 @@ -302,7 +306,7 @@ Jobs löschen apps/client/src/app/components/admin-jobs/admin-jobs.html - 193 + 202 @@ -310,7 +314,7 @@ Datenquelle apps/client/src/app/components/admin-jobs/admin-jobs.html - 82 + 91 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -322,7 +326,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 155 + 151 libs/ui/src/lib/i18n.ts @@ -334,7 +338,7 @@ Versuche apps/client/src/app/components/admin-jobs/admin-jobs.html - 120 + 129 @@ -342,7 +346,7 @@ Erstellt apps/client/src/app/components/admin-jobs/admin-jobs.html - 134 + 143 @@ -350,7 +354,7 @@ Abgeschlossen apps/client/src/app/components/admin-jobs/admin-jobs.html - 143 + 152 @@ -358,11 +362,11 @@ Status apps/client/src/app/components/admin-jobs/admin-jobs.html - 152 + 161 apps/client/src/app/components/admin-settings/admin-settings.component.html - 92 + 104 @@ -378,7 +382,7 @@ Anlageprofile apps/client/src/app/components/admin-settings/admin-settings.component.html - 106 + 123 libs/ui/src/lib/assistant/assistant.html @@ -390,11 +394,11 @@ Historische Marktdaten apps/client/src/app/components/admin-jobs/admin-jobs.html - 54 + 63 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 448 + 451 @@ -402,7 +406,7 @@ Daten anzeigen apps/client/src/app/components/admin-jobs/admin-jobs.html - 208 + 217 @@ -410,7 +414,7 @@ Stacktrace anzeigen apps/client/src/app/components/admin-jobs/admin-jobs.html - 216 + 225 @@ -418,7 +422,7 @@ Job löschen apps/client/src/app/components/admin-jobs/admin-jobs.html - 224 + 233 @@ -434,7 +438,7 @@ Datum apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 161 + 157 libs/ui/src/lib/account-balances/account-balances.component.html @@ -502,7 +506,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 44 + 40 @@ -510,7 +514,7 @@ Möchtest du diesen Gutscheincode wirklich löschen? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 193 + 196 @@ -518,7 +522,7 @@ Möchtest du den Cache wirklich leeren? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 230 + 233 @@ -526,7 +530,7 @@ Bitte gebe deine Systemmeldung ein: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 250 + 253 @@ -682,7 +686,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 89 + 108 @@ -738,7 +742,7 @@ apps/client/src/app/pages/public/public-page.html - 242 + 241 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -754,7 +758,7 @@ apps/client/src/app/components/header/header.component.ts - 297 + 298 apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html @@ -774,15 +778,15 @@ Ups! Falsches Sicherheits-Token. apps/client/src/app/components/header/header.component.ts - 312 + 313 apps/client/src/app/components/user-account-access/user-account-access.component.ts - 154 + 152 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 193 + 191 @@ -790,7 +794,7 @@ Aktivitäten verwalten apps/client/src/app/components/home-holdings/home-holdings.html - 67 + 64 @@ -906,7 +910,7 @@ Absolute Brutto Performance apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 73 + 77 @@ -914,7 +918,7 @@ Absolute Netto Performance apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 107 + 111 apps/client/src/app/pages/portfolio/analysis/analysis-page.html @@ -926,7 +930,7 @@ Netto Performance apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 123 + 127 apps/client/src/app/pages/portfolio/analysis/analysis-page.html @@ -938,7 +942,7 @@ Gesamtanlagevermögen apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 149 + 153 @@ -946,7 +950,7 @@ Kaufkraft apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 241 + 248 @@ -954,7 +958,7 @@ Gesamtvermögen apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 317 + 324 @@ -962,7 +966,7 @@ Performance pro Jahr apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 331 + 338 @@ -982,7 +986,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 396 + 399 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -990,7 +994,7 @@ apps/client/src/app/pages/public/public-page.html - 114 + 113 @@ -1002,7 +1006,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 407 + 410 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -1014,7 +1018,7 @@ Tags apps/client/src/app/components/admin-settings/admin-settings.component.html - 201 + 218 libs/ui/src/lib/tags-selector/tags-selector.component.html @@ -1030,7 +1034,7 @@ Datenfehler melden apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 451 + 456 @@ -1058,7 +1062,7 @@ Alle anzeigen libs/ui/src/lib/holdings-table/holdings-table.component.html - 216 + 212 @@ -1070,7 +1074,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 363 + 362 @@ -1078,11 +1082,11 @@ YTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 199 + 205 libs/ui/src/lib/assistant/assistant.component.ts - 375 + 374 @@ -1090,11 +1094,11 @@ 1J apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 203 + 209 libs/ui/src/lib/assistant/assistant.component.ts - 385 + 384 @@ -1102,11 +1106,11 @@ 5J apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 207 + 213 libs/ui/src/lib/assistant/assistant.component.ts - 409 + 408 @@ -1122,11 +1126,11 @@ Max apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 211 + 217 libs/ui/src/lib/assistant/assistant.component.ts - 415 + 414 @@ -1142,7 +1146,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 196 + 195 @@ -1234,7 +1238,7 @@ Möchtest du diese Anmeldemethode wirklich löschen? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 282 + 279 @@ -1294,7 +1298,7 @@ Lokalität apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 512 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -1342,7 +1346,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 11 + 30 @@ -1390,11 +1394,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 375 + 381 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 66 + 85 apps/client/src/app/pages/accounts/accounts-page.html @@ -1434,7 +1438,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 316 + 317 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -1446,7 +1450,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 145 + 141 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -1626,7 +1630,7 @@ Da du bereits eingeloggt bist, kannst du nicht auf die Live Demo zugreifen. apps/client/src/app/pages/demo/demo-page.component.ts - 35 + 32 @@ -1672,6 +1676,10 @@ Overview Übersicht + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 7 + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 114 @@ -1690,11 +1698,11 @@ apps/client/src/app/pages/admin/admin-page.component.ts - 48 + 45 apps/client/src/app/pages/resources/resources-page.component.ts - 30 + 29 libs/common/src/lib/routes/routes.ts @@ -1710,7 +1718,7 @@ Märkte apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 378 + 381 apps/client/src/app/components/footer/footer.component.html @@ -1734,7 +1742,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 40 + 39 libs/common/src/lib/routes/routes.ts @@ -1834,7 +1842,7 @@ apps/client/src/app/pages/public/public-page.html - 151 + 150 @@ -1930,7 +1938,7 @@ Aktuelle Woche apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 191 + 197 @@ -1974,7 +1982,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 124 + 120 @@ -1986,7 +1994,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 189 + 185 libs/ui/src/lib/activities-table/activities-table.component.html @@ -2002,7 +2010,7 @@ Stückpreis apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 214 + 210 libs/ui/src/lib/activities-table/activities-table.component.html @@ -2014,7 +2022,7 @@ Kommentar apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 432 + 435 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -2022,7 +2030,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 275 + 271 @@ -2034,7 +2042,7 @@ apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 115 + 113 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -2054,11 +2062,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 342 + 348 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 75 + 94 apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -2078,7 +2086,7 @@ Daten importieren... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 175 + 174 @@ -2086,7 +2094,7 @@ Der Import wurde abgeschlossen apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 185 + 184 @@ -2158,7 +2166,7 @@ Kontinente apps/client/src/app/pages/public/public-page.html - 132 + 131 @@ -2174,7 +2182,7 @@ Ghostfolio verschafft dir den Überblick über dein Vermögen. apps/client/src/app/pages/public/public-page.html - 238 + 237 @@ -2204,6 +2212,10 @@ apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html 88 + + libs/ui/src/lib/value/value.component.html + 18 + Resources @@ -2322,7 +2334,7 @@ Möchtest du diese Aktivität wirklich löschen? libs/ui/src/lib/activities-table/activities-table.component.ts - 288 + 292 @@ -2394,7 +2406,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 195 + 194 @@ -2406,7 +2418,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 193 + 192 @@ -2454,7 +2466,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 53 + 72 @@ -2478,7 +2490,7 @@ apps/client/src/app/pages/public/public-page.html - 168 + 167 @@ -2486,7 +2498,7 @@ Neueste Aktivitäten apps/client/src/app/pages/public/public-page.html - 211 + 210 @@ -2498,7 +2510,7 @@ apps/client/src/app/pages/public/public-page.html - 177 + 176 @@ -2510,7 +2522,7 @@ apps/client/src/app/pages/public/public-page.html - 186 + 185 @@ -2526,7 +2538,7 @@ Monatlich apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 91 + 90 @@ -2542,7 +2554,7 @@ Einlage libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 377 + 404 @@ -2554,11 +2566,11 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 352 + 359 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 387 + 414 libs/ui/src/lib/i18n.ts @@ -2570,7 +2582,7 @@ Ersparnisse libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 397 + 424 @@ -2594,11 +2606,11 @@ Angst apps/client/src/app/components/home-market/home-market.component.ts - 42 + 41 apps/client/src/app/components/markets/markets.component.ts - 47 + 46 libs/ui/src/lib/i18n.ts @@ -2610,11 +2622,11 @@ Gier apps/client/src/app/components/home-market/home-market.component.ts - 43 + 42 apps/client/src/app/components/markets/markets.component.ts - 48 + 47 libs/ui/src/lib/i18n.ts @@ -2626,7 +2638,7 @@ Filtern nach... apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 385 + 383 @@ -2662,11 +2674,11 @@ Das Formular konnte nicht validiert werden apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 554 + 570 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 557 + 573 @@ -2682,7 +2694,7 @@ Benchmark apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 376 + 379 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -2702,7 +2714,7 @@ Von der Analyse ausgenommen apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 267 + 274 @@ -2710,7 +2722,7 @@ Automatisch apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 70 + 69 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -2746,7 +2758,7 @@ Gesamtbetrag apps/client/src/app/components/investment-chart/investment-chart.component.ts - 143 + 146 @@ -2798,7 +2810,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 326 + 327 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -2806,7 +2818,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 290 + 286 libs/ui/src/lib/i18n.ts @@ -2822,7 +2834,7 @@ Symbol apps/client/src/app/components/admin-jobs/admin-jobs.html - 68 + 77 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -2838,7 +2850,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 315 + 318 libs/ui/src/lib/i18n.ts @@ -2862,7 +2874,7 @@ Bargeld apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 212 + 219 libs/ui/src/lib/i18n.ts @@ -2910,7 +2922,7 @@ Authentifizierung apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 35 + 54 @@ -2974,7 +2986,7 @@ Notfallfonds apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 164 + 168 apps/client/src/app/pages/features/features-page.html @@ -2994,7 +3006,7 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 437 + 451 @@ -3006,7 +3018,7 @@ apps/client/src/app/pages/public/public-page.html - 196 + 195 libs/ui/src/lib/benchmark/benchmark.component.html @@ -3014,11 +3026,11 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 439 + 453 libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 452 + 467 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -3122,7 +3134,7 @@ Symbol Zuordnung apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 384 + 387 @@ -3154,7 +3166,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 365 + 372 apps/client/src/app/pages/features/features-page.html @@ -3162,11 +3174,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 202 + 198 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 76 + 75 libs/ui/src/lib/i18n.ts @@ -3186,7 +3198,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 342 + 343 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -3194,7 +3206,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 309 + 305 libs/ui/src/lib/i18n.ts @@ -3214,7 +3226,7 @@ Daten validieren... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 299 + 293 @@ -3230,7 +3242,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 71 + 67 @@ -3238,7 +3250,7 @@ Marktdaten apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 398 + 403 libs/common/src/lib/routes/routes.ts @@ -3290,7 +3302,7 @@ Jährlich apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 92 + 91 @@ -3298,7 +3310,7 @@ Dividenden importieren apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 137 + 136 libs/ui/src/lib/activities-table/activities-table.component.html @@ -3314,7 +3326,7 @@ Gültig bis apps/client/src/app/components/admin-settings/admin-settings.component.html - 74 + 86 libs/ui/src/lib/membership-card/membership-card.component.html @@ -3353,6 +3365,14 @@ 22 + + No Activities + Keine Aktivitäten + + apps/client/src/app/components/admin-market-data/admin-market-data.component.ts + 145 + + Retirement Provision Altersvorsorge @@ -3626,11 +3646,11 @@ Das Anlageprofil konnte nicht gespeichert werden apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 588 + 604 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 591 + 607 @@ -3650,7 +3670,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 88 + 92 @@ -3822,7 +3842,7 @@ Möchtest du diese Aktivitäten wirklich löschen? libs/ui/src/lib/activities-table/activities-table.component.ts - 278 + 282 @@ -3833,6 +3853,14 @@ 306 + + Explore + Entdecke + + apps/client/src/app/pages/resources/overview/resources-overview.component.html + 11 + + By Bis @@ -3854,7 +3882,7 @@ Aktuelles Jahr apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 199 + 205 @@ -3870,11 +3898,11 @@ Url apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 419 + 422 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 550 + 553 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -3890,7 +3918,7 @@ Das Anlageprofil wurde gespeichert apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 578 + 594 @@ -3898,7 +3926,7 @@ Möchtest du diese Plattform wirklich löschen? apps/client/src/app/components/admin-platform/admin-platform.component.ts - 106 + 111 @@ -3906,7 +3934,7 @@ Plattformen apps/client/src/app/components/admin-settings/admin-settings.component.html - 195 + 212 @@ -3914,7 +3942,7 @@ Cash-Bestand aktualisieren apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 112 + 108 @@ -4094,7 +4122,7 @@ Verbindlichkeiten apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 295 + 302 apps/client/src/app/pages/features/features-page.html @@ -4250,7 +4278,7 @@ Scraper Konfiguration apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 471 + 474 @@ -4494,7 +4522,7 @@ ETFs ohne Länder apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 136 + 135 @@ -4502,7 +4530,7 @@ ETFs ohne Sektoren apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 141 + 140 @@ -4510,7 +4538,7 @@ Anlagevermögen apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 233 @@ -4682,7 +4710,7 @@ Job ID apps/client/src/app/components/admin-jobs/admin-jobs.html - 34 + 43 @@ -4738,11 +4766,11 @@ Währungen apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 131 + 130 apps/client/src/app/pages/public/public-page.html - 96 + 95 @@ -4790,11 +4818,11 @@ Die Scraper Konfiguration konnte nicht geparsed werden apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 509 + 525 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 512 + 528 @@ -5456,7 +5484,7 @@ Gebühr apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 262 + 258 libs/ui/src/lib/activities-table/activities-table.component.html @@ -5488,7 +5516,7 @@ Möchtest du diesen Tag wirklich löschen? apps/client/src/app/components/admin-tag/admin-tag.component.ts - 103 + 108 @@ -5556,7 +5584,7 @@ Mitgliedschaft apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 48 + 67 libs/common/src/lib/routes/routes.ts @@ -5588,7 +5616,7 @@ Anlageprofil apps/client/src/app/components/admin-jobs/admin-jobs.html - 52 + 61 @@ -5712,7 +5740,7 @@ Ups! Die historischen Daten konnten nicht geparsed werden. libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.ts - 262 + 284 @@ -5720,7 +5748,7 @@ Möchtest du diese Systemmeldung wirklich löschen? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 206 + 209 @@ -5744,7 +5772,7 @@ Cash-Bestände apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 148 + 146 @@ -5764,7 +5792,7 @@ Möchtest du diesen Cash-Bestand wirklich löschen? libs/ui/src/lib/account-balances/account-balances.component.ts - 120 + 113 @@ -5780,7 +5808,7 @@ Der aktuelle Marktpreis ist apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 706 + 722 @@ -5788,7 +5816,7 @@ Test apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 568 + 571 @@ -5876,11 +5904,11 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 81 + 80 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 97 + 96 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -5900,7 +5928,7 @@ Position abschliessen apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 442 + 447 @@ -5940,7 +5968,7 @@ Seit Wochenbeginn libs/ui/src/lib/assistant/assistant.component.ts - 367 + 366 @@ -5948,11 +5976,11 @@ WTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 191 + 197 libs/ui/src/lib/assistant/assistant.component.ts - 367 + 366 @@ -5960,7 +5988,7 @@ Seit Monatsbeginn libs/ui/src/lib/assistant/assistant.component.ts - 371 + 370 @@ -5968,11 +5996,11 @@ MTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 195 + 201 libs/ui/src/lib/assistant/assistant.component.ts - 371 + 370 @@ -5980,7 +6008,7 @@ Seit Jahresbeginn libs/ui/src/lib/assistant/assistant.component.ts - 375 + 374 @@ -6016,7 +6044,7 @@ Jahr apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 203 + 209 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -6028,7 +6056,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 385 + 384 @@ -6036,11 +6064,11 @@ Jahre apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 207 + 213 libs/ui/src/lib/assistant/assistant.component.ts - 409 + 408 @@ -6056,7 +6084,7 @@ Finanzmarktdaten synchronisieren apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 587 + 594 apps/client/src/app/components/admin-overview/admin-overview.html @@ -6068,7 +6096,7 @@ Allgemein apps/client/src/app/pages/faq/faq-page.component.ts - 49 + 41 @@ -6076,7 +6104,7 @@ Cloud apps/client/src/app/pages/faq/faq-page.component.ts - 54 + 46 libs/common/src/lib/routes/routes.ts @@ -6088,7 +6116,7 @@ Self-Hosting apps/client/src/app/pages/faq/faq-page.component.ts - 60 + 52 libs/common/src/lib/routes/routes.ts @@ -6129,7 +6157,7 @@ Aktiv apps/client/src/app/components/home-holdings/home-holdings.component.ts - 64 + 63 @@ -6137,7 +6165,7 @@ Abgeschlossen apps/client/src/app/components/home-holdings/home-holdings.component.ts - 65 + 64 @@ -6169,7 +6197,7 @@ Job ausführen apps/client/src/app/components/admin-jobs/admin-jobs.html - 220 + 229 @@ -6177,7 +6205,7 @@ Priorität apps/client/src/app/components/admin-jobs/admin-jobs.html - 96 + 105 @@ -6233,7 +6261,7 @@ Möchtest du dieses Ghostfolio Konto wirklich schliessen? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 208 + 205 @@ -6281,7 +6309,7 @@ Berücksichtigen in apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 374 + 377 @@ -6289,7 +6317,7 @@ Ups! Beim Einrichten der biometrischen Authentifizierung ist ein Fehler aufgetreten. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 336 + 333 @@ -6305,7 +6333,7 @@ Benchmarks apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 126 + 125 @@ -6353,7 +6381,7 @@ Möchtest du deine persönliche Anlagestrategie verfeinern? apps/client/src/app/pages/public/public-page.html - 234 + 233 @@ -6685,7 +6713,7 @@ Fehler apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 697 + 713 @@ -6737,7 +6765,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 592 + 599 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6769,7 +6797,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 345 + 341 apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html @@ -6777,7 +6805,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 46 + 47 libs/ui/src/lib/i18n.ts @@ -6789,7 +6817,7 @@ Schliessen apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 594 + 601 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6815,13 +6843,17 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 68 + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 127 + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html 107 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 347 + 343 libs/ui/src/lib/i18n.ts @@ -6833,7 +6865,7 @@ Rolle apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 14 + 33 @@ -6857,7 +6889,7 @@ Portfolio Snapshot apps/client/src/app/components/admin-jobs/admin-jobs.html - 56 + 65 @@ -6924,6 +6956,14 @@ 42 + + has been copied to the clipboard + wurde in die Zwischenablage kopiert + + libs/ui/src/lib/value/value.component.ts + 180 + + From the beginning Seit Beginn @@ -7089,7 +7129,7 @@ API-Schlüssel setzen apps/client/src/app/components/admin-settings/admin-settings.component.html - 171 + 188 @@ -7125,7 +7165,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 45 + 44 libs/common/src/lib/routes/routes.ts @@ -7141,7 +7181,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 34 + 33 libs/common/src/lib/routes/routes.ts @@ -7195,7 +7235,7 @@ von apps/client/src/app/components/admin-settings/admin-settings.component.html - 135 + 152 @@ -7203,7 +7243,7 @@ täglichen Anfragen apps/client/src/app/components/admin-settings/admin-settings.component.html - 137 + 154 @@ -7211,7 +7251,7 @@ API-Schlüssel löschen apps/client/src/app/components/admin-settings/admin-settings.component.html - 161 + 178 @@ -7219,7 +7259,7 @@ Möchtest du den API-Schlüssel wirklich löschen? apps/client/src/app/components/admin-settings/admin-settings.component.ts - 127 + 133 @@ -7239,7 +7279,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 98 + 117 @@ -7311,7 +7351,7 @@ Speichern apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 603 + 610 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7347,11 +7387,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 356 + 352 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 48 + 49 @@ -7363,7 +7403,7 @@ apps/client/src/app/components/user-account-access/user-account-access.component.ts - 260 + 257 @@ -7387,7 +7427,7 @@ Bitte gebe deinen Ghostfolio API-Schlüssel ein. apps/client/src/app/components/admin-settings/admin-settings.component.ts - 146 + 152 @@ -7403,7 +7443,7 @@ KI-Anweisung wurde in die Zwischenablage kopiert apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 201 + 199 @@ -7419,7 +7459,7 @@ Verzögert apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 225 + 231 @@ -7427,7 +7467,7 @@ Sofort apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 229 + 235 @@ -7435,7 +7475,7 @@ Standardmarktpreis apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 481 + 484 @@ -7443,7 +7483,7 @@ Modus apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 518 + 521 @@ -7451,7 +7491,7 @@ Selektor apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 534 + 537 @@ -7459,7 +7499,7 @@ HTTP Request-Headers apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 494 + 497 @@ -7467,7 +7507,7 @@ Tagesende apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 225 + 231 @@ -7475,7 +7515,7 @@ in Echtzeit apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 229 + 235 @@ -7483,7 +7523,7 @@ Öffne Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 202 + 200 @@ -7503,7 +7543,7 @@ libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 377 @@ -7515,7 +7555,7 @@ apps/client/src/app/components/home-overview/home-overview.component.ts - 55 + 54 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -7523,11 +7563,11 @@ libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 377 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 381 + 390 @@ -7631,11 +7671,11 @@ Sicherheits-Token apps/client/src/app/components/admin-users/admin-users.component.ts - 236 + 235 apps/client/src/app/components/user-account-access/user-account-access.component.ts - 170 + 167 @@ -7643,7 +7683,7 @@ Möchtest du für diesen Benutzer wirklich ein neues Sicherheits-Token generieren? apps/client/src/app/components/admin-users/admin-users.component.ts - 241 + 240 @@ -7651,7 +7691,7 @@ Konto, Position oder Seite finden... libs/ui/src/lib/assistant/assistant.component.ts - 151 + 115 @@ -7716,7 +7756,7 @@ () wird bereits verwendet. apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 633 + 649 @@ -7724,7 +7764,7 @@ Bei der Änderung zu () ist ein Fehler aufgetreten. apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 641 + 657 @@ -7764,7 +7804,7 @@ jemand apps/client/src/app/pages/public/public-page.component.ts - 59 + 61 @@ -7796,7 +7836,7 @@ Möchtest du diesen Eintrag wirklich löschen? libs/ui/src/lib/benchmark/benchmark.component.ts - 144 + 139 @@ -7837,12 +7877,12 @@ Demo Benutzerkonto wurde synchronisiert. apps/client/src/app/components/admin-overview/admin-overview.component.ts - 274 + 277 Sync Demo User Account - Synchronisiere Demo Benutzerkonto + Synchronisiere Demo Benutzerkonto apps/client/src/app/components/admin-overview/admin-overview.html 195 @@ -7872,7 +7912,7 @@ 150 - + Fee Ratio Gebührenverhältnis @@ -7880,17 +7920,17 @@ 152 - - The fees do exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - Die Gebühren übersteigen ${thresholdMax}% deiner ursprünglichen Investition (${feeRatio}%) + + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + Die Gebühren übersteigen ${thresholdMax}% deines gesamten Investitionsvolumens (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 154 - - The fees do not exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - Die Gebühren übersteigen ${thresholdMax}% deiner ursprünglichen Investition (${feeRatio}%) nicht + + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + Die Gebühren übersteigen ${thresholdMax}% deines gesamten Investitionsvolumens (${feeRatio}%) nicht apps/client/src/app/pages/i18n/i18n-page.html 158 @@ -8051,7 +8091,7 @@ Aktueller Monat apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 195 + 201 @@ -8059,11 +8099,11 @@ neu apps/client/src/app/components/admin-settings/admin-settings.component.html - 67 + 79 apps/client/src/app/pages/admin/admin-page.component.ts - 56 + 53 @@ -8220,7 +8260,7 @@ Möchtest du wirklich ein neues Sicherheits-Token generieren? apps/client/src/app/components/user-account-access/user-account-access.component.ts - 175 + 172 @@ -8244,7 +8284,7 @@ Aktien apps/client/src/app/components/markets/markets.component.ts - 52 + 51 apps/client/src/app/pages/features/features-page.html @@ -8256,7 +8296,7 @@ Kryptowährungen apps/client/src/app/components/markets/markets.component.ts - 53 + 52 apps/client/src/app/pages/features/features-page.html @@ -8276,7 +8316,7 @@ Anlageprofil verwalten apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 466 + 471 @@ -8696,7 +8736,7 @@ Registrierungsdatum apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 26 + 45 diff --git a/apps/client/src/locales/messages.es.xlf b/apps/client/src/locales/messages.es.xlf index 7564e4d80..26c76ef6c 100644 --- a/apps/client/src/locales/messages.es.xlf +++ b/apps/client/src/locales/messages.es.xlf @@ -32,7 +32,7 @@ Grantee - Beneficiario + Usuario autorizado apps/client/src/app/components/access-table/access-table.component.html 11 @@ -51,7 +51,7 @@ Tipo apps/client/src/app/components/admin-jobs/admin-jobs.html - 48 + 57 apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html @@ -76,7 +76,7 @@ Revoke - Revoca + Revocar apps/client/src/app/components/access-table/access-table.component.html 96 @@ -92,7 +92,7 @@ Do you really want to revoke this granted access? - ¿Quieres revocar el acceso concedido? + ¿Seguro que quieres revocar el acceso concedido? apps/client/src/app/components/access-table/access-table.component.ts 113 @@ -107,7 +107,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 309 + 310 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -119,7 +119,7 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 46 + 58 apps/client/src/app/components/admin-tag/admin-tag.component.html @@ -135,7 +135,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 139 + 135 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -179,15 +179,15 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 205 + 201 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 208 + 204 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 211 + 207 libs/ui/src/lib/account-balances/account-balances.component.html @@ -224,7 +224,7 @@ Edit - Edita + Editar apps/client/src/app/components/access-table/access-table.component.html 76 @@ -235,11 +235,11 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 74 + 78 apps/client/src/app/components/admin-tag/admin-tag.component.html - 67 + 71 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -252,7 +252,7 @@ Delete - Elimina + Eliminar apps/client/src/app/components/admin-market-data/admin-market-data.html 289 @@ -267,11 +267,15 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 85 + 89 apps/client/src/app/components/admin-tag/admin-tag.component.html - 78 + 82 + + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 22 libs/ui/src/lib/account-balances/account-balances.component.html @@ -292,18 +296,18 @@ Do you really want to delete this account? - ¿Estás seguro de eliminar esta cuenta? + ¿Seguro que quieres eliminar esta cuenta? libs/ui/src/lib/accounts-table/accounts-table.component.ts - 150 + 148 Delete Jobs - Elimina los trabajos + Eliminar trabajos apps/client/src/app/components/admin-jobs/admin-jobs.html - 193 + 202 @@ -311,7 +315,7 @@ Fuente de datos apps/client/src/app/components/admin-jobs/admin-jobs.html - 82 + 91 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -323,7 +327,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 155 + 151 libs/ui/src/lib/i18n.ts @@ -335,7 +339,7 @@ Intentos apps/client/src/app/components/admin-jobs/admin-jobs.html - 120 + 129 @@ -343,7 +347,7 @@ Creado apps/client/src/app/components/admin-jobs/admin-jobs.html - 134 + 143 @@ -351,7 +355,7 @@ Finalizado apps/client/src/app/components/admin-jobs/admin-jobs.html - 143 + 152 @@ -359,16 +363,16 @@ Estado apps/client/src/app/components/admin-jobs/admin-jobs.html - 152 + 161 apps/client/src/app/components/admin-settings/admin-settings.component.html - 92 + 104 and is driven by the efforts of its contributors - y es impulsado por los esfuerzos de sus contribuidores + y es impulsado por los esfuerzos de sus colaboradores apps/client/src/app/pages/about/overview/about-overview-page.html 49 @@ -376,10 +380,10 @@ Asset Profiles - Perfiles de activos. + Perfiles de activos apps/client/src/app/components/admin-settings/admin-settings.component.html - 106 + 123 libs/ui/src/lib/assistant/assistant.html @@ -391,40 +395,40 @@ Datos históricos del mercado apps/client/src/app/components/admin-jobs/admin-jobs.html - 54 + 63 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 448 + 451 View Data - Visualiza los datos + Ver datos apps/client/src/app/components/admin-jobs/admin-jobs.html - 208 + 217 View Stacktrace - Visualiza Stacktrace + Ver Stacktrace apps/client/src/app/components/admin-jobs/admin-jobs.html - 216 + 225 Delete Job - Elimina el trabajo + Eliminar trabajo apps/client/src/app/components/admin-jobs/admin-jobs.html - 224 + 233 Details for - Detalles para + Detalles de libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html 2 @@ -435,7 +439,7 @@ Fecha apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 161 + 157 libs/ui/src/lib/account-balances/account-balances.component.html @@ -468,7 +472,7 @@ First Activity - Primera actividad + Primera operación apps/client/src/app/components/admin-market-data/admin-market-data.html 147 @@ -488,7 +492,7 @@ Activity Count - Recuento de actividad + Número de operaciones apps/client/src/app/components/admin-overview/admin-overview.html 19 @@ -503,23 +507,23 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 44 + 40 Do you really want to delete this coupon? - ¿Estás seguro de eliminar este cupón? + ¿Seguro que quieres eliminar este cupón? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 193 + 196 Do you really want to flush the cache? - ¿Estás seguro de limpiar la caché? + ¿Seguro que quieres limpiar la caché? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 230 + 233 @@ -527,7 +531,7 @@ Por favor, establece tu mensaje del sistema: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 250 + 253 @@ -540,7 +544,7 @@ per User - por usario + por usuario apps/client/src/app/components/admin-overview/admin-overview.html 28 @@ -548,7 +552,7 @@ Gather Profile Data - Recoger los datos del perfil + Recopilar datos del perfil apps/client/src/app/components/admin-market-data/admin-market-data.html 234 @@ -612,7 +616,7 @@ Housekeeping - Tareas domésticas + Limpieza del sistema apps/client/src/app/components/admin-overview/admin-overview.html 184 @@ -628,7 +632,7 @@ Do you really want to delete this user? - ¿Estás seguro de eliminar este usuario? + ¿Seguro que quieres eliminar este usuario? apps/client/src/app/components/admin-users/admin-users.component.ts 215 @@ -652,7 +656,7 @@ No auto-renewal on membership. - No se renueva automáticamente la membresía. + Sin renovación automática de la membresía. apps/client/src/app/components/user-account-membership/user-account-membership.html 74 @@ -660,14 +664,14 @@ Engagement per Day - Contratación diaria + Interacción diaria apps/client/src/app/components/admin-users/admin-users.html 140 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 89 + 108 @@ -680,7 +684,7 @@ Current Market Mood - Estado de ánimo del mercado + Sentimiento del mercado apps/client/src/app/components/fear-and-greed-index/fear-and-greed-index.component.html 12 @@ -723,7 +727,7 @@ apps/client/src/app/pages/public/public-page.html - 242 + 241 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -739,7 +743,7 @@ apps/client/src/app/components/header/header.component.ts - 297 + 298 apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html @@ -756,26 +760,26 @@ Oops! Incorrect Security Token. - Vaya! Token de seguridad incorrecto. + ¡Vaya! Token de seguridad incorrecto. apps/client/src/app/components/header/header.component.ts - 312 + 313 apps/client/src/app/components/user-account-access/user-account-access.component.ts - 154 + 152 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 193 + 191 Manage Activities - Gestión de las operaciones + Gestionar operaciones apps/client/src/app/components/home-holdings/home-holdings.html - 67 + 64 @@ -891,7 +895,7 @@ Rendimiento bruto absoluto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 73 + 77 @@ -899,7 +903,7 @@ Rendimiento neto absoluto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 107 + 111 apps/client/src/app/pages/portfolio/analysis/analysis-page.html @@ -911,7 +915,7 @@ Rendimiento neto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 123 + 127 apps/client/src/app/pages/portfolio/analysis/analysis-page.html @@ -923,15 +927,15 @@ Total de activos apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 149 + 153 Buying Power - Capacidad de compra + Poder adquisitivo apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 241 + 248 @@ -939,7 +943,7 @@ Patrimonio neto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 317 + 324 @@ -947,12 +951,12 @@ Rendimiento anualizado apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 331 + 338 Please set the amount of your emergency fund. - Por favor, ingresa la cantidad de tu fondo de emergencia: + Por favor, ingresa la cantidad de tu fondo de emergencia. apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts 111 @@ -967,7 +971,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 396 + 399 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -975,7 +979,7 @@ apps/client/src/app/pages/public/public-page.html - 114 + 113 @@ -987,7 +991,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 407 + 410 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -999,7 +1003,7 @@ Etiquetas apps/client/src/app/components/admin-settings/admin-settings.component.html - 201 + 218 libs/ui/src/lib/tags-selector/tags-selector.component.html @@ -1012,10 +1016,10 @@ Report Data Glitch - Reporta un anomalía de los datos + Reportar anomalía en los datos apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 451 + 456 @@ -1043,7 +1047,7 @@ Mostrar todos libs/ui/src/lib/holdings-table/holdings-table.component.html - 216 + 212 @@ -1055,19 +1059,19 @@ libs/ui/src/lib/assistant/assistant.component.ts - 363 + 362 YTD - Desde principio de año + YTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 199 + 205 libs/ui/src/lib/assistant/assistant.component.ts - 375 + 374 @@ -1075,11 +1079,11 @@ 1 año apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 203 + 209 libs/ui/src/lib/assistant/assistant.component.ts - 385 + 384 @@ -1087,16 +1091,16 @@ 5 años apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 207 + 213 libs/ui/src/lib/assistant/assistant.component.ts - 409 + 408 Performance with currency effect - Rendimiento con el efecto del tipo de cambio de divisa + Rendimiento con el efecto de la divisa apps/client/src/app/pages/portfolio/analysis/analysis-page.html 135 @@ -1107,11 +1111,11 @@ Máximo apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 211 + 217 libs/ui/src/lib/assistant/assistant.component.ts - 415 + 414 @@ -1127,12 +1131,12 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 196 + 195 About - Sobre + Acerca de apps/client/src/app/components/footer/footer.component.html 20 @@ -1184,7 +1188,7 @@ Please enter your coupon code. - Por favor, ingresa tu código de cupón: + Por favor, ingresa tu código de cupón. apps/client/src/app/components/user-account-membership/user-account-membership.component.ts 210 @@ -1192,7 +1196,7 @@ Could not redeem coupon code - No se puede canjear este código de cupón + No se pudo canjear el código de cupón apps/client/src/app/components/user-account-membership/user-account-membership.component.ts 174 @@ -1200,7 +1204,7 @@ Coupon code has been redeemed - El codigo de cupón ha sido canjeado + El código del cupón ha sido canjeado apps/client/src/app/components/user-account-membership/user-account-membership.component.ts 187 @@ -1208,7 +1212,7 @@ Reload - Refrescar + Recargar apps/client/src/app/components/user-account-membership/user-account-membership.component.ts 188 @@ -1216,10 +1220,10 @@ Do you really want to remove this sign in method? - ¿Estás seguro de eliminar este método de acceso? + ¿Seguro que quieres eliminar este método de acceso? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 282 + 279 @@ -1244,7 +1248,7 @@ Try Premium - Prueba Premium + Probar Premium apps/client/src/app/components/user-account-membership/user-account-membership.html 53 @@ -1252,7 +1256,7 @@ Redeem Coupon - Canjea el cupón + Canjear cupón apps/client/src/app/components/user-account-membership/user-account-membership.html 67 @@ -1276,10 +1280,10 @@ Locale - Ubicación + Configuración regional apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 512 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -1316,7 +1320,7 @@ User ID - ID usuario + ID de usuario apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 51 @@ -1327,7 +1331,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 11 + 30 @@ -1375,11 +1379,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 375 + 381 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 66 + 85 apps/client/src/app/pages/accounts/accounts-page.html @@ -1396,7 +1400,7 @@ Update account - Editar cuenta + Actualizar cuenta apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html 8 @@ -1412,14 +1416,14 @@ Currency - Divisa base + Divisa apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 199 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 316 + 317 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -1431,7 +1435,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 145 + 141 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -1476,7 +1480,7 @@ Account ID - ID cuenta + ID de cuenta apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html 96 @@ -1611,12 +1615,12 @@ Como estás conectado, no puedes acceder a la cuenta de demostración. apps/client/src/app/pages/demo/demo-page.component.ts - 35 + 32 Frequently Asked Questions (FAQ) - Preguntas más frecuentes (FAQ) + Preguntas frecuentes (FAQ) apps/client/src/app/components/footer/footer.component.html 33 @@ -1657,6 +1661,10 @@ Overview Visión general + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 7 + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 114 @@ -1675,11 +1683,11 @@ apps/client/src/app/pages/admin/admin-page.component.ts - 48 + 45 apps/client/src/app/pages/resources/resources-page.component.ts - 30 + 29 libs/common/src/lib/routes/routes.ts @@ -1695,7 +1703,7 @@ Mercados apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 378 + 381 apps/client/src/app/components/footer/footer.component.html @@ -1719,7 +1727,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 40 + 39 libs/common/src/lib/routes/routes.ts @@ -1780,7 +1788,7 @@ By Holding - Por participación + Por posiciones apps/client/src/app/pages/portfolio/allocations/allocations-page.html 107 @@ -1819,7 +1827,7 @@ apps/client/src/app/pages/public/public-page.html - 151 + 150 @@ -1844,7 +1852,7 @@ Top - Lo mejor + Mejores apps/client/src/app/pages/portfolio/analysis/analysis-page.html 305 @@ -1852,7 +1860,7 @@ Bottom - Lo peor + Peores apps/client/src/app/pages/portfolio/analysis/analysis-page.html 354 @@ -1876,7 +1884,7 @@ Holdings - Participaciones + Posiciones apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html 102 @@ -1904,7 +1912,7 @@ Update activity - Actualizar opereación + Actualizar operación apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html 10 @@ -1915,7 +1923,7 @@ Semana actual apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 191 + 197 @@ -1959,7 +1967,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 124 + 120 @@ -1971,7 +1979,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 189 + 185 libs/ui/src/lib/activities-table/activities-table.component.html @@ -1987,7 +1995,7 @@ Precio unitario apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 214 + 210 libs/ui/src/lib/activities-table/activities-table.component.html @@ -1999,7 +2007,7 @@ Nota apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 432 + 435 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -2007,19 +2015,19 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 275 + 271 Activities - Operación + Operaciones apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html 86 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 115 + 113 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -2039,11 +2047,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 342 + 348 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 75 + 94 apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -2063,7 +2071,7 @@ Importando datos... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 175 + 174 @@ -2071,12 +2079,12 @@ La importación se ha completado apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 185 + 184 or start a discussion at - o iniciar una discusión en + o inicia una discusión en apps/client/src/app/pages/about/overview/about-overview-page.html 94 @@ -2143,12 +2151,12 @@ Continentes apps/client/src/app/pages/public/public-page.html - 132 + 131 Sustainable retirement income - Ingreso sostenible de retiro + Ingresos sostenibles para la jubilación apps/client/src/app/pages/portfolio/fire/fire-page.html 41 @@ -2156,10 +2164,10 @@ Ghostfolio empowers you to keep track of your wealth. - Ghostfolio te permite hacer un seguimiento de tu riqueza. + Ghostfolio te permite hacer un seguimiento de tu patrimonio. apps/client/src/app/pages/public/public-page.html - 238 + 237 @@ -2189,6 +2197,10 @@ apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html 88 + + libs/ui/src/lib/value/value.component.html + 18 + Resources @@ -2304,10 +2316,10 @@ Do you really want to delete this activity? - ¿Estás seguro de eliminar esta operación? + ¿Seguro que quieres eliminar esta operación? libs/ui/src/lib/activities-table/activities-table.component.ts - 288 + 292 @@ -2320,7 +2332,7 @@ contact us - contactarnos + contáctanos apps/client/src/app/pages/pricing/pricing-page.html 336 @@ -2336,7 +2348,7 @@ Annual Interest Rate - Tipo de interés anual + Tasa de interés anual libs/ui/src/lib/fire-calculator/fire-calculator.component.html 21 @@ -2368,14 +2380,14 @@ Oops! Something went wrong. - Vaya! Algo no funcionó bien. + ¡Vaya! Algo no funcionó bien. apps/client/src/app/core/http-response.interceptor.ts 86 apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 193 + 192 @@ -2391,7 +2403,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 195 + 194 @@ -2415,15 +2427,15 @@ apps/client/src/app/pages/public/public-page.html - 168 + 167 Latest activities - Últimas actividades + Últimas operaciones apps/client/src/app/pages/public/public-page.html - 211 + 210 @@ -2443,7 +2455,7 @@ apps/client/src/app/pages/public/public-page.html - 186 + 185 @@ -2455,7 +2467,7 @@ apps/client/src/app/pages/public/public-page.html - 177 + 176 @@ -2487,7 +2499,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 53 + 72 @@ -2511,7 +2523,7 @@ Ahorros libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 397 + 424 @@ -2523,11 +2535,11 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 352 + 359 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 387 + 414 libs/ui/src/lib/i18n.ts @@ -2547,7 +2559,7 @@ Depósito libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 377 + 404 @@ -2555,7 +2567,7 @@ Mensual apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 91 + 90 @@ -2579,11 +2591,11 @@ Miedo apps/client/src/app/components/home-market/home-market.component.ts - 42 + 41 apps/client/src/app/components/markets/markets.component.ts - 47 + 46 libs/ui/src/lib/i18n.ts @@ -2595,11 +2607,11 @@ Codicia apps/client/src/app/components/home-market/home-market.component.ts - 43 + 42 apps/client/src/app/components/markets/markets.component.ts - 48 + 47 libs/ui/src/lib/i18n.ts @@ -2611,12 +2623,12 @@ Filtrar por... apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 385 + 383 Hello, has shared a Portfolio with you! - Hola, ha compartido una Cartera contigo! + ¡Hola, ha compartido una cartera contigo! apps/client/src/app/pages/public/public-page.html 5 @@ -2644,10 +2656,10 @@ Benchmark - Benchmark + Índice de referencia apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 376 + 379 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -2659,11 +2671,11 @@ No se pudo validar el formulario apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 554 + 570 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 557 + 573 @@ -2687,7 +2699,7 @@ Excluido del análisis apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 267 + 274 @@ -2695,7 +2707,7 @@ Automático apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 70 + 69 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -2731,12 +2743,12 @@ Importe total apps/client/src/app/components/investment-chart/investment-chart.component.ts - 143 + 146 Portfolio Evolution - Evolución cartera + Evolución de la cartera apps/client/src/app/pages/portfolio/analysis/analysis-page.html 407 @@ -2783,7 +2795,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 326 + 327 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -2791,7 +2803,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 290 + 286 libs/ui/src/lib/i18n.ts @@ -2807,7 +2819,7 @@ Símbolo apps/client/src/app/components/admin-jobs/admin-jobs.html - 68 + 77 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -2823,7 +2835,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 315 + 318 libs/ui/src/lib/i18n.ts @@ -2847,7 +2859,7 @@ Efectivo apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 212 + 219 libs/ui/src/lib/i18n.ts @@ -2856,7 +2868,7 @@ Commodity - Bien + Materia prima libs/ui/src/lib/i18n.ts 47 @@ -2864,7 +2876,7 @@ Equity - Capital + Renta variable apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html 57 @@ -2895,7 +2907,7 @@ Autenticación apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 35 + 54 @@ -2959,7 +2971,7 @@ Fondo de emergencia apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 164 + 168 apps/client/src/app/pages/features/features-page.html @@ -2979,7 +2991,7 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 437 + 451 @@ -2991,7 +3003,7 @@ apps/client/src/app/pages/public/public-page.html - 196 + 195 libs/ui/src/lib/benchmark/benchmark.component.html @@ -2999,11 +3011,11 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 439 + 453 libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 452 + 467 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -3044,7 +3056,7 @@ If you retire today, you would be able to withdraw - Si te retirases hoy, podrías sacar + Si te jubilas hoy, podrías retirar apps/client/src/app/pages/portfolio/fire/fire-page.html 68 @@ -3068,7 +3080,7 @@ The following file formats are supported: - Los siguientes formatos de archivo están soportados: + Los siguientes formatos de archivo son compatibles: apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.html 90 @@ -3088,7 +3100,7 @@ Activities Count - Recuento de actividades + Número de operaciones apps/client/src/app/components/admin-market-data/admin-market-data.html 156 @@ -3096,7 +3108,7 @@ Refresh - Refrescar + Actualizar apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 21 @@ -3107,12 +3119,12 @@ Mapeo de símbolos apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 384 + 387 Looking for a student discount? - ¿Buscando un descuento para estudiantes? + ¿Buscas un descuento para estudiantes? apps/client/src/app/pages/pricing/pricing-page.html 342 @@ -3131,7 +3143,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 365 + 372 apps/client/src/app/pages/features/features-page.html @@ -3139,11 +3151,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 202 + 198 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 76 + 75 libs/ui/src/lib/i18n.ts @@ -3171,7 +3183,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 342 + 343 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -3179,7 +3191,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 309 + 305 libs/ui/src/lib/i18n.ts @@ -3199,7 +3211,7 @@ Validando datos... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 299 + 293 @@ -3215,7 +3227,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 71 + 67 @@ -3223,7 +3235,7 @@ Datos del mercado apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 398 + 403 libs/common/src/lib/routes/routes.ts @@ -3252,7 +3264,7 @@ Holding - Participación + Posición apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.html 32 @@ -3275,15 +3287,15 @@ Anual apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 92 + 91 Import Dividends - Importar Dividendos + Importar dividendos apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 137 + 136 libs/ui/src/lib/activities-table/activities-table.component.html @@ -3299,7 +3311,7 @@ Válido hasta apps/client/src/app/components/admin-settings/admin-settings.component.html - 74 + 86 libs/ui/src/lib/membership-card/membership-card.component.html @@ -3324,7 +3336,7 @@ Higher Risk - Riesgo mayor + Mayor riesgo libs/ui/src/lib/i18n.ts 20 @@ -3338,6 +3350,14 @@ 22 + + No Activities + Sin operaciones + + apps/client/src/app/components/admin-market-data/admin-market-data.component.ts + 145 + + Retirement Provision Provisión de jubilación @@ -3348,7 +3368,7 @@ Everything in Basic, plus - Todo en Básico, más + Todo lo incluido en Basic, más apps/client/src/app/pages/pricing/pricing-page.html 199 @@ -3364,7 +3384,7 @@ Protection for sensitive information like absolute performances and quantity values - Protección de información confidencial como rendimientos absolutos y valores cuantitativos + Protección de información confidencial como rendimientos absolutos y cantidades apps/client/src/app/components/user-account-settings/user-account-settings.html 194 @@ -3388,7 +3408,7 @@ Are you an ambitious investor who needs the full picture? - ¿Es usted un inversor ambicioso que necesita una visión completa? + ¿Eres un inversor ambicioso que necesita una visión completa? apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 15 @@ -3412,7 +3432,7 @@ Performance Benchmarks - Puntos de referencia de rendimiento + Índices de referencia de rendimiento apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 32 @@ -3444,7 +3464,7 @@ and more Features... - y más características... + y más funcionalidades... apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 44 @@ -3460,7 +3480,7 @@ Skip - Saltar + Omitir apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 59 @@ -3516,7 +3536,7 @@ Unlimited Transactions - Transacciones ilimitadas + Operaciones ilimitadas apps/client/src/app/pages/pricing/pricing-page.html 35 @@ -3540,7 +3560,7 @@ Portfolio Performance - Rendimiento del Portfolio + Rendimiento de la cartera apps/client/src/app/pages/pricing/pricing-page.html 43 @@ -3552,7 +3572,7 @@ Self-hosted, update manually. - Auto alojado, actualiza manualmente. + Autoalojado, actualiza manualmente. apps/client/src/app/pages/pricing/pricing-page.html 84 @@ -3572,7 +3592,7 @@ For new investors who are just getting started with trading. - Para nuevos inversores que estan empezando con el trading. + Para nuevos inversores que están empezando con el trading. apps/client/src/app/pages/pricing/pricing-page.html 119 @@ -3580,7 +3600,7 @@ Fully managed Ghostfolio cloud offering. - Oferta en la nube de Ghostfolio totalmente administrada. + Oferta de Ghostfolio en la nube totalmente gestionada. apps/client/src/app/pages/pricing/pricing-page.html 150 @@ -3592,7 +3612,7 @@ For ambitious investors who need the full picture of their financial assets. - Para inversores ambiciosos que necesitan una visión completa de sus activos financieros + Para inversores ambiciosos que necesitan una visión completa de sus activos financieros. apps/client/src/app/pages/pricing/pricing-page.html 193 @@ -3611,11 +3631,11 @@ No se pudo guardar el perfil del activo apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 588 + 604 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 591 + 607 @@ -3635,12 +3655,12 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 88 + 92 Portfolio Allocations - Distribucion del Portfolio + Distribución de la cartera apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 28 @@ -3668,7 +3688,7 @@ Data Import and Export - Importacion y exportacion de datos + Importación y exportación de datos apps/client/src/app/pages/pricing/pricing-page.html 63 @@ -3680,7 +3700,7 @@ Switch to Ghostfolio Premium easily - Cambia a Ghostfolio Premium facilmente + Cambia a Ghostfolio Premium fácilmente libs/ui/src/lib/i18n.ts 13 @@ -3696,7 +3716,7 @@ Email and Chat Support - Soporte a Traves de Email y Chat + Soporte a través de correo electrónico y chat apps/client/src/app/pages/pricing/pricing-page.html 248 @@ -3704,7 +3724,7 @@ Switch to Ghostfolio Premium or Ghostfolio Open Source easily - Cambie a Ghostfolio Premium o Ghostfolio Open Source fácilmente + Cambia a Ghostfolio Premium o Ghostfolio Open Source fácilmente libs/ui/src/lib/i18n.ts 12 @@ -3712,7 +3732,7 @@ Switch to Ghostfolio Open Source or Ghostfolio Basic easily - Cambie a Ghostfolio Open Source o Ghostfolio Basic fácilmente + Cambia a Ghostfolio Open Source o Ghostfolio Basic fácilmente libs/ui/src/lib/i18n.ts 14 @@ -3736,7 +3756,7 @@ Professional Data Provider - Proveedor de datos profesional + Proveedor de datos profesional apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 40 @@ -3796,10 +3816,10 @@ Do you really want to delete these activities? - ¿Realmente deseas eliminar estas actividades? + ¿Seguro que quieres eliminar estas operaciones? libs/ui/src/lib/activities-table/activities-table.component.ts - 278 + 282 @@ -3810,6 +3830,14 @@ 306 + + Explore + Explorar + + apps/client/src/app/pages/resources/overview/resources-overview.component.html + 11 + + By Por @@ -3831,12 +3859,12 @@ Año actual apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 199 + 205 Add platform - Agregar plataforma + Añadir plataforma apps/client/src/app/components/admin-platform/create-or-update-platform-dialog/create-or-update-platform-dialog.html 10 @@ -3844,14 +3872,14 @@ Url - ¿La URL? + Url apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 419 + 422 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 550 + 553 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -3864,18 +3892,18 @@ Asset profile has been saved - El perfil del activo ha sido guardado + Perfil del activo guardado apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 578 + 594 Do you really want to delete this platform? - ¿Realmente deseas eliminar esta plataforma? + ¿Seguro que quieres eliminar esta plataforma? apps/client/src/app/components/admin-platform/admin-platform.component.ts - 106 + 111 @@ -3883,7 +3911,7 @@ Plataformas apps/client/src/app/components/admin-settings/admin-settings.component.html - 195 + 212 @@ -3891,7 +3919,7 @@ Actualizar saldo en efectivo apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 112 + 108 @@ -3904,7 +3932,7 @@ Upgrade to Ghostfolio Premium today and gain access to exclusive features to enhance your investment experience: - Actualiza a Ghostfolio Premium hoy y accede a características exclusivas para mejorar tu experiencia de inversión: + Actualiza a Ghostfolio Premium hoy y accede a funcionalidades exclusivas para mejorar tu experiencia de inversión: apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 18 @@ -3920,7 +3948,7 @@ Add Platform - Agregar plataforma + Añadir plataforma apps/client/src/app/components/admin-platform/admin-platform.component.html 9 @@ -3928,7 +3956,7 @@ Settings - Configuraciones + Ajustes apps/client/src/app/components/user-account-settings/user-account-settings.html 2 @@ -3944,7 +3972,7 @@ This activity already exists. - Esta actividad ya existe. + Esta operación ya existe. libs/ui/src/lib/i18n.ts 21 @@ -3952,7 +3980,7 @@ Manage Benchmarks - Gestionar puntos de referencia + Gestionar índices de referencia apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html 35 @@ -3984,7 +4012,7 @@ Select Activities - Seleccionar dividendos + Seleccionar operaciones apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.html 115 @@ -4071,7 +4099,7 @@ Pasivos apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 295 + 302 apps/client/src/app/pages/features/features-page.html @@ -4144,7 +4172,7 @@ Multi-Accounts - Cuentas múltiples + Múltiples cuentas apps/client/src/app/pages/features/features-page.html 127 @@ -4152,7 +4180,7 @@ Portfolio Calculations - Cálculos de portafolio + Cálculos de la cartera apps/client/src/app/pages/features/features-page.html 141 @@ -4168,7 +4196,7 @@ Market Mood - Modo de mercado + Sentimiento del mercado apps/client/src/app/pages/features/features-page.html 215 @@ -4184,7 +4212,7 @@ Multi-Language - Multilenguaje + Multilingüe apps/client/src/app/pages/features/features-page.html 259 @@ -4208,7 +4236,7 @@ Liability - Responsabilidad + Pasivo libs/ui/src/lib/i18n.ts 41 @@ -4216,7 +4244,7 @@ and we share aggregated key metrics of the platform’s performance - y compartimos agregados métricas clave del rendimiento de la plataforma + y compartimos métricas clave agregadas del rendimiento de la plataforma apps/client/src/app/pages/about/overview/about-overview-page.html 32 @@ -4227,12 +4255,12 @@ Configuración del scraper apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 471 + 474 Add Asset Profile - Agregar perfil de activo + Añadir perfil de activo apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html 7 @@ -4252,7 +4280,7 @@ Discover Open Source Alternatives for Personal Finance Tools - Descubra alternativas de software libre para herramientas de finanzas personales + Descubre alternativas de software de código abierto para herramientas de finanzas personales apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.html 5 @@ -4404,7 +4432,7 @@ Effortlessly track, analyze, and visualize your wealth with Ghostfolio. - Siga, analice y visualice su patrimonio sin esfuerzo con Ghostfolio. + Sigue, analiza y visualiza tu patrimonio sin esfuerzo con Ghostfolio. apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 329 @@ -4448,7 +4476,7 @@ Buy - Comprar + Compra apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html 31 @@ -4460,7 +4488,7 @@ Valuable - Valioso + Activo de valor libs/ui/src/lib/i18n.ts 43 @@ -4471,7 +4499,7 @@ ETFs sin países apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 136 + 135 @@ -4479,7 +4507,7 @@ ETFs sin sectores apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 141 + 140 @@ -4487,7 +4515,7 @@ Activos apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 233 @@ -4532,7 +4560,7 @@ The source code is fully available as open source software (OSS) under the AGPL-3.0 license - El código fuente está disponible completamente en software de código abierto (OSS) bajo la licencia AGPL-3.0 + El código fuente está disponible como software de código abierto (OSS) bajo la licencia AGPL-3.0 apps/client/src/app/pages/about/overview/about-overview-page.html 16 @@ -4556,7 +4584,7 @@ Capture your activities - Captura tus actividades + Captura tus operaciones apps/client/src/app/components/home-overview/home-overview.html 28 @@ -4564,7 +4592,7 @@ Record your investment activities to keep your portfolio up to date. - Registra tus actividades de inversión para mantener tu portafolio actualizado. + Registra tus operaciones de inversión para mantener tu cartera actualizada. apps/client/src/app/components/home-overview/home-overview.html 30 @@ -4572,7 +4600,7 @@ Monitor and analyze your portfolio - Monitorea y analiza tu portafolio + Monitorea y analiza tu cartera apps/client/src/app/components/home-overview/home-overview.html 37 @@ -4588,7 +4616,7 @@ Ready to take control of your personal finances? - ¿Listo para tomar el control de tus finanzas personales? + ¿Estás preparado para tomar el control de tus finanzas personales? apps/client/src/app/components/home-overview/home-overview.html 12 @@ -4604,7 +4632,7 @@ this is projected to increase to - esto se proyecta a aumentar a + se proyecta que esto aumente a apps/client/src/app/pages/portfolio/fire/fire-page.html 147 @@ -4620,7 +4648,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. - En Ghostfolio, la transparencia está en el centro de nuestros valores. Publicamos el código fuente como software de código abierto (OSS) bajo la licencia Licencia AGPL-3.0 y compartimos abiertamente métricas clave agregadas sobre el estado operativo de la plataforma. + En Ghostfolio, la transparencia está en el centro de nuestros valores. Publicamos el código fuente como software de código abierto (OSS) bajo la Licencia AGPL-3.0 y compartimos abiertamente métricas clave agregadas sobre el estado operativo de la plataforma. apps/client/src/app/pages/open/open-page.html 7 @@ -4656,10 +4684,10 @@ Job ID - ID de trabajo + ID del trabajo apps/client/src/app/components/admin-jobs/admin-jobs.html - 34 + 43 @@ -4712,14 +4740,14 @@ Currencies - Monedas + Divisas apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 131 + 130 apps/client/src/app/pages/public/public-page.html - 96 + 95 @@ -4756,7 +4784,7 @@ Check out the numerous features of Ghostfolio to manage your wealth - Descubra las numerosas funciones de Ghostfolio para gestionar su patrimonio + Descubre las numerosas funciones de Ghostfolio para gestionar tu patrimonio apps/client/src/app/pages/features/features-page.html 7 @@ -4767,11 +4795,11 @@ No se pudo analizar la configuración del scraper apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 509 + 525 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 512 + 528 @@ -4832,7 +4860,7 @@ Protect your assets. Refine your personal investment strategy. - Protege tus assets. Mejora tu estrategia de inversión personal. + Protege tus activos. Mejora tu estrategia de inversión personal. apps/client/src/app/pages/landing/landing-page.html 124 @@ -4880,7 +4908,7 @@ Get access to 80’000+ tickers from over 50 exchanges - Obtén acceso a más de 80,000 tickers de más de 50 exchanges + Accede a más de 80.000 tickers de más de 50 bolsas apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 84 @@ -4912,7 +4940,7 @@ pursuing a buy & hold strategy - persiguiendo una compra & mantener estrategia + siguiendo una estrategia de comprar y mantener apps/client/src/app/pages/landing/landing-page.html 184 @@ -4920,7 +4948,7 @@ interested in getting insights of your portfolio composition - interesado en obtener información sobre la composición de tu portafolio + interesado en obtener información sobre la composición de tu cartera apps/client/src/app/pages/landing/landing-page.html 189 @@ -4936,7 +4964,7 @@ into minimalism - en el minimalismo + interesado en el minimalismo apps/client/src/app/pages/landing/landing-page.html 197 @@ -4944,7 +4972,7 @@ caring about diversifying your financial resources - preocuparse por diversificar tus recursos financieros + preocupado por diversificar tus recursos financieros apps/client/src/app/pages/landing/landing-page.html 201 @@ -5000,7 +5028,7 @@ How does Ghostfolio work? - ¿Cómo Ghostfolio work? + ¿Cómo funciona Ghostfolio? apps/client/src/app/pages/landing/landing-page.html 282 @@ -5016,7 +5044,7 @@ * no e-mail address nor credit card required - * no se requiere dirección de correo electrónico ni tarjeta de crédito + * no se necesita correo electrónico ni tarjeta de crédito apps/client/src/app/pages/landing/landing-page.html 292 @@ -5032,7 +5060,7 @@ Get valuable insights of your portfolio composition - Obtén información valiosa sobre la composición de tu portafolio + Obtén información valiosa sobre la composición de tu cartera apps/client/src/app/pages/landing/landing-page.html 316 @@ -5040,7 +5068,7 @@ Are you ready? - ¿Estás listo? + ¿Estás preparado? apps/client/src/app/pages/landing/landing-page.html 330 @@ -5064,7 +5092,7 @@ less than - menos que + menos de apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 129 @@ -5253,7 +5281,7 @@ Open Source Alternative to - Alternativa de software libre a + Alternativa de software de código abierto a apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.html 42 @@ -5261,7 +5289,7 @@ The Open Source Alternative to - La alternativa de software libre a + La alternativa de software de código abierto a apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 8 @@ -5269,7 +5297,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. - ¿Estás buscando una alternativa de código abierto a ? Ghostfolio es una potente herramienta de gestión de carteras que ofrece a los usuarios una plataforma integral para rastrear, analizar y optimizar sus inversiones. Ya seas un inversor con experiencia o estés comenzando, Ghostfolio ofrece una interfaz intuitiva y una amplia gama de funcionalidades para ayudarte a tomar decisiones informadas y tener el control de tu futuro financiero. + ¿Estás buscando una alternativa de código abierto a ? Ghostfolio es una potente herramienta de gestión de carteras que proporciona a los usuarios una plataforma completa para seguir, analizar y optimizar sus inversiones. Ya seas un inversor con experiencia o estés comenzando, Ghostfolio ofrece una interfaz intuitiva y una amplia gama de funcionalidades para ayudarte a tomar decisiones informadas y tener el control de tu futuro financiero. apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 19 @@ -5293,7 +5321,7 @@ open-source-alternative-to - alternativa-de-software-libre-a + alternativa-de-software-de-codigo-abierto-a kebab-case libs/common/src/lib/routes/routes.ts @@ -5314,7 +5342,7 @@ Ready to take your investments to the next level? - ¿Listo para llevar sus inversiones al siguiente nivel? + ¿Estás preparado para llevar tus inversiones al siguiente nivel? apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 325 @@ -5362,7 +5390,7 @@ with your university e-mail address - con tu dirección de correo electrónico de la universidad + con tu dirección de correo electrónico universitaria apps/client/src/app/pages/pricing/pricing-page.html 348 @@ -5414,7 +5442,7 @@ One-time fee, annual account fees - Tarifa única, tarifas anuales de la cuenta + Comisión única, comisiones anuales de la cuenta apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html 33 @@ -5430,10 +5458,10 @@ Fee - Tarifa + Comisión apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 262 + 258 libs/ui/src/lib/activities-table/activities-table.component.html @@ -5454,7 +5482,7 @@ Add Tag - Agregar etiqueta + Añadir etiqueta apps/client/src/app/components/admin-tag/admin-tag.component.html 9 @@ -5462,10 +5490,10 @@ Do you really want to delete this tag? - ¿Realmente deseas eliminar esta etiqueta? + ¿Seguro que quieres eliminar esta etiqueta? apps/client/src/app/components/admin-tag/admin-tag.component.ts - 103 + 108 @@ -5533,7 +5561,7 @@ Membresía apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 48 + 67 libs/common/src/lib/routes/routes.ts @@ -5546,7 +5574,7 @@ Request it - Solicitar + Solicítalo apps/client/src/app/pages/pricing/pricing-page.html 344 @@ -5565,12 +5593,12 @@ Perfil de activo apps/client/src/app/components/admin-jobs/admin-jobs.html - 52 + 61 Do you really want to delete this asset profile? - ¿Realmente deseas eliminar este perfil de activo? + ¿Seguro que quieres eliminar este perfil de activo? apps/client/src/app/components/admin-market-data/admin-market-data.service.ts 37 @@ -5594,7 +5622,7 @@ Ghostfolio is a personal finance dashboard to keep track of your net worth including cash, stocks, ETFs and cryptocurrencies across multiple platforms. - Ghostfolio es un dashboard de finanzas personales para hacer un seguimiento de tus activos como acciones, ETFs o criptodivisas a través de múltiples plataformas. + Ghostfolio es un panel de control de finanzas personales para hacer un seguimiento de tu patrimonio neto, incluyendo efectivo, acciones, ETFs y criptomonedas a través de múltiples plataformas. apps/client/src/app/pages/i18n/i18n-page.html 5 @@ -5630,7 +5658,7 @@ Ghostfolio vs comparison table - Ghostfolio vs tabla comparativa + Tabla comparativa de Ghostfolio vs apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 55 @@ -5646,7 +5674,7 @@ app, asset, cryptocurrency, dashboard, etf, finance, management, performance, portfolio, software, stock, trading, wealth, web3 - aplicación, activo, criptomoneda, panel, ETF, finanzas, gestión, rendimiento, cartera, software, acciones, comercio, riqueza, web3 + aplicación, activo, criptomoneda, panel, ETF, finanzas, gestión, rendimiento, cartera, software, acciones, comercio, patrimonio, web3 apps/client/src/app/pages/i18n/i18n-page.html 10 @@ -5654,7 +5682,7 @@ Oops, cash balance transfer has failed. - Oops, el saldo de efectivo no se ha transferido. + ¡Vaya! La transferencia del saldo de efectivo ha fallado. apps/client/src/app/pages/accounts/accounts-page.component.ts 341 @@ -5670,7 +5698,7 @@ Extreme Greed - Avaricia extrema + Codicia extrema libs/ui/src/lib/i18n.ts 107 @@ -5686,18 +5714,18 @@ Oops! Could not parse historical data. - ¡Ups! No se pudieron analizar los datos históricos. + ¡Vaya! No se pudieron analizar los datos históricos. libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.ts - 262 + 284 Do you really want to delete this system message? - ¿Realmente deseas eliminar este mensaje del sistema? + ¿Seguro que quieres eliminar este mensaje del sistema? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 206 + 209 @@ -5721,7 +5749,7 @@ Saldos de efectivo apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 148 + 146 @@ -5738,15 +5766,15 @@ Do you really want to delete this account balance? - ¿Realmente desea eliminar el saldo de esta cuenta? + ¿Seguro que quieres eliminar el saldo de esta cuenta? libs/ui/src/lib/account-balances/account-balances.component.ts - 120 + 113 If a translation is missing, kindly support us in extending it here. - Si falta una traducción, por favor ayúdenos a ampliarla. here. + Si falta una traducción, por favor ayúdanos a completarla aquí. apps/client/src/app/components/user-account-settings/user-account-settings.html 59 @@ -5757,7 +5785,7 @@ El precio actual de mercado es apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 706 + 722 @@ -5765,7 +5793,7 @@ Prueba apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 568 + 571 @@ -5802,7 +5830,7 @@ Oops! Could not grant access. - ¡Ups! No se pudo otorgar acceso. + ¡Vaya! No se pudo otorgar acceso. apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts 141 @@ -5834,7 +5862,7 @@ Market data is delayed for - Los datos del mercado se retrasan por + Los datos del mercado tienen un retraso de apps/client/src/app/components/portfolio-performance/portfolio-performance.component.ts 95 @@ -5853,11 +5881,11 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 81 + 80 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 97 + 96 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -5877,7 +5905,7 @@ Cerrar posición apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 442 + 447 @@ -5890,7 +5918,7 @@ Asset Performance - Rendimiento de activos + Rendimiento de los activos apps/client/src/app/pages/portfolio/analysis/analysis-page.html 190 @@ -5898,7 +5926,7 @@ Absolute Currency Performance - Rendimiento absoluto de divisas + Rendimiento absoluto de las divisas apps/client/src/app/pages/portfolio/analysis/analysis-page.html 211 @@ -5906,7 +5934,7 @@ Currency Performance - Rendimiento de la moneda + Rendimiento de la divisa apps/client/src/app/pages/portfolio/analysis/analysis-page.html 236 @@ -5917,7 +5945,7 @@ Semana hasta la fecha libs/ui/src/lib/assistant/assistant.component.ts - 367 + 366 @@ -5925,11 +5953,11 @@ WTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 191 + 197 libs/ui/src/lib/assistant/assistant.component.ts - 367 + 366 @@ -5937,7 +5965,7 @@ Mes hasta la fecha libs/ui/src/lib/assistant/assistant.component.ts - 371 + 370 @@ -5945,19 +5973,19 @@ MTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 195 + 201 libs/ui/src/lib/assistant/assistant.component.ts - 371 + 370 Year to date - El año hasta la fecha + Año hasta la fecha libs/ui/src/lib/assistant/assistant.component.ts - 375 + 374 @@ -5974,7 +6002,7 @@ Oops! A data provider is experiencing the hiccups. - ¡Ups! Un proveedor de datos está experimentando problemas. + ¡Vaya! Un proveedor de datos está experimentando problemas. apps/client/src/app/components/portfolio-performance/portfolio-performance.component.html 8 @@ -5993,7 +6021,7 @@ año apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 203 + 209 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -6005,7 +6033,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 385 + 384 @@ -6013,11 +6041,11 @@ años apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 207 + 213 libs/ui/src/lib/assistant/assistant.component.ts - 409 + 408 @@ -6033,7 +6061,7 @@ Recopilación de datos apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 587 + 594 apps/client/src/app/components/admin-overview/admin-overview.html @@ -6045,7 +6073,7 @@ General apps/client/src/app/pages/faq/faq-page.component.ts - 49 + 41 @@ -6053,7 +6081,7 @@ Nube apps/client/src/app/pages/faq/faq-page.component.ts - 54 + 46 libs/common/src/lib/routes/routes.ts @@ -6065,7 +6093,7 @@ Autoalojamiento apps/client/src/app/pages/faq/faq-page.component.ts - 60 + 52 libs/common/src/lib/routes/routes.ts @@ -6074,7 +6102,7 @@ self-hosting - auto-alojado + autoalojado kebab-case libs/common/src/lib/routes/routes.ts @@ -6106,7 +6134,7 @@ Activo apps/client/src/app/components/home-holdings/home-holdings.component.ts - 64 + 63 @@ -6114,7 +6142,7 @@ Cerrado apps/client/src/app/components/home-holdings/home-holdings.component.ts - 65 + 64 @@ -6127,7 +6155,7 @@ Activity - Actividad + Operación apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html 229 @@ -6143,10 +6171,10 @@ Execute Job - Ejecutar Tarea + Ejecutar trabajo apps/client/src/app/components/admin-jobs/admin-jobs.html - 220 + 229 @@ -6154,7 +6182,7 @@ Prioridad apps/client/src/app/components/admin-jobs/admin-jobs.html - 96 + 105 @@ -6175,7 +6203,7 @@ {VAR_PLURAL, plural, =1 {activity} other {activities}} - {VAR_PLURAL, plural, =1 {actividad} other {actividades}} + {VAR_PLURAL, plural, =1 {operación} other {operaciones}} apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html 14 @@ -6191,7 +6219,7 @@ Delete Activities - Eliminar actividades + Eliminar operaciones libs/ui/src/lib/activities-table/activities-table.component.html 69 @@ -6207,10 +6235,10 @@ Do you really want to close your Ghostfolio account? - ¿Estás seguro de querer borrar tu cuenta de Ghostfolio? + ¿Seguro que quieres eliminar tu cuenta de Ghostfolio? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 208 + 205 @@ -6239,7 +6267,7 @@ Approximation based on the top holdings of each ETF - Aproximación basada en las principales participaciones de cada ETF + Aproximación basada en las principales posiciones de cada ETF apps/client/src/app/pages/portfolio/allocations/allocations-page.html 340 @@ -6258,15 +6286,15 @@ Incluir en apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 374 + 377 Oops! There was an error setting up biometric authentication. - ¡Ups! Hubo un error al configurar la autenticación biométrica. + ¡Vaya! Hubo un error al configurar la autenticación biométrica. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 336 + 333 @@ -6279,15 +6307,15 @@ Benchmarks - Puntos de referencia + Índices de referencia apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 126 + 125 Delete Profiles - Borrar Perfiles + Eliminar Perfiles apps/client/src/app/components/admin-market-data/admin-market-data.html 242 @@ -6295,7 +6323,7 @@ Do you really want to delete these profiles? - Estas seguro de borrar estos perfiles? + ¿Seguro que quieres eliminar estos perfiles? apps/client/src/app/components/admin-market-data/admin-market-data.service.ts 68 @@ -6303,7 +6331,7 @@ Oops! Could not delete profiles. - ¡Ups! No se pudieron eliminar los perfiles. + ¡Vaya! No se pudieron eliminar los perfiles. apps/client/src/app/components/admin-market-data/admin-market-data.service.ts 56 @@ -6319,7 +6347,7 @@ Chart - Grafico + Gráfico apps/client/src/app/components/home-holdings/home-holdings.html 19 @@ -6330,7 +6358,7 @@ ¿Te gustaría refinar tu estrategia de inversión personal? apps/client/src/app/pages/public/public-page.html - 234 + 233 @@ -6351,7 +6379,7 @@ Budgeting - Presupuestación + Presupuestos apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 85 @@ -6491,7 +6519,7 @@ Wealth - Riqueza + Patrimonio apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts 99 @@ -6539,7 +6567,7 @@ View Holding - Ver fondos + Ver posición libs/ui/src/lib/activities-table/activities-table.component.html 450 @@ -6662,7 +6690,7 @@ Error apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 697 + 713 @@ -6683,7 +6711,7 @@ Oops! Could not update access. - Oops! No se pudo actualizar el acceso. + ¡Vaya! No se pudo actualizar el acceso. apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts 178 @@ -6714,7 +6742,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 592 + 599 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6746,7 +6774,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 345 + 341 apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html @@ -6754,7 +6782,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 46 + 47 libs/ui/src/lib/i18n.ts @@ -6766,7 +6794,7 @@ Cerrar apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 594 + 601 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6792,13 +6820,17 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 68 + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 127 + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html 107 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 347 + 343 libs/ui/src/lib/i18n.ts @@ -6810,7 +6842,7 @@ Rol apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 14 + 33 @@ -6834,12 +6866,12 @@ Instantánea de la cartera apps/client/src/app/components/admin-jobs/admin-jobs.html - 56 + 65 Change with currency effect Change - Cambiar con efecto de cambio dedivisa Cambiar + Cambio con el efecto de la divisa Cambio apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html 63 @@ -6855,7 +6887,7 @@ Performance with currency effect Performance - Rendimiento con cambio de divisa Rendimiento + Rendimiento con el efecto de la divisa Rendimiento apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html 83 @@ -6879,7 +6911,7 @@ send an e-mail to - enviar un correo electrónico a + envía un correo electrónico a apps/client/src/app/pages/about/overview/about-overview-page.html 87 @@ -6901,6 +6933,14 @@ 42 + + has been copied to the clipboard + has been copied to the clipboard + + libs/ui/src/lib/value/value.component.ts + 180 + + From the beginning Desde el principio @@ -6911,7 +6951,7 @@ Oops! Invalid currency. - ¡Ups! Moneda inválida. + ¡Vaya! Divisa no válida. apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html 48 @@ -6959,7 +6999,7 @@ to use our referral link and get a Ghostfolio Premium membership for one year - para usar nuestro enlace de referido y obtener una membresía Ghostfolio Premium por un año + para utilizar nuestro enlace de recomendación y obtener una membresía de Ghostfolio Premium por un año apps/client/src/app/pages/pricing/pricing-page.html 340 @@ -7039,7 +7079,7 @@ Ghostfolio is a lightweight wealth management application for individuals to keep track of stocks, ETFs or cryptocurrencies and make solid, data-driven investment decisions. - Ghostfolio es una aplicación de gestión de patrimonio para aquellos individuos que desean realizar un seguimiento de acciones, ETFs o criptomonedas y tomar decisiones de inversión sólidas y basadas en datos. + Ghostfolio es una aplicación ligera de gestión de patrimonio para que las personas realicen un seguimiento de acciones, ETFs o criptomonedas y tomen decisiones de inversión sólidas basadas en datos. apps/client/src/app/pages/about/overview/about-overview-page.html 10 @@ -7047,7 +7087,7 @@ Oops! Could not find any assets. - ¡Ups! No se pudieron encontrar activos. + ¡Vaya! No se pudieron encontrar activos. libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.html 40 @@ -7066,12 +7106,12 @@ Configurar clave API apps/client/src/app/components/admin-settings/admin-settings.component.html - 171 + 188 Get access to 80’000+ tickers from over 50 exchanges - Accede a más de 80’000 tickers de más de 50 bolsas + Accede a más de 80.000 tickers de más de 50 bolsas libs/ui/src/lib/i18n.ts 26 @@ -7102,7 +7142,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 45 + 44 libs/common/src/lib/routes/routes.ts @@ -7118,7 +7158,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 34 + 33 libs/common/src/lib/routes/routes.ts @@ -7153,7 +7193,7 @@ Threshold range - Rango umbral + Rango del umbral apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html 9 @@ -7172,7 +7212,7 @@ de apps/client/src/app/components/admin-settings/admin-settings.component.html - 135 + 152 @@ -7180,7 +7220,7 @@ solicitudes diarias apps/client/src/app/components/admin-settings/admin-settings.component.html - 137 + 154 @@ -7188,20 +7228,20 @@ Eliminar clave API apps/client/src/app/components/admin-settings/admin-settings.component.html - 161 + 178 Do you really want to delete the API key? - ¿Realmente deseas eliminar la clave API? + ¿Seguro que quieres eliminar la clave API? apps/client/src/app/components/admin-settings/admin-settings.component.ts - 127 + 133 Please enter your Ghostfolio API key: - Ingrese su clave API de Ghostfolio: + Ingresa tu clave API de Ghostfolio: apps/client/src/app/pages/api/api-page.component.ts 43 @@ -7209,14 +7249,14 @@ API Requests Today - Solicitudes de API hoy + Solicitudes de API de hoy apps/client/src/app/components/admin-users/admin-users.html 161 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 98 + 117 @@ -7229,7 +7269,7 @@ Set this API key in your self-hosted environment: - Configure esta clave API en su entorno autohospedado: + Configura esta clave API en tu entorno autoalojado: apps/client/src/app/components/user-account-membership/user-account-membership.component.ts 151 @@ -7245,7 +7285,7 @@ Do you really want to generate a new API key? - ¿Realmente desea generar una nueva clave API? + ¿Seguro que quieres generar una nueva clave API? apps/client/src/app/components/user-account-membership/user-account-membership.component.ts 159 @@ -7261,7 +7301,7 @@ Generate Ghostfolio Premium Data Provider API key for self-hosted environments... - Genere la clave API del proveedor de datos premium de Ghostfolio para entornos autohospedados... + Genera la clave API del proveedor de datos premium de Ghostfolio para entornos autoalojados... libs/ui/src/lib/membership-card/membership-card.component.html 29 @@ -7269,7 +7309,7 @@ out of - fuera de + de apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html 56 @@ -7277,7 +7317,7 @@ rules align with your portfolio. - Las reglas se alinean con su cartera. + reglas se alinean con tu cartera. apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html 58 @@ -7285,10 +7325,10 @@ Save - Ahorrar + Guardar apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 603 + 610 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7324,11 +7364,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 356 + 352 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 48 + 49 @@ -7340,7 +7380,7 @@ apps/client/src/app/components/user-account-access/user-account-access.component.ts - 260 + 257 @@ -7353,7 +7393,7 @@ Check the system status at - Verificar el estado del sistema en + Verifica el estado del sistema en apps/client/src/app/pages/about/overview/about-overview-page.html 57 @@ -7364,12 +7404,12 @@ Por favor, ingresa tu clave API de Ghostfolio. apps/client/src/app/components/admin-settings/admin-settings.component.ts - 146 + 152 Change with currency effect - Cambiar con el efecto del tipo de cambio de divisa + Cambio con el efecto de la divisa apps/client/src/app/pages/portfolio/analysis/analysis-page.html 116 @@ -7377,10 +7417,10 @@ AI prompt has been copied to the clipboard - El aviso de IA ha sido copiado al portapapeles + El prompt para la IA ha sido copiado al portapapeles apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 201 + 199 @@ -7393,10 +7433,10 @@ Lazy - Perezoso + Bajo demanda apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 225 + 231 @@ -7404,7 +7444,7 @@ Instantáneo apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 229 + 235 @@ -7412,7 +7452,7 @@ Precio de mercado por defecto apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 481 + 484 @@ -7420,7 +7460,7 @@ Modo apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 518 + 521 @@ -7428,7 +7468,7 @@ Selector apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 534 + 537 @@ -7436,7 +7476,7 @@ Encabezados de solicitud HTTP apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 494 + 497 @@ -7444,7 +7484,7 @@ final del día apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 225 + 231 @@ -7452,7 +7492,7 @@ en tiempo real apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 229 + 235 @@ -7460,7 +7500,7 @@ Abrir Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 202 + 200 @@ -7473,14 +7513,14 @@ Change - Cambiar + Cambio libs/ui/src/lib/holdings-table/holdings-table.component.html 138 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 377 @@ -7492,7 +7532,7 @@ apps/client/src/app/components/home-overview/home-overview.component.ts - 55 + 54 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -7500,11 +7540,11 @@ libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 377 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 381 + 390 @@ -7517,7 +7557,7 @@ Copy portfolio data to clipboard for AI prompt - Copiar los datos del portafolio al portapapeles para el aviso de IA + Copiar los datos de la cartera al portapapeles para el prompt de IA apps/client/src/app/pages/portfolio/analysis/analysis-page.html 42 @@ -7525,7 +7565,7 @@ Copy AI prompt to clipboard for analysis - Copiar el aviso de IA al portapapeles para análisis + Copiar el prompt de IA al portapapeles para análisis apps/client/src/app/pages/portfolio/analysis/analysis-page.html 67 @@ -7533,7 +7573,7 @@ Total amount - Cantidad total + Importe total apps/client/src/app/pages/portfolio/analysis/analysis-page.html 95 @@ -7565,7 +7605,7 @@ Terms and Conditions - Terminos y condiciones + Términos y Condiciones apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html 15 @@ -7608,27 +7648,27 @@ Token de seguridad apps/client/src/app/components/admin-users/admin-users.component.ts - 236 + 235 apps/client/src/app/components/user-account-access/user-account-access.component.ts - 170 + 167 Do you really want to generate a new security token for this user? - ¿Realmente deseas generar un nuevo token de seguridad para este usuario? + ¿Seguro que quieres generar un nuevo token de seguridad para este usuario? apps/client/src/app/components/admin-users/admin-users.component.ts - 241 + 240 Find account, holding or page... - Buscar cuenta, posición o página... + Busca una cuenta, posición o página... libs/ui/src/lib/assistant/assistant.component.ts - 151 + 115 @@ -7682,7 +7722,7 @@ and I agree to the Terms of Service. - y acepto los Términos del servicio. + y acepto los Términos de servicio. apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html 34 @@ -7693,7 +7733,7 @@ () ya está en uso. apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 633 + 649 @@ -7701,7 +7741,7 @@ Ocurrió un error al actualizar a (). apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 641 + 657 @@ -7765,7 +7805,7 @@ alguien apps/client/src/app/pages/public/public-page.component.ts - 59 + 61 @@ -7794,15 +7834,15 @@ Do you really want to delete this item? - ¿Realmente deseas eliminar este elemento? + ¿Seguro que quieres eliminar este elemento? libs/ui/src/lib/benchmark/benchmark.component.ts - 144 + 139 Log out - Finalizar la sesión + Cerrar sesión apps/client/src/app/components/header/header.component.html 329 @@ -7810,7 +7850,7 @@ Calculations are based on delayed market data and may not be displayed in real-time. - Los cálculos se basan en datos de mercado retrasados ​​y es posible que no se muestren en tiempo real. + Los cálculos se basan en datos de mercado con retraso y es posible que no se muestren en tiempo real. apps/client/src/app/components/home-market/home-market.html 45 @@ -7822,7 +7862,7 @@ changelog - registro-decambios + registro-de-cambios kebab-case libs/common/src/lib/routes/routes.ts @@ -7838,7 +7878,7 @@ La cuenta de usuario de demostración se ha sincronizado. apps/client/src/app/components/admin-overview/admin-overview.component.ts - 274 + 277 @@ -7851,7 +7891,7 @@ Set up - Fondo de Emergencia: Establecer + Establecer apps/client/src/app/pages/i18n/i18n-page.html 145 @@ -7873,25 +7913,25 @@ 150 - + Fee Ratio - Relación de tarifas + Relación de comisiones apps/client/src/app/pages/i18n/i18n-page.html 152 - - The fees do exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - Las tarifas superan el ${thresholdMax}% de su inversión inicial (${feeRatio}%) + + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + Las comisiones superan el ${thresholdMax}% de tu volumen total de inversión (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 154 - - The fees do not exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - Las tarifas no superan el ${thresholdMax}% de su inversión inicial (${feeRatio}%) + + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + Las comisiones no superan el ${thresholdMax}% de tu volumen total de inversión (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 158 @@ -7923,7 +7963,7 @@ Open Source Alternative to - Alternativa de software libre a + Alternativa de software de código abierto a libs/common/src/lib/routes/routes.ts 326 @@ -7985,7 +8025,7 @@ Fuel your self-hosted Ghostfolio with a powerful data provider to access 80,000+ tickers from over 50 exchanges worldwide. - Alimenta tu Ghostfolio autoalojado con un proveedor de datos potente para acceder a más de 80.000 tickers de más de 50 intercambios a nivel mundial. + Alimenta tu Ghostfolio autoalojado con un proveedor de datos potente para acceder a más de 80.000 tickers de más de 50 bolsas a nivel mundial. apps/client/src/app/components/admin-settings/admin-settings.component.html 16 @@ -8001,7 +8041,7 @@ Learn more - Aprender más + Más información apps/client/src/app/components/admin-settings/admin-settings.component.html 38 @@ -8052,7 +8092,7 @@ Mes actual apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 195 + 201 @@ -8060,11 +8100,11 @@ nuevo apps/client/src/app/components/admin-settings/admin-settings.component.html - 67 + 79 apps/client/src/app/pages/admin/admin-page.component.ts - 56 + 53 @@ -8093,7 +8133,7 @@ Equity - Acciones + Renta variable apps/client/src/app/pages/i18n/i18n-page.html 41 @@ -8157,7 +8197,7 @@ Investment: Base Currency - Inversión: Moneda base + Inversión: Divisa base apps/client/src/app/pages/i18n/i18n-page.html 85 @@ -8165,7 +8205,7 @@ The major part of your current investment is not in your base currency (${baseCurrencyValueRatio}% in ${baseCurrency}) - La mayor parte de tu inversión actual no está en tu moneda base (${baseCurrencyValueRatio}% en ${baseCurrency}) + La mayor parte de tu inversión actual no está en tu divisa base (${baseCurrencyValueRatio}% en ${baseCurrency}) apps/client/src/app/pages/i18n/i18n-page.html 88 @@ -8173,7 +8213,7 @@ The major part of your current investment is in your base currency (${baseCurrencyValueRatio}% in ${baseCurrency}) - La mayor parte de tu inversión actual está en tu moneda base (${baseCurrencyValueRatio}% en ${baseCurrency}) + La mayor parte de tu inversión actual está en tu divisa base (${baseCurrencyValueRatio}% en ${baseCurrency}) apps/client/src/app/pages/i18n/i18n-page.html 92 @@ -8218,10 +8258,10 @@ Do you really want to generate a new security token? - ¿Realmente deseas generar un nuevo token de seguridad? + ¿Seguro que quieres generar un nuevo token de seguridad? apps/client/src/app/components/user-account-access/user-account-access.component.ts - 175 + 172 @@ -8234,7 +8274,7 @@ If you encounter a bug, would like to suggest an improvement or a new feature, please join the Ghostfolio Slack community, post to @ghostfolio_ - Si encuentras un error, deseas sugerir una mejora o una nueva característica, por favor únete a la comunidad Ghostfolio Slack, publica en @ghostfolio_ + Si encuentras un error, deseas sugerir una mejora o una nueva funcionalidad, por favor únete a la comunidad de Ghostfolio en Slack y publica en @ghostfolio_ apps/client/src/app/pages/about/overview/about-overview-page.html 69 @@ -8245,7 +8285,7 @@ Acciones apps/client/src/app/components/markets/markets.component.ts - 52 + 51 apps/client/src/app/pages/features/features-page.html @@ -8257,7 +8297,7 @@ Criptomonedas apps/client/src/app/components/markets/markets.component.ts - 53 + 52 apps/client/src/app/pages/features/features-page.html @@ -8266,7 +8306,7 @@ - + apps/client/src/app/components/admin-users/admin-users.html 39 @@ -8277,7 +8317,7 @@ Gestionar perfil de activo apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 466 + 471 @@ -8310,7 +8350,7 @@ Account Cluster Risks - Riesgos de grupo de cuentas + Riesgos de agrupación de cuentas apps/client/src/app/pages/i18n/i18n-page.html 14 @@ -8318,7 +8358,7 @@ Asset Class Cluster Risks - Riesgos de grupo de clases de activos + Riesgos de agrupación de tipos de activos apps/client/src/app/pages/i18n/i18n-page.html 39 @@ -8326,7 +8366,7 @@ Currency Cluster Risks - Riesgos del clúster de divisas + Riesgos de agrupación de divisas apps/client/src/app/pages/i18n/i18n-page.html 83 @@ -8334,7 +8374,7 @@ Economic Market Cluster Risks - Riesgos del clúster de mercados económicos + Riesgos de agrupación de mercados económicos apps/client/src/app/pages/i18n/i18n-page.html 106 @@ -8366,7 +8406,7 @@ Buying Power - Poder de compra + Poder adquisitivo apps/client/src/app/pages/i18n/i18n-page.html 71 @@ -8374,7 +8414,7 @@ Your buying power is below ${thresholdMin} ${baseCurrency} - Tu poder de compra es inferior a ${thresholdMin} ${baseCurrency} + Tu poder adquisitivo está por debajo de ${thresholdMin} ${baseCurrency} apps/client/src/app/pages/i18n/i18n-page.html 73 @@ -8382,7 +8422,7 @@ Your buying power is 0 ${baseCurrency} - Tu poder de compra es 0 ${baseCurrency} + Tu poder adquisitivo es 0 ${baseCurrency} apps/client/src/app/pages/i18n/i18n-page.html 77 @@ -8390,7 +8430,7 @@ Your buying power exceeds ${thresholdMin} ${baseCurrency} - Tu poder de compra excede ${thresholdMin} ${baseCurrency} + Tu poder adquisitivo supera ${thresholdMin} ${baseCurrency} apps/client/src/app/pages/i18n/i18n-page.html 80 @@ -8398,7 +8438,7 @@ Regional Market Cluster Risks - Riesgos de los grupos de mercados regionales + Riesgos de agrupación de mercados regionales apps/client/src/app/pages/i18n/i18n-page.html 163 @@ -8422,7 +8462,7 @@ The developed markets contribution of your current investment (${developedMarketsValueRatio}%) exceeds ${thresholdMax}% - La contribución a los mercados desarrollados de tu inversión actual (${developedMarketsValueRatio}%) supera el ${thresholdMax}% + La contribución a mercados desarrollados de tu inversión actual (${developedMarketsValueRatio}%) supera ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 112 @@ -8430,7 +8470,7 @@ The developed markets contribution of your current investment (${developedMarketsValueRatio}%) is below ${thresholdMin}% - La contribución a los mercados desarrollados de tu inversión actual (${developedMarketsValueRatio}%) es inferior al ${thresholdMin}% + La contribución a mercados desarrollados de tu inversión actual (${developedMarketsValueRatio}%) es inferior a ${thresholdMin}% apps/client/src/app/pages/i18n/i18n-page.html 117 @@ -8438,7 +8478,7 @@ The developed markets contribution of your current investment (${developedMarketsValueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% - La contribución a los mercados desarrollados de tu inversión actual (${developedMarketsValueRatio}%) está dentro del rango de ${thresholdMin}% y ${thresholdMax}% + La contribución a mercados desarrollados de tu inversión actual (${developedMarketsValueRatio}%) está dentro del rango de ${thresholdMin}% y ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 122 @@ -8454,7 +8494,7 @@ The emerging markets contribution of your current investment (${emergingMarketsValueRatio}%) exceeds ${thresholdMax}% - La contribución a los mercados emergentes de tu inversión actual (${emergingMarketsValueRatio}%) supera el ${thresholdMax}% + La contribución a mercados emergentes de tu inversión actual (${emergingMarketsValueRatio}%) supera ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 130 @@ -8462,7 +8502,7 @@ The emerging markets contribution of your current investment (${emergingMarketsValueRatio}%) is below ${thresholdMin}% - La contribución a los mercados emergentes de tu inversión actual (${emergingMarketsValueRatio}%) es inferior al ${thresholdMin}% + La contribución a mercados emergentes de tu inversión actual (${emergingMarketsValueRatio}%) es inferior a ${thresholdMin}% apps/client/src/app/pages/i18n/i18n-page.html 135 @@ -8470,7 +8510,7 @@ The emerging markets contribution of your current investment (${emergingMarketsValueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% - La contribución a los mercados emergentes de tu inversión actual (${emergingMarketsValueRatio}%) está dentro del rango de ${thresholdMin}% y ${thresholdMax}% + La contribución a mercados emergentes de tu inversión actual (${emergingMarketsValueRatio}%) está dentro del rango de ${thresholdMin}% y ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 140 @@ -8486,7 +8526,7 @@ Your net worth is managed by 0 accounts - Su patrimonio neto es administrado por 0 cuentas + Tu patrimonio neto es administrado por 0 cuentas apps/client/src/app/pages/i18n/i18n-page.html 33 @@ -8502,7 +8542,7 @@ The Asia-Pacific market contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% - La contribución al mercado de Asia-Pacífico de tu inversión actual (${valueRatio}%) supera el ${thresholdMax}% + La contribución al mercado Asiático-Pacífico de tu inversión actual (${valueRatio}%) supera ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 167 @@ -8510,7 +8550,7 @@ The Asia-Pacific market contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% - La contribución al mercado de Asia-Pacífico de tu inversión actual (${valueRatio}%) es inferior al ${thresholdMin}% + La contribución al mercado Asiático-Pacífico de tu inversión actual (${valueRatio}%) es inferior a ${thresholdMin}% apps/client/src/app/pages/i18n/i18n-page.html 171 @@ -8518,7 +8558,7 @@ The Asia-Pacific market contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% - La contribución al mercado de Asia-Pacífico de tu inversión actual (${valueRatio}%) está dentro del rango de ${thresholdMin}% y ${thresholdMax}% + La contribución al mercado Asiático-Pacífico de tu inversión actual (${valueRatio}%) está dentro del rango de ${thresholdMin}% y ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 175 @@ -8534,7 +8574,7 @@ The Emerging Markets contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% - La contribución a los mercados emergentes de tu inversión actual (${valueRatio}%) supera el ${thresholdMax}% + La contribución a mercados emergentes de tu inversión actual (${valueRatio}%) supera ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 183 @@ -8542,7 +8582,7 @@ The Emerging Markets contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% - La contribución a los mercados emergentes de tu inversión actual (${valueRatio}%) es inferior al ${thresholdMin}% + La contribución a mercados emergentes de tu inversión actual (${valueRatio}%) es inferior a ${thresholdMin}% apps/client/src/app/pages/i18n/i18n-page.html 187 @@ -8550,7 +8590,7 @@ The Emerging Markets contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% - La contribución a los mercados emergentes de tu inversión actual (${valueRatio}%) está dentro del rango de ${thresholdMin}% y ${thresholdMax}% + La contribución a mercados emergentes de tu inversión actual (${valueRatio}%) está dentro del rango de ${thresholdMin}% y ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 191 @@ -8566,7 +8606,7 @@ The Europe market contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% - La contribución al mercado europeo de tu inversión actual (${valueRatio}%) supera el ${thresholdMax}% + La contribución al mercado europeo de tu inversión actual (${valueRatio}%) supera ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 197 @@ -8574,7 +8614,7 @@ The Europe market contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% - La contribución al mercado europeo de tu inversión actual (${valueRatio}%) es inferior al ${thresholdMin}% + La contribución al mercado europeo de tu inversión actual (${valueRatio}%) es inferior a ${thresholdMin}% apps/client/src/app/pages/i18n/i18n-page.html 201 @@ -8598,7 +8638,7 @@ The Japan market contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% - La contribución al mercado japonés de su inversión actual (${valueRatio}%) supera el ${thresholdMax}% + La contribución al mercado japonés de tu inversión actual (${valueRatio}%) supera el ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 211 @@ -8606,7 +8646,7 @@ The Japan market contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% - La contribución al mercado japonés de su inversión actual (${valueRatio}%) es inferior a ${thresholdMin}% + La contribución al mercado japonés de tu inversión actual (${valueRatio}%) es inferior a ${thresholdMin}% apps/client/src/app/pages/i18n/i18n-page.html 215 @@ -8614,7 +8654,7 @@ The Japan market contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% - La contribución al mercado japonés de su inversión actual (${valueRatio}%) está dentro del rango de ${thresholdMin}% y ${thresholdMax}% + La contribución al mercado japonés de tu inversión actual (${valueRatio}%) está dentro del rango de ${thresholdMin}% y ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 219 @@ -8630,7 +8670,7 @@ The North America market contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% - La contribución del mercado de América del Norte de su inversión actual (${valueRatio}%) supera el ${thresholdMax}% + La contribución al mercado de América del Norte de tu inversión actual (${valueRatio}%) supera el ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 225 @@ -8638,7 +8678,7 @@ The North America market contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% - La contribución al mercado de América del Norte de su inversión actual (${valueRatio}%) es inferior a ${thresholdMin}% + La contribución al mercado de América del Norte de tu inversión actual (${valueRatio}%) es inferior a ${thresholdMin}% apps/client/src/app/pages/i18n/i18n-page.html 229 @@ -8646,7 +8686,7 @@ The North America market contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% - La contribución al mercado de América del Norte de su inversión actual (${valueRatio}%) está dentro del rango de ${thresholdMin}% y ${thresholdMax}% + La contribución al mercado de América del Norte de tu inversión actual (${valueRatio}%) está dentro del rango de ${thresholdMin}% y ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 233 @@ -8666,7 +8706,7 @@ Join the Ghostfolio Slack community - Únete a la comunidad de Ghostfolio Slack + Únete a la comunidad de Ghostfolio en Slack apps/client/src/app/pages/about/overview/about-overview-page.html 109 @@ -8674,7 +8714,7 @@ Follow Ghostfolio on X (formerly Twitter) - Siga a Ghostfolio en X (anteriormente Twitter) + Sigue a Ghostfolio en X (anteriormente Twitter) apps/client/src/app/pages/about/overview/about-overview-page.html 118 @@ -8697,12 +8737,12 @@ Fecha de registro apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 26 + 45 Follow Ghostfolio on LinkedIn - Siga a Ghostfolio en LinkedIn + Sigue a Ghostfolio en LinkedIn apps/client/src/app/pages/about/overview/about-overview-page.html 147 @@ -8710,7 +8750,7 @@ Ghostfolio is an independent & bootstrapped business - Ghostfolio es una empresa independiente y autónoma + Ghostfolio es una empresa independiente y autofinanciada apps/client/src/app/pages/about/overview/about-overview-page.html 157 @@ -8718,7 +8758,7 @@ Support Ghostfolio - Soporte Ghostfolio + Apoya a Ghostfolio apps/client/src/app/pages/about/overview/about-overview-page.html 166 diff --git a/apps/client/src/locales/messages.fr.xlf b/apps/client/src/locales/messages.fr.xlf index 0da1c3f6a..eec144e92 100644 --- a/apps/client/src/locales/messages.fr.xlf +++ b/apps/client/src/locales/messages.fr.xlf @@ -42,7 +42,7 @@ Type apps/client/src/app/components/admin-jobs/admin-jobs.html - 48 + 57 apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html @@ -114,7 +114,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 309 + 310 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -126,7 +126,7 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 46 + 58 apps/client/src/app/components/admin-tag/admin-tag.component.html @@ -142,7 +142,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 139 + 135 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -186,7 +186,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 316 + 317 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -198,7 +198,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 145 + 141 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -234,15 +234,15 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 205 + 201 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 208 + 204 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 211 + 207 libs/ui/src/lib/account-balances/account-balances.component.html @@ -290,11 +290,11 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 74 + 78 apps/client/src/app/components/admin-tag/admin-tag.component.html - 67 + 71 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -322,11 +322,15 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 85 + 89 apps/client/src/app/components/admin-tag/admin-tag.component.html - 78 + 82 + + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 22 libs/ui/src/lib/account-balances/account-balances.component.html @@ -350,7 +354,7 @@ Voulez-vous vraiment supprimer ce compte ? libs/ui/src/lib/accounts-table/accounts-table.component.ts - 150 + 148 @@ -358,7 +362,7 @@ Source Données apps/client/src/app/components/admin-jobs/admin-jobs.html - 82 + 91 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -370,7 +374,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 155 + 151 libs/ui/src/lib/i18n.ts @@ -382,7 +386,7 @@ Tentatives apps/client/src/app/components/admin-jobs/admin-jobs.html - 120 + 129 @@ -390,7 +394,7 @@ Créé apps/client/src/app/components/admin-jobs/admin-jobs.html - 134 + 143 @@ -398,7 +402,7 @@ Terminé apps/client/src/app/components/admin-jobs/admin-jobs.html - 143 + 152 @@ -406,11 +410,11 @@ Statut apps/client/src/app/components/admin-jobs/admin-jobs.html - 152 + 161 apps/client/src/app/components/admin-settings/admin-settings.component.html - 92 + 104 @@ -426,7 +430,7 @@ Supprimer Tâches apps/client/src/app/components/admin-jobs/admin-jobs.html - 193 + 202 @@ -434,7 +438,7 @@ Profils d’Actifs apps/client/src/app/components/admin-settings/admin-settings.component.html - 106 + 123 libs/ui/src/lib/assistant/assistant.html @@ -446,11 +450,11 @@ Données historiques du marché apps/client/src/app/components/admin-jobs/admin-jobs.html - 54 + 63 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 448 + 451 @@ -458,7 +462,7 @@ Voir Données apps/client/src/app/components/admin-jobs/admin-jobs.html - 208 + 217 @@ -466,7 +470,7 @@ Voir la Stacktrace apps/client/src/app/components/admin-jobs/admin-jobs.html - 216 + 225 @@ -474,7 +478,7 @@ Supprimer Tâche apps/client/src/app/components/admin-jobs/admin-jobs.html - 224 + 233 @@ -490,7 +494,7 @@ Date apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 161 + 157 libs/ui/src/lib/account-balances/account-balances.component.html @@ -526,7 +530,7 @@ Filtrer par... apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 385 + 383 @@ -566,7 +570,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 44 + 40 @@ -634,7 +638,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 53 + 72 @@ -646,7 +650,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 396 + 399 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -654,7 +658,7 @@ apps/client/src/app/pages/public/public-page.html - 114 + 113 @@ -666,7 +670,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 407 + 410 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -678,7 +682,7 @@ Équivalence de Symboles apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 384 + 387 @@ -686,7 +690,7 @@ Note apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 432 + 435 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -694,7 +698,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 275 + 271 @@ -702,7 +706,7 @@ Voulez-vous vraiment supprimer ce code promotionnel ? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 193 + 196 @@ -710,7 +714,7 @@ Voulez-vous vraiment vider le cache ? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 230 + 233 @@ -718,7 +722,7 @@ Veuillez définir votre message système : apps/client/src/app/components/admin-overview/admin-overview.component.ts - 250 + 253 @@ -758,7 +762,7 @@ Étiquettes apps/client/src/app/components/admin-settings/admin-settings.component.html - 201 + 218 libs/ui/src/lib/tags-selector/tags-selector.component.html @@ -878,7 +882,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 89 + 108 @@ -894,11 +898,11 @@ Could not validate form apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 554 + 570 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 557 + 573 @@ -938,7 +942,7 @@ Référence apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 376 + 379 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -974,7 +978,7 @@ apps/client/src/app/components/header/header.component.ts - 297 + 298 apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html @@ -994,15 +998,15 @@ Oups! Jeton de Sécurité Incorrect. apps/client/src/app/components/header/header.component.ts - 312 + 313 apps/client/src/app/components/user-account-access/user-account-access.component.ts - 154 + 152 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 193 + 191 @@ -1010,7 +1014,7 @@ Gérer les Activités apps/client/src/app/components/home-holdings/home-holdings.html - 67 + 64 @@ -1018,11 +1022,11 @@ Peur apps/client/src/app/components/home-market/home-market.component.ts - 42 + 41 apps/client/src/app/components/markets/markets.component.ts - 47 + 46 libs/ui/src/lib/i18n.ts @@ -1034,11 +1038,11 @@ Avidité apps/client/src/app/components/home-market/home-market.component.ts - 43 + 42 apps/client/src/app/components/markets/markets.component.ts - 48 + 47 libs/ui/src/lib/i18n.ts @@ -1062,7 +1066,7 @@ Montant Total apps/client/src/app/components/investment-chart/investment-chart.component.ts - 143 + 146 @@ -1174,7 +1178,7 @@ Performance Absolue Brute apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 73 + 77 @@ -1182,7 +1186,7 @@ Performance Absolue Nette apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 107 + 111 apps/client/src/app/pages/portfolio/analysis/analysis-page.html @@ -1194,7 +1198,7 @@ Performance nette apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 123 + 127 apps/client/src/app/pages/portfolio/analysis/analysis-page.html @@ -1206,7 +1210,7 @@ Actifs Totaux apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 149 + 153 @@ -1214,7 +1218,7 @@ Pouvoir d’Achat apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 241 + 248 @@ -1222,7 +1226,7 @@ Exclus de l’Analyse apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 267 + 274 @@ -1230,7 +1234,7 @@ Fortune apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 317 + 324 @@ -1238,7 +1242,7 @@ Performance annualisée apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 331 + 338 @@ -1274,7 +1278,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 189 + 185 libs/ui/src/lib/activities-table/activities-table.component.html @@ -1290,7 +1294,7 @@ Signaler une Erreur de Données apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 451 + 456 @@ -1302,7 +1306,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 363 + 362 @@ -1310,11 +1314,11 @@ CDA apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 199 + 205 libs/ui/src/lib/assistant/assistant.component.ts - 375 + 374 @@ -1322,11 +1326,11 @@ 1A apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 203 + 209 libs/ui/src/lib/assistant/assistant.component.ts - 385 + 384 @@ -1334,11 +1338,11 @@ 5A apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 207 + 213 libs/ui/src/lib/assistant/assistant.component.ts - 409 + 408 @@ -1354,11 +1358,11 @@ Max apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 211 + 217 libs/ui/src/lib/assistant/assistant.component.ts - 415 + 414 @@ -1382,7 +1386,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 195 + 194 @@ -1394,7 +1398,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 193 + 192 @@ -1410,7 +1414,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 196 + 195 @@ -1470,7 +1474,7 @@ Auto apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 70 + 69 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -1514,7 +1518,7 @@ Voulez-vous vraiment supprimer cette méthode de connexion ? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 282 + 279 @@ -1582,7 +1586,7 @@ Paramètres régionaux apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 512 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -1662,7 +1666,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 11 + 30 @@ -1710,11 +1714,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 375 + 381 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 66 + 85 apps/client/src/app/pages/accounts/accounts-page.html @@ -1758,7 +1762,7 @@ Données du marché apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 398 + 403 libs/common/src/lib/routes/routes.ts @@ -1902,7 +1906,7 @@ Puisque vous êtes déjà connecté·e, vous ne pouvez pas accéder au compte de démonstration. apps/client/src/app/pages/demo/demo-page.component.ts - 35 + 32 @@ -1990,7 +1994,7 @@ Marchés apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 378 + 381 apps/client/src/app/components/footer/footer.component.html @@ -2014,7 +2018,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 40 + 39 libs/common/src/lib/routes/routes.ts @@ -2042,7 +2046,7 @@ apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 115 + 113 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -2062,11 +2066,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 342 + 348 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 75 + 94 apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -2094,7 +2098,7 @@ Current week apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 191 + 197 @@ -2138,7 +2142,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 124 + 120 @@ -2146,7 +2150,7 @@ Prix Unitaire apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 214 + 210 libs/ui/src/lib/activities-table/activities-table.component.html @@ -2158,7 +2162,7 @@ Import des données... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 175 + 174 @@ -2166,7 +2170,7 @@ L’import est terminé apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 185 + 184 @@ -2182,7 +2186,7 @@ Validation des données... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 299 + 293 @@ -2218,7 +2222,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 71 + 67 @@ -2310,7 +2314,7 @@ apps/client/src/app/pages/public/public-page.html - 151 + 150 @@ -2334,7 +2338,7 @@ apps/client/src/app/pages/public/public-page.html - 168 + 167 @@ -2342,7 +2346,7 @@ Latest activities apps/client/src/app/pages/public/public-page.html - 211 + 210 @@ -2354,7 +2358,7 @@ apps/client/src/app/pages/public/public-page.html - 177 + 176 @@ -2366,7 +2370,7 @@ apps/client/src/app/pages/public/public-page.html - 186 + 185 @@ -2402,7 +2406,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 365 + 372 apps/client/src/app/pages/features/features-page.html @@ -2410,11 +2414,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 202 + 198 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 76 + 75 libs/ui/src/lib/i18n.ts @@ -2434,7 +2438,7 @@ Dépôt libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 377 + 404 @@ -2442,7 +2446,7 @@ Mensuel apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 91 + 90 @@ -2546,7 +2550,7 @@ Continents apps/client/src/app/pages/public/public-page.html - 132 + 131 @@ -2562,7 +2566,7 @@ Ghostfolio vous aide à garder un aperçu de votre patrimoine. apps/client/src/app/pages/public/public-page.html - 238 + 237 @@ -2590,7 +2594,7 @@ apps/client/src/app/pages/public/public-page.html - 242 + 241 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -2644,6 +2648,10 @@ apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html 88 + + libs/ui/src/lib/value/value.component.html + 18 + Resources @@ -2696,6 +2704,10 @@ Overview Aperçu + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 7 + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 114 @@ -2714,11 +2726,11 @@ apps/client/src/app/pages/admin/admin-page.component.ts - 48 + 45 apps/client/src/app/pages/resources/resources-page.component.ts - 30 + 29 libs/common/src/lib/routes/routes.ts @@ -2798,7 +2810,7 @@ Voulez-vous vraiment supprimer cette activité ? libs/ui/src/lib/activities-table/activities-table.component.ts - 288 + 292 @@ -2850,11 +2862,11 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 352 + 359 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 387 + 414 libs/ui/src/lib/i18n.ts @@ -2866,7 +2878,7 @@ Épargne libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 397 + 424 @@ -2894,7 +2906,7 @@ Montrer tout libs/ui/src/lib/holdings-table/holdings-table.component.html - 216 + 212 @@ -2930,7 +2942,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 326 + 327 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -2938,7 +2950,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 290 + 286 libs/ui/src/lib/i18n.ts @@ -2962,7 +2974,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 342 + 343 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -2970,7 +2982,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 309 + 305 libs/ui/src/lib/i18n.ts @@ -2982,7 +2994,7 @@ Fonds d’Urgence apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 164 + 168 apps/client/src/app/pages/features/features-page.html @@ -3002,7 +3014,7 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 437 + 451 @@ -3010,7 +3022,7 @@ Symbole apps/client/src/app/components/admin-jobs/admin-jobs.html - 68 + 77 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -3026,7 +3038,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 315 + 318 libs/ui/src/lib/i18n.ts @@ -3050,7 +3062,7 @@ Cash apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 212 + 219 libs/ui/src/lib/i18n.ts @@ -3098,7 +3110,7 @@ Authentication apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 35 + 54 @@ -3230,7 +3242,7 @@ apps/client/src/app/pages/public/public-page.html - 196 + 195 libs/ui/src/lib/benchmark/benchmark.component.html @@ -3238,11 +3250,11 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 439 + 453 libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 452 + 467 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -3274,7 +3286,7 @@ Annuel apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 92 + 91 @@ -3282,7 +3294,7 @@ Importer Dividendes apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 137 + 136 libs/ui/src/lib/activities-table/activities-table.component.html @@ -3298,7 +3310,7 @@ Valide jusqu’au apps/client/src/app/components/admin-settings/admin-settings.component.html - 74 + 86 libs/ui/src/lib/membership-card/membership-card.component.html @@ -3337,6 +3349,14 @@ 22 + + No Activities + No Activities + + apps/client/src/app/components/admin-market-data/admin-market-data.component.ts + 145 + + Retirement Provision Réserve pour retraite @@ -3610,11 +3630,11 @@ Could not save asset profile apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 588 + 604 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 591 + 607 @@ -3634,7 +3654,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 88 + 92 @@ -3798,7 +3818,7 @@ Voulez-vous vraiment supprimer toutes vos activités ? libs/ui/src/lib/activities-table/activities-table.component.ts - 278 + 282 @@ -3809,6 +3829,14 @@ 306 + + Explore + Explore + + apps/client/src/app/pages/resources/overview/resources-overview.component.html + 11 + + By By @@ -3830,7 +3858,7 @@ Current year apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 199 + 205 @@ -3846,11 +3874,11 @@ Lien apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 419 + 422 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 550 + 553 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -3866,7 +3894,7 @@ Asset profile has been saved apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 578 + 594 @@ -3874,7 +3902,7 @@ Voulez-vous vraiment supprimer cette plateforme ? apps/client/src/app/components/admin-platform/admin-platform.component.ts - 106 + 111 @@ -3882,7 +3910,7 @@ Platformes apps/client/src/app/components/admin-settings/admin-settings.component.html - 195 + 212 @@ -3890,7 +3918,7 @@ Mettre à jour le Solde apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 112 + 108 @@ -4070,7 +4098,7 @@ Dettes apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 295 + 302 apps/client/src/app/pages/features/features-page.html @@ -4226,7 +4254,7 @@ Configuration du Scraper apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 471 + 474 @@ -4470,7 +4498,7 @@ ETF sans Pays apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 136 + 135 @@ -4478,7 +4506,7 @@ ETF sans Secteurs apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 141 + 140 @@ -4486,7 +4514,7 @@ Actifs apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 233 @@ -4658,7 +4686,7 @@ Job ID apps/client/src/app/components/admin-jobs/admin-jobs.html - 34 + 43 @@ -4714,11 +4742,11 @@ Devises apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 131 + 130 apps/client/src/app/pages/public/public-page.html - 96 + 95 @@ -4766,11 +4794,11 @@ Could not parse scraper configuration apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 509 + 525 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 512 + 528 @@ -5432,7 +5460,7 @@ Frais apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 262 + 258 libs/ui/src/lib/activities-table/activities-table.component.html @@ -5464,7 +5492,7 @@ Confirmez la suppression de ce tag ? apps/client/src/app/components/admin-tag/admin-tag.component.ts - 103 + 108 @@ -5532,7 +5560,7 @@ Statut apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 48 + 67 libs/common/src/lib/routes/routes.ts @@ -5564,7 +5592,7 @@ Profil d’Actif apps/client/src/app/components/admin-jobs/admin-jobs.html - 52 + 61 @@ -5688,7 +5716,7 @@ Oops! Echec du parsing des données historiques. libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.ts - 262 + 284 @@ -5696,7 +5724,7 @@ Confirmer la suppresion de ce message système? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 206 + 209 @@ -5720,7 +5748,7 @@ Cash Balances apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 148 + 146 @@ -5740,7 +5768,7 @@ Voulez-vous vraiment supprimer ce solde de compte ? libs/ui/src/lib/account-balances/account-balances.component.ts - 120 + 113 @@ -5756,7 +5784,7 @@ Le prix actuel du marché est apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 706 + 722 @@ -5764,7 +5792,7 @@ Test apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 568 + 571 @@ -5852,11 +5880,11 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 81 + 80 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 97 + 96 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -5876,7 +5904,7 @@ Close Holding apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 442 + 447 @@ -5916,7 +5944,7 @@ Week to date libs/ui/src/lib/assistant/assistant.component.ts - 367 + 366 @@ -5924,11 +5952,11 @@ WTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 191 + 197 libs/ui/src/lib/assistant/assistant.component.ts - 367 + 366 @@ -5936,7 +5964,7 @@ Month to date libs/ui/src/lib/assistant/assistant.component.ts - 371 + 370 @@ -5944,11 +5972,11 @@ MTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 195 + 201 libs/ui/src/lib/assistant/assistant.component.ts - 371 + 370 @@ -5956,7 +5984,7 @@ Year to date libs/ui/src/lib/assistant/assistant.component.ts - 375 + 374 @@ -5992,7 +6020,7 @@ année apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 203 + 209 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -6004,7 +6032,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 385 + 384 @@ -6012,11 +6040,11 @@ années apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 207 + 213 libs/ui/src/lib/assistant/assistant.component.ts - 409 + 408 @@ -6032,7 +6060,7 @@ Collecter les données apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 587 + 594 apps/client/src/app/components/admin-overview/admin-overview.html @@ -6044,7 +6072,7 @@ Général apps/client/src/app/pages/faq/faq-page.component.ts - 49 + 41 @@ -6052,7 +6080,7 @@ Cloud apps/client/src/app/pages/faq/faq-page.component.ts - 54 + 46 libs/common/src/lib/routes/routes.ts @@ -6064,7 +6092,7 @@ Self-Hosting apps/client/src/app/pages/faq/faq-page.component.ts - 60 + 52 libs/common/src/lib/routes/routes.ts @@ -6105,7 +6133,7 @@ Actif apps/client/src/app/components/home-holdings/home-holdings.component.ts - 64 + 63 @@ -6113,7 +6141,7 @@ Clôturé apps/client/src/app/components/home-holdings/home-holdings.component.ts - 65 + 64 @@ -6145,7 +6173,7 @@ Execute la tâche apps/client/src/app/components/admin-jobs/admin-jobs.html - 220 + 229 @@ -6153,7 +6181,7 @@ Priorité apps/client/src/app/components/admin-jobs/admin-jobs.html - 96 + 105 @@ -6209,7 +6237,7 @@ Confirmer la suppresion de votre compte Ghostfolio ? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 208 + 205 @@ -6257,7 +6285,7 @@ Include in apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 374 + 377 @@ -6265,7 +6293,7 @@ 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 - 336 + 333 @@ -6281,7 +6309,7 @@ Benchmarks apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 126 + 125 @@ -6329,7 +6357,7 @@ Souhaitez-vous affiner votre stratégie d’investissement personnelle? apps/client/src/app/pages/public/public-page.html - 234 + 233 @@ -6661,7 +6689,7 @@ Erreur apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 697 + 713 @@ -6713,7 +6741,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 592 + 599 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6745,7 +6773,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 345 + 341 apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html @@ -6753,7 +6781,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 46 + 47 libs/ui/src/lib/i18n.ts @@ -6765,7 +6793,7 @@ Fermer apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 594 + 601 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6791,13 +6819,17 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 68 + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 127 + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html 107 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 347 + 343 libs/ui/src/lib/i18n.ts @@ -6809,7 +6841,7 @@ Role apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 14 + 33 @@ -6833,7 +6865,7 @@ Résumé du portefeuille apps/client/src/app/components/admin-jobs/admin-jobs.html - 56 + 65 @@ -6900,6 +6932,14 @@ 42 + + has been copied to the clipboard + has been copied to the clipboard + + libs/ui/src/lib/value/value.component.ts + 180 + + From the beginning Depuis le début @@ -7065,7 +7105,7 @@ Définir clé API apps/client/src/app/components/admin-settings/admin-settings.component.html - 171 + 188 @@ -7101,7 +7141,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 45 + 44 libs/common/src/lib/routes/routes.ts @@ -7117,7 +7157,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 34 + 33 libs/common/src/lib/routes/routes.ts @@ -7171,7 +7211,7 @@ sur apps/client/src/app/components/admin-settings/admin-settings.component.html - 135 + 152 @@ -7179,7 +7219,7 @@ requêtes journalières apps/client/src/app/components/admin-settings/admin-settings.component.html - 137 + 154 @@ -7187,7 +7227,7 @@ Retirer la clé API apps/client/src/app/components/admin-settings/admin-settings.component.html - 161 + 178 @@ -7195,7 +7235,7 @@ Voulez-vous vraiment supprimer la clé API? apps/client/src/app/components/admin-settings/admin-settings.component.ts - 127 + 133 @@ -7215,7 +7255,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 98 + 117 @@ -7287,7 +7327,7 @@ Sauvegarder apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 603 + 610 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7323,11 +7363,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 356 + 352 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 48 + 49 @@ -7339,7 +7379,7 @@ apps/client/src/app/components/user-account-access/user-account-access.component.ts - 260 + 257 @@ -7363,7 +7403,7 @@ Veuillez saisir votre clé API Ghostfolio. apps/client/src/app/components/admin-settings/admin-settings.component.ts - 146 + 152 @@ -7379,7 +7419,7 @@ Le prompt IA a été copié dans le presse-papiers apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 201 + 199 @@ -7395,7 +7435,7 @@ Paresseux apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 225 + 231 @@ -7403,7 +7443,7 @@ Instantané apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 229 + 235 @@ -7411,7 +7451,7 @@ Prix du marché par défaut apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 481 + 484 @@ -7419,7 +7459,7 @@ Mode apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 518 + 521 @@ -7427,7 +7467,7 @@ Selecteur apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 534 + 537 @@ -7435,7 +7475,7 @@ En-têtes de requête HTTP apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 494 + 497 @@ -7443,7 +7483,7 @@ fin de journée apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 225 + 231 @@ -7451,7 +7491,7 @@ temps réel apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 229 + 235 @@ -7459,7 +7499,7 @@ Ouvrir Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 202 + 200 @@ -7479,7 +7519,7 @@ libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 377 @@ -7491,7 +7531,7 @@ apps/client/src/app/components/home-overview/home-overview.component.ts - 55 + 54 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -7499,11 +7539,11 @@ libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 377 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 381 + 390 @@ -7607,11 +7647,11 @@ Jeton de sécurité apps/client/src/app/components/admin-users/admin-users.component.ts - 236 + 235 apps/client/src/app/components/user-account-access/user-account-access.component.ts - 170 + 167 @@ -7619,7 +7659,7 @@ Voulez-vous vraiment générer un nouveau jeton de sécurité pour cet utilisateur ? apps/client/src/app/components/admin-users/admin-users.component.ts - 241 + 240 @@ -7627,7 +7667,7 @@ Find account, holding or page... libs/ui/src/lib/assistant/assistant.component.ts - 151 + 115 @@ -7692,7 +7732,7 @@ () est déjà utilisé. apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 633 + 649 @@ -7700,7 +7740,7 @@ Une erreur s’est produite lors de la mise à jour vers (). apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 641 + 657 @@ -7764,7 +7804,7 @@ quelqu’un apps/client/src/app/pages/public/public-page.component.ts - 59 + 61 @@ -7796,7 +7836,7 @@ Voulez-vous vraiment supprimer cet élément? libs/ui/src/lib/benchmark/benchmark.component.ts - 144 + 139 @@ -7837,7 +7877,7 @@ Le compte utilisateur de démonstration a été synchronisé. apps/client/src/app/components/admin-overview/admin-overview.component.ts - 274 + 277 @@ -7872,25 +7912,25 @@ 150 - + Fee Ratio - Ratio de frais + Fee Ratio apps/client/src/app/pages/i18n/i18n-page.html 152 - - The fees do exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - Les frais dépassent ${thresholdMax}% de votre investissement initial (${feeRatio}%) + + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 154 - - The fees do not exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - Les frais ne dépassent pas ${thresholdMax}% de votre investissement initial (${feeRatio}%) + + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 158 @@ -8051,7 +8091,7 @@ Current month apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 195 + 201 @@ -8059,11 +8099,11 @@ new apps/client/src/app/components/admin-settings/admin-settings.component.html - 67 + 79 apps/client/src/app/pages/admin/admin-page.component.ts - 56 + 53 @@ -8220,7 +8260,7 @@ Voulez-vous vraiment générer un nouveau jeton de sécurité? apps/client/src/app/components/user-account-access/user-account-access.component.ts - 175 + 172 @@ -8244,7 +8284,7 @@ Actions apps/client/src/app/components/markets/markets.component.ts - 52 + 51 apps/client/src/app/pages/features/features-page.html @@ -8256,7 +8296,7 @@ Crypto-monnaies apps/client/src/app/components/markets/markets.component.ts - 53 + 52 apps/client/src/app/pages/features/features-page.html @@ -8276,7 +8316,7 @@ Gérer le profil d’actif apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 466 + 471 @@ -8696,7 +8736,7 @@ Registration Date apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 26 + 45 diff --git a/apps/client/src/locales/messages.it.xlf b/apps/client/src/locales/messages.it.xlf index 746e1fbd1..b143bbde3 100644 --- a/apps/client/src/locales/messages.it.xlf +++ b/apps/client/src/locales/messages.it.xlf @@ -51,7 +51,7 @@ Tipo apps/client/src/app/components/admin-jobs/admin-jobs.html - 48 + 57 apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html @@ -107,7 +107,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 309 + 310 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -119,7 +119,7 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 46 + 58 apps/client/src/app/components/admin-tag/admin-tag.component.html @@ -135,7 +135,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 139 + 135 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -179,15 +179,15 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 205 + 201 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 208 + 204 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 211 + 207 libs/ui/src/lib/account-balances/account-balances.component.html @@ -235,11 +235,11 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 74 + 78 apps/client/src/app/components/admin-tag/admin-tag.component.html - 67 + 71 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -267,11 +267,15 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 85 + 89 apps/client/src/app/components/admin-tag/admin-tag.component.html - 78 + 82 + + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 22 libs/ui/src/lib/account-balances/account-balances.component.html @@ -295,7 +299,7 @@ Vuoi davvero eliminare questo account? libs/ui/src/lib/accounts-table/accounts-table.component.ts - 150 + 148 @@ -303,7 +307,7 @@ Elimina i lavori apps/client/src/app/components/admin-jobs/admin-jobs.html - 193 + 202 @@ -311,7 +315,7 @@ Sorgente dei dati apps/client/src/app/components/admin-jobs/admin-jobs.html - 82 + 91 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -323,7 +327,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 155 + 151 libs/ui/src/lib/i18n.ts @@ -335,7 +339,7 @@ Tentativi apps/client/src/app/components/admin-jobs/admin-jobs.html - 120 + 129 @@ -343,7 +347,7 @@ Creato apps/client/src/app/components/admin-jobs/admin-jobs.html - 134 + 143 @@ -351,7 +355,7 @@ Finito apps/client/src/app/components/admin-jobs/admin-jobs.html - 143 + 152 @@ -359,11 +363,11 @@ Stato apps/client/src/app/components/admin-jobs/admin-jobs.html - 152 + 161 apps/client/src/app/components/admin-settings/admin-settings.component.html - 92 + 104 @@ -379,7 +383,7 @@ Profilo dell’asset apps/client/src/app/components/admin-settings/admin-settings.component.html - 106 + 123 libs/ui/src/lib/assistant/assistant.html @@ -391,11 +395,11 @@ Dati storici del mercato apps/client/src/app/components/admin-jobs/admin-jobs.html - 54 + 63 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 448 + 451 @@ -403,7 +407,7 @@ Visualizza i dati apps/client/src/app/components/admin-jobs/admin-jobs.html - 208 + 217 @@ -411,7 +415,7 @@ Visualizza Stacktrace apps/client/src/app/components/admin-jobs/admin-jobs.html - 216 + 225 @@ -419,7 +423,7 @@ Elimina il lavoro apps/client/src/app/components/admin-jobs/admin-jobs.html - 224 + 233 @@ -435,7 +439,7 @@ Data apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 161 + 157 libs/ui/src/lib/account-balances/account-balances.component.html @@ -503,7 +507,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 44 + 40 @@ -511,7 +515,7 @@ Vuoi davvero eliminare questo buono? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 193 + 196 @@ -519,7 +523,7 @@ Vuoi davvero svuotare la cache? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 230 + 233 @@ -527,7 +531,7 @@ Imposta il messaggio di sistema: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 250 + 253 @@ -667,7 +671,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 89 + 108 @@ -723,7 +727,7 @@ apps/client/src/app/pages/public/public-page.html - 242 + 241 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -739,7 +743,7 @@ apps/client/src/app/components/header/header.component.ts - 297 + 298 apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html @@ -759,15 +763,15 @@ Ops! Token di sicurezza errato. apps/client/src/app/components/header/header.component.ts - 312 + 313 apps/client/src/app/components/user-account-access/user-account-access.component.ts - 154 + 152 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 193 + 191 @@ -775,7 +779,7 @@ Gestione delle attività apps/client/src/app/components/home-holdings/home-holdings.html - 67 + 64 @@ -891,7 +895,7 @@ Prestazioni lorde assolute apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 73 + 77 @@ -899,7 +903,7 @@ Prestazioni nette assolute apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 107 + 111 apps/client/src/app/pages/portfolio/analysis/analysis-page.html @@ -911,7 +915,7 @@ Prestazioni nette apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 123 + 127 apps/client/src/app/pages/portfolio/analysis/analysis-page.html @@ -923,7 +927,7 @@ Asset totali apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 149 + 153 @@ -931,7 +935,7 @@ Potere d’acquisto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 241 + 248 @@ -939,7 +943,7 @@ Patrimonio netto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 317 + 324 @@ -947,7 +951,7 @@ Prestazioni annualizzate apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 331 + 338 @@ -967,7 +971,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 396 + 399 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -975,7 +979,7 @@ apps/client/src/app/pages/public/public-page.html - 114 + 113 @@ -987,7 +991,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 407 + 410 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -999,7 +1003,7 @@ Tag apps/client/src/app/components/admin-settings/admin-settings.component.html - 201 + 218 libs/ui/src/lib/tags-selector/tags-selector.component.html @@ -1015,7 +1019,7 @@ Segnala un’anomalia dei dati apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 451 + 456 @@ -1043,7 +1047,7 @@ Mostra tutti libs/ui/src/lib/holdings-table/holdings-table.component.html - 216 + 212 @@ -1055,7 +1059,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 363 + 362 @@ -1063,11 +1067,11 @@ anno corrente apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 199 + 205 libs/ui/src/lib/assistant/assistant.component.ts - 375 + 374 @@ -1075,11 +1079,11 @@ 1 anno apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 203 + 209 libs/ui/src/lib/assistant/assistant.component.ts - 385 + 384 @@ -1087,11 +1091,11 @@ 5 anni apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 207 + 213 libs/ui/src/lib/assistant/assistant.component.ts - 409 + 408 @@ -1107,11 +1111,11 @@ Massimo apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 211 + 217 libs/ui/src/lib/assistant/assistant.component.ts - 415 + 414 @@ -1127,7 +1131,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 196 + 195 @@ -1219,7 +1223,7 @@ Vuoi davvero rimuovere questo metodo di accesso? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 282 + 279 @@ -1279,7 +1283,7 @@ Locale apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 512 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -1327,7 +1331,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 11 + 30 @@ -1375,11 +1379,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 375 + 381 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 66 + 85 apps/client/src/app/pages/accounts/accounts-page.html @@ -1419,7 +1423,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 316 + 317 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -1431,7 +1435,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 145 + 141 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -1611,7 +1615,7 @@ Poiché hai già effettuato l’accesso, non puoi accedere all’account demo. apps/client/src/app/pages/demo/demo-page.component.ts - 35 + 32 @@ -1657,6 +1661,10 @@ Overview Panoramica + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 7 + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 114 @@ -1675,11 +1683,11 @@ apps/client/src/app/pages/admin/admin-page.component.ts - 48 + 45 apps/client/src/app/pages/resources/resources-page.component.ts - 30 + 29 libs/common/src/lib/routes/routes.ts @@ -1695,7 +1703,7 @@ Mercati apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 378 + 381 apps/client/src/app/components/footer/footer.component.html @@ -1719,7 +1727,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 40 + 39 libs/common/src/lib/routes/routes.ts @@ -1819,7 +1827,7 @@ apps/client/src/app/pages/public/public-page.html - 151 + 150 @@ -1915,7 +1923,7 @@ Current week apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 191 + 197 @@ -1959,7 +1967,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 124 + 120 @@ -1971,7 +1979,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 189 + 185 libs/ui/src/lib/activities-table/activities-table.component.html @@ -1987,7 +1995,7 @@ Prezzo unitario apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 214 + 210 libs/ui/src/lib/activities-table/activities-table.component.html @@ -1999,7 +2007,7 @@ Nota apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 432 + 435 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -2007,7 +2015,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 275 + 271 @@ -2019,7 +2027,7 @@ apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 115 + 113 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -2039,11 +2047,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 342 + 348 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 75 + 94 apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -2063,7 +2071,7 @@ Importazione dei dati... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 175 + 174 @@ -2071,7 +2079,7 @@ L’importazione è stata completata apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 185 + 184 @@ -2143,7 +2151,7 @@ Continenti apps/client/src/app/pages/public/public-page.html - 132 + 131 @@ -2159,7 +2167,7 @@ Ghostfolio ti permette di tenere traccia della tua ricchezza. apps/client/src/app/pages/public/public-page.html - 238 + 237 @@ -2189,6 +2197,10 @@ apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html 88 + + libs/ui/src/lib/value/value.component.html + 18 + Resources @@ -2307,7 +2319,7 @@ Vuoi davvero eliminare questa attività? libs/ui/src/lib/activities-table/activities-table.component.ts - 288 + 292 @@ -2375,7 +2387,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 193 + 192 @@ -2391,7 +2403,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 195 + 194 @@ -2415,7 +2427,7 @@ apps/client/src/app/pages/public/public-page.html - 168 + 167 @@ -2423,7 +2435,7 @@ Latest activities apps/client/src/app/pages/public/public-page.html - 211 + 210 @@ -2443,7 +2455,7 @@ apps/client/src/app/pages/public/public-page.html - 186 + 185 @@ -2455,7 +2467,7 @@ apps/client/src/app/pages/public/public-page.html - 177 + 176 @@ -2487,7 +2499,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 53 + 72 @@ -2511,7 +2523,7 @@ Risparmio libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 397 + 424 @@ -2523,11 +2535,11 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 352 + 359 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 387 + 414 libs/ui/src/lib/i18n.ts @@ -2547,7 +2559,7 @@ Deposito libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 377 + 404 @@ -2555,7 +2567,7 @@ Mensile apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 91 + 90 @@ -2579,11 +2591,11 @@ Paura apps/client/src/app/components/home-market/home-market.component.ts - 42 + 41 apps/client/src/app/components/markets/markets.component.ts - 47 + 46 libs/ui/src/lib/i18n.ts @@ -2595,11 +2607,11 @@ Avidità apps/client/src/app/components/home-market/home-market.component.ts - 43 + 42 apps/client/src/app/components/markets/markets.component.ts - 48 + 47 libs/ui/src/lib/i18n.ts @@ -2611,7 +2623,7 @@ Filtra per... apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 385 + 383 @@ -2647,7 +2659,7 @@ Benchmark apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 376 + 379 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -2659,11 +2671,11 @@ Could not validate form apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 554 + 570 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 557 + 573 @@ -2687,7 +2699,7 @@ Escluso dall’analisi apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 267 + 274 @@ -2695,7 +2707,7 @@ Auto apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 70 + 69 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -2731,7 +2743,7 @@ Importo totale apps/client/src/app/components/investment-chart/investment-chart.component.ts - 143 + 146 @@ -2783,7 +2795,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 326 + 327 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -2791,7 +2803,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 290 + 286 libs/ui/src/lib/i18n.ts @@ -2807,7 +2819,7 @@ Simbolo apps/client/src/app/components/admin-jobs/admin-jobs.html - 68 + 77 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -2823,7 +2835,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 315 + 318 libs/ui/src/lib/i18n.ts @@ -2847,7 +2859,7 @@ Contanti apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 212 + 219 libs/ui/src/lib/i18n.ts @@ -2895,7 +2907,7 @@ Authentication apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 35 + 54 @@ -2959,7 +2971,7 @@ Fondo di emergenza apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 164 + 168 apps/client/src/app/pages/features/features-page.html @@ -2979,7 +2991,7 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 437 + 451 @@ -2991,7 +3003,7 @@ apps/client/src/app/pages/public/public-page.html - 196 + 195 libs/ui/src/lib/benchmark/benchmark.component.html @@ -2999,11 +3011,11 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 439 + 453 libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 452 + 467 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -3107,7 +3119,7 @@ Mappatura dei simboli apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 384 + 387 @@ -3131,7 +3143,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 365 + 372 apps/client/src/app/pages/features/features-page.html @@ -3139,11 +3151,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 202 + 198 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 76 + 75 libs/ui/src/lib/i18n.ts @@ -3171,7 +3183,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 342 + 343 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -3179,7 +3191,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 309 + 305 libs/ui/src/lib/i18n.ts @@ -3199,7 +3211,7 @@ Convalida dei dati... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 299 + 293 @@ -3215,7 +3227,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 71 + 67 @@ -3223,7 +3235,7 @@ Dati del mercato apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 398 + 403 libs/common/src/lib/routes/routes.ts @@ -3240,7 +3252,7 @@ Summary - Summario + Riepilogo apps/client/src/app/components/home-summary/home-summary.html 2 @@ -3275,7 +3287,7 @@ Annuale apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 92 + 91 @@ -3283,7 +3295,7 @@ Importa i dividendi apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 137 + 136 libs/ui/src/lib/activities-table/activities-table.component.html @@ -3299,7 +3311,7 @@ Valido fino a apps/client/src/app/components/admin-settings/admin-settings.component.html - 74 + 86 libs/ui/src/lib/membership-card/membership-card.component.html @@ -3338,6 +3350,14 @@ 22 + + No Activities + No Activities + + apps/client/src/app/components/admin-market-data/admin-market-data.component.ts + 145 + + Retirement Provision Fondo pensione @@ -3611,11 +3631,11 @@ Could not save asset profile apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 588 + 604 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 591 + 607 @@ -3635,7 +3655,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 88 + 92 @@ -3799,7 +3819,7 @@ Vuoi davvero eliminare tutte le tue attività? libs/ui/src/lib/activities-table/activities-table.component.ts - 278 + 282 @@ -3810,6 +3830,14 @@ 306 + + Explore + Explore + + apps/client/src/app/pages/resources/overview/resources-overview.component.html + 11 + + By By @@ -3831,7 +3859,7 @@ Current year apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 199 + 205 @@ -3847,11 +3875,11 @@ Url apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 419 + 422 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 550 + 553 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -3867,7 +3895,7 @@ Asset profile has been saved apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 578 + 594 @@ -3875,7 +3903,7 @@ Vuoi davvero eliminare questa piattaforma? apps/client/src/app/components/admin-platform/admin-platform.component.ts - 106 + 111 @@ -3883,7 +3911,7 @@ Piattaforme apps/client/src/app/components/admin-settings/admin-settings.component.html - 195 + 212 @@ -3891,7 +3919,7 @@ Aggiornamento del saldo di cassa apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 112 + 108 @@ -4071,7 +4099,7 @@ Passività apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 295 + 302 apps/client/src/app/pages/features/features-page.html @@ -4227,7 +4255,7 @@ Configurazione dello scraper apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 471 + 474 @@ -4471,7 +4499,7 @@ ETF senza paesi apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 136 + 135 @@ -4479,7 +4507,7 @@ ETF senza settori apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 141 + 140 @@ -4487,7 +4515,7 @@ Asset apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 233 @@ -4659,7 +4687,7 @@ Job ID apps/client/src/app/components/admin-jobs/admin-jobs.html - 34 + 43 @@ -4715,11 +4743,11 @@ Valute apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 131 + 130 apps/client/src/app/pages/public/public-page.html - 96 + 95 @@ -4767,11 +4795,11 @@ Could not parse scraper configuration apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 509 + 525 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 512 + 528 @@ -5433,7 +5461,7 @@ Commissione apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 262 + 258 libs/ui/src/lib/activities-table/activities-table.component.html @@ -5465,7 +5493,7 @@ Sei sicuro di voler eliminare questo tag? apps/client/src/app/components/admin-tag/admin-tag.component.ts - 103 + 108 @@ -5533,7 +5561,7 @@ Iscrizione apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 48 + 67 libs/common/src/lib/routes/routes.ts @@ -5565,7 +5593,7 @@ Profilo dell’asset apps/client/src/app/components/admin-jobs/admin-jobs.html - 52 + 61 @@ -5689,7 +5717,7 @@ Ops! Impossibile elaborare i dati storici. libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.ts - 262 + 284 @@ -5697,7 +5725,7 @@ Confermi di voler cancellare questo messaggio di sistema? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 206 + 209 @@ -5721,7 +5749,7 @@ Saldi di cassa apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 148 + 146 @@ -5741,7 +5769,7 @@ Vuoi veramente elimnare il saldo di questo conto? libs/ui/src/lib/account-balances/account-balances.component.ts - 120 + 113 @@ -5757,7 +5785,7 @@ L’attuale prezzo di mercato è apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 706 + 722 @@ -5765,7 +5793,7 @@ Prova apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 568 + 571 @@ -5853,11 +5881,11 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 81 + 80 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 97 + 96 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -5877,7 +5905,7 @@ Close Holding apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 442 + 447 @@ -5917,7 +5945,7 @@ Da inizio settimana libs/ui/src/lib/assistant/assistant.component.ts - 367 + 366 @@ -5925,11 +5953,11 @@ Settimana corrente apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 191 + 197 libs/ui/src/lib/assistant/assistant.component.ts - 367 + 366 @@ -5937,7 +5965,7 @@ Da inizio mese libs/ui/src/lib/assistant/assistant.component.ts - 371 + 370 @@ -5945,11 +5973,11 @@ Mese corrente apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 195 + 201 libs/ui/src/lib/assistant/assistant.component.ts - 371 + 370 @@ -5957,7 +5985,7 @@ Da inizio anno libs/ui/src/lib/assistant/assistant.component.ts - 375 + 374 @@ -5993,7 +6021,7 @@ anno apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 203 + 209 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -6005,7 +6033,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 385 + 384 @@ -6013,11 +6041,11 @@ anni apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 207 + 213 libs/ui/src/lib/assistant/assistant.component.ts - 409 + 408 @@ -6033,7 +6061,7 @@ Raccolta Dati apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 587 + 594 apps/client/src/app/components/admin-overview/admin-overview.html @@ -6045,7 +6073,7 @@ Generale apps/client/src/app/pages/faq/faq-page.component.ts - 49 + 41 @@ -6053,7 +6081,7 @@ Cloud apps/client/src/app/pages/faq/faq-page.component.ts - 54 + 46 libs/common/src/lib/routes/routes.ts @@ -6065,7 +6093,7 @@ Self-Hosting apps/client/src/app/pages/faq/faq-page.component.ts - 60 + 52 libs/common/src/lib/routes/routes.ts @@ -6106,7 +6134,7 @@ Attivo apps/client/src/app/components/home-holdings/home-holdings.component.ts - 64 + 63 @@ -6114,7 +6142,7 @@ Chiuso apps/client/src/app/components/home-holdings/home-holdings.component.ts - 65 + 64 @@ -6146,7 +6174,7 @@ Esegui il lavoro apps/client/src/app/components/admin-jobs/admin-jobs.html - 220 + 229 @@ -6154,7 +6182,7 @@ Priorità apps/client/src/app/components/admin-jobs/admin-jobs.html - 96 + 105 @@ -6210,7 +6238,7 @@ Confermi di voler chiudere il tuo account Ghostfolio? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 208 + 205 @@ -6258,7 +6286,7 @@ Include in apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 374 + 377 @@ -6266,7 +6294,7 @@ Ops! C’è stato un errore impostando l’autenticazione biometrica. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 336 + 333 @@ -6282,7 +6310,7 @@ Benchmarks apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 126 + 125 @@ -6330,7 +6358,7 @@ Vorresti perfezionare la tua strategia personale di investimento? apps/client/src/app/pages/public/public-page.html - 234 + 233 @@ -6662,7 +6690,7 @@ Errore apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 697 + 713 @@ -6714,7 +6742,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 592 + 599 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6746,7 +6774,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 345 + 341 apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html @@ -6754,7 +6782,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 46 + 47 libs/ui/src/lib/i18n.ts @@ -6766,7 +6794,7 @@ Chiudi apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 594 + 601 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6792,13 +6820,17 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 68 + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 127 + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html 107 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 347 + 343 libs/ui/src/lib/i18n.ts @@ -6810,7 +6842,7 @@ Role apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 14 + 33 @@ -6834,7 +6866,7 @@ Stato del Portfolio apps/client/src/app/components/admin-jobs/admin-jobs.html - 56 + 65 @@ -6901,6 +6933,14 @@ 42 + + has been copied to the clipboard + has been copied to the clipboard + + libs/ui/src/lib/value/value.component.ts + 180 + + From the beginning Dall’inizio @@ -7066,7 +7106,7 @@ Imposta API Key apps/client/src/app/components/admin-settings/admin-settings.component.html - 171 + 188 @@ -7102,7 +7142,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 45 + 44 libs/common/src/lib/routes/routes.ts @@ -7118,7 +7158,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 34 + 33 libs/common/src/lib/routes/routes.ts @@ -7172,7 +7212,7 @@ di apps/client/src/app/components/admin-settings/admin-settings.component.html - 135 + 152 @@ -7180,7 +7220,7 @@ richieste giornaliere apps/client/src/app/components/admin-settings/admin-settings.component.html - 137 + 154 @@ -7188,7 +7228,7 @@ Rimuovi API key apps/client/src/app/components/admin-settings/admin-settings.component.html - 161 + 178 @@ -7196,7 +7236,7 @@ Vuoi davvero eliminare l’API key? apps/client/src/app/components/admin-settings/admin-settings.component.ts - 127 + 133 @@ -7216,7 +7256,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 98 + 117 @@ -7288,7 +7328,7 @@ Salva apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 603 + 610 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7324,11 +7364,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 356 + 352 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 48 + 49 @@ -7340,7 +7380,7 @@ apps/client/src/app/components/user-account-access/user-account-access.component.ts - 260 + 257 @@ -7364,7 +7404,7 @@ Inserisci la tua API key di Ghostfolio. apps/client/src/app/components/admin-settings/admin-settings.component.ts - 146 + 152 @@ -7380,7 +7420,7 @@ L’AI prompt è stato copiato negli appunti apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 201 + 199 @@ -7396,7 +7436,7 @@ Pigro apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 225 + 231 @@ -7404,7 +7444,7 @@ Istantaneo apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 229 + 235 @@ -7412,7 +7452,7 @@ Prezzo di mercato predefinito apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 481 + 484 @@ -7420,7 +7460,7 @@ Modalità apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 518 + 521 @@ -7428,7 +7468,7 @@ Selettore apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 534 + 537 @@ -7436,7 +7476,7 @@ Intestazioni della richiesta HTTP apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 494 + 497 @@ -7444,7 +7484,7 @@ fine giornata apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 225 + 231 @@ -7452,7 +7492,7 @@ in tempo reale apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 229 + 235 @@ -7460,7 +7500,7 @@ Apri Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 202 + 200 @@ -7480,7 +7520,7 @@ libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 377 @@ -7492,7 +7532,7 @@ apps/client/src/app/components/home-overview/home-overview.component.ts - 55 + 54 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -7500,11 +7540,11 @@ libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 377 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 381 + 390 @@ -7608,11 +7648,11 @@ Token di sicurezza apps/client/src/app/components/admin-users/admin-users.component.ts - 236 + 235 apps/client/src/app/components/user-account-access/user-account-access.component.ts - 170 + 167 @@ -7620,7 +7660,7 @@ Vuoi davvero generare un nuovo token di sicurezza per questo utente? apps/client/src/app/components/admin-users/admin-users.component.ts - 241 + 240 @@ -7628,7 +7668,7 @@ Find account, holding or page... libs/ui/src/lib/assistant/assistant.component.ts - 151 + 115 @@ -7693,7 +7733,7 @@ () e gia in uso. apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 633 + 649 @@ -7701,7 +7741,7 @@ Si è verificato un errore durante l’aggiornamento di (). apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 641 + 657 @@ -7765,7 +7805,7 @@ qualcuno apps/client/src/app/pages/public/public-page.component.ts - 59 + 61 @@ -7797,7 +7837,7 @@ Vuoi davvero eliminare questo elemento? libs/ui/src/lib/benchmark/benchmark.component.ts - 144 + 139 @@ -7838,7 +7878,7 @@ L’account utente demo è stato sincronizzato. apps/client/src/app/components/admin-overview/admin-overview.component.ts - 274 + 277 @@ -7873,25 +7913,25 @@ 150 - + Fee Ratio - Rapporto tariffario + Fee Ratio apps/client/src/app/pages/i18n/i18n-page.html 152 - - The fees do exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - Le commissioni superano il ${thresholdMax}% del tuo investimento iniziale (${feeRatio}%) + + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 154 - - The fees do not exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - Le commissioni non superano il ${thresholdMax}% del tuo investimento iniziale (${feeRatio}%) + + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 158 @@ -8052,7 +8092,7 @@ Current month apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 195 + 201 @@ -8060,11 +8100,11 @@ nuovo apps/client/src/app/components/admin-settings/admin-settings.component.html - 67 + 79 apps/client/src/app/pages/admin/admin-page.component.ts - 56 + 53 @@ -8221,7 +8261,7 @@ Vuoi davvero generare un nuovo token di sicurezza? apps/client/src/app/components/user-account-access/user-account-access.component.ts - 175 + 172 @@ -8245,7 +8285,7 @@ Azioni apps/client/src/app/components/markets/markets.component.ts - 52 + 51 apps/client/src/app/pages/features/features-page.html @@ -8257,7 +8297,7 @@ criptovalute apps/client/src/app/components/markets/markets.component.ts - 53 + 52 apps/client/src/app/pages/features/features-page.html @@ -8277,7 +8317,7 @@ Gestisci profilo risorsa apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 466 + 471 @@ -8697,7 +8737,7 @@ Registration Date apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 26 + 45 diff --git a/apps/client/src/locales/messages.ko.xlf b/apps/client/src/locales/messages.ko.xlf index 67443706b..4f544e4aa 100644 --- a/apps/client/src/locales/messages.ko.xlf +++ b/apps/client/src/locales/messages.ko.xlf @@ -252,7 +252,7 @@ 유형 apps/client/src/app/components/admin-jobs/admin-jobs.html - 48 + 57 apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html @@ -336,7 +336,7 @@ 현금 잔액 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 148 + 146 @@ -360,7 +360,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 309 + 310 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -372,7 +372,7 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 46 + 58 apps/client/src/app/components/admin-tag/admin-tag.component.html @@ -388,7 +388,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 139 + 135 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -432,7 +432,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 316 + 317 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -444,7 +444,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 145 + 141 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -464,15 +464,15 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 205 + 201 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 208 + 204 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 211 + 207 libs/ui/src/lib/account-balances/account-balances.component.html @@ -520,11 +520,11 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 74 + 78 apps/client/src/app/components/admin-tag/admin-tag.component.html - 67 + 71 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -552,11 +552,15 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 85 + 89 apps/client/src/app/components/admin-tag/admin-tag.component.html - 78 + 82 + + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 22 libs/ui/src/lib/account-balances/account-balances.component.html @@ -580,7 +584,7 @@ 이 계정을 정말 삭제하시겠습니까? libs/ui/src/lib/accounts-table/accounts-table.component.ts - 150 + 148 @@ -588,7 +592,7 @@ 자산 프로필 apps/client/src/app/components/admin-jobs/admin-jobs.html - 52 + 61 @@ -596,11 +600,11 @@ 과거 시장 데이터 apps/client/src/app/components/admin-jobs/admin-jobs.html - 54 + 63 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 448 + 451 @@ -608,7 +612,7 @@ 데이터 소스 apps/client/src/app/components/admin-jobs/admin-jobs.html - 82 + 91 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -620,7 +624,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 155 + 151 libs/ui/src/lib/i18n.ts @@ -632,7 +636,7 @@ 시도 횟수 apps/client/src/app/components/admin-jobs/admin-jobs.html - 120 + 129 @@ -640,7 +644,7 @@ 생성됨 apps/client/src/app/components/admin-jobs/admin-jobs.html - 134 + 143 @@ -648,7 +652,7 @@ 완료됨 apps/client/src/app/components/admin-jobs/admin-jobs.html - 143 + 152 @@ -656,11 +660,11 @@ 상태 apps/client/src/app/components/admin-jobs/admin-jobs.html - 152 + 161 apps/client/src/app/components/admin-settings/admin-settings.component.html - 92 + 104 @@ -676,7 +680,7 @@ 작업 삭제 apps/client/src/app/components/admin-jobs/admin-jobs.html - 193 + 202 @@ -684,7 +688,7 @@ 데이터 보기 apps/client/src/app/components/admin-jobs/admin-jobs.html - 208 + 217 @@ -692,7 +696,7 @@ 스택트레이스 보기 apps/client/src/app/components/admin-jobs/admin-jobs.html - 216 + 225 @@ -700,7 +704,7 @@ 작업 삭제 apps/client/src/app/components/admin-jobs/admin-jobs.html - 224 + 233 @@ -716,7 +720,7 @@ 날짜 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 161 + 157 libs/ui/src/lib/account-balances/account-balances.component.html @@ -752,11 +756,11 @@ 통화 apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 131 + 130 apps/client/src/app/pages/public/public-page.html - 96 + 95 @@ -764,7 +768,7 @@ 국가 정보 없는 ETF apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 136 + 135 @@ -772,7 +776,7 @@ 섹터 정보 없는 ETF apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 141 + 140 @@ -788,7 +792,7 @@ 다음 기준으로 필터... apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 385 + 383 @@ -828,7 +832,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 44 + 40 @@ -880,7 +884,7 @@ 이런! 과거 데이터를 파싱할 수 없습니다. libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.ts - 262 + 284 @@ -912,7 +916,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 71 + 67 @@ -944,7 +948,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 53 + 72 @@ -956,7 +960,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 396 + 399 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -964,7 +968,7 @@ apps/client/src/app/pages/public/public-page.html - 114 + 113 @@ -976,7 +980,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 407 + 410 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -988,7 +992,7 @@ 심볼 매핑 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 384 + 387 @@ -1004,7 +1008,7 @@ 스크래퍼 설정 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 471 + 474 @@ -1012,7 +1016,7 @@ 메모 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 432 + 435 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1020,7 +1024,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 275 + 271 @@ -1064,7 +1068,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 124 + 120 @@ -1072,7 +1076,7 @@ 이 쿠폰을 정말 삭제하시겠습니까? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 193 + 196 @@ -1080,7 +1084,7 @@ 이 시스템 메시지를 정말 삭제하시겠습니까? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 206 + 209 @@ -1088,7 +1092,7 @@ 정말로 캐시를 플러시하시겠습니까? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 230 + 233 @@ -1096,7 +1100,7 @@ 시스템 메시지를 설정하십시오: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 250 + 253 @@ -1220,11 +1224,11 @@ 링크 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 419 + 422 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 550 + 553 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -1240,7 +1244,7 @@ Asset profile has been saved apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 578 + 594 @@ -1248,7 +1252,15 @@ 정말로 이 플랫폼을 삭제하시겠습니까? apps/client/src/app/components/admin-platform/admin-platform.component.ts - 106 + 111 + + + + Explore + Explore + + apps/client/src/app/pages/resources/overview/resources-overview.component.html + 11 @@ -1272,7 +1284,7 @@ 올해 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 199 + 205 @@ -1288,7 +1300,7 @@ 플랫폼 apps/client/src/app/components/admin-settings/admin-settings.component.html - 195 + 212 @@ -1296,7 +1308,7 @@ 태그 apps/client/src/app/components/admin-settings/admin-settings.component.html - 201 + 218 libs/ui/src/lib/tags-selector/tags-selector.component.html @@ -1320,7 +1332,7 @@ 이 태그를 정말로 삭제하시겠습니까? apps/client/src/app/components/admin-tag/admin-tag.component.ts - 103 + 108 @@ -1380,7 +1392,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 89 + 108 @@ -1412,11 +1424,11 @@ Could not validate form apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 554 + 570 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 557 + 573 @@ -1464,7 +1476,7 @@ 기준 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 376 + 379 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -1500,7 +1512,7 @@ apps/client/src/app/components/header/header.component.ts - 297 + 298 apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html @@ -1520,15 +1532,15 @@ 이런! 잘못된 보안 토큰. apps/client/src/app/components/header/header.component.ts - 312 + 313 apps/client/src/app/components/user-account-access/user-account-access.component.ts - 154 + 152 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 193 + 191 @@ -1536,7 +1548,7 @@ 활동 관리 apps/client/src/app/components/home-holdings/home-holdings.html - 67 + 64 @@ -1544,11 +1556,11 @@ 두려움 apps/client/src/app/components/home-market/home-market.component.ts - 42 + 41 apps/client/src/app/components/markets/markets.component.ts - 47 + 46 libs/ui/src/lib/i18n.ts @@ -1560,11 +1572,11 @@ 탐욕 apps/client/src/app/components/home-market/home-market.component.ts - 43 + 42 apps/client/src/app/components/markets/markets.component.ts - 48 + 47 libs/ui/src/lib/i18n.ts @@ -1668,7 +1680,7 @@ 이번주 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 191 + 197 @@ -1688,7 +1700,7 @@ 총액 apps/client/src/app/components/investment-chart/investment-chart.component.ts - 143 + 146 @@ -1800,7 +1812,7 @@ 절대 총 성과 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 73 + 77 @@ -1812,7 +1824,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 88 + 92 @@ -1820,7 +1832,7 @@ 절대 순 성과 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 107 + 111 apps/client/src/app/pages/portfolio/analysis/analysis-page.html @@ -1832,7 +1844,7 @@ 순 성과 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 123 + 127 apps/client/src/app/pages/portfolio/analysis/analysis-page.html @@ -1844,7 +1856,7 @@ 총자산 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 149 + 153 @@ -1852,7 +1864,7 @@ 자산 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 233 @@ -1860,7 +1872,7 @@ 매수 가능 금액 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 241 + 248 @@ -1868,7 +1880,7 @@ 분석에서 제외됨 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 267 + 274 @@ -1876,7 +1888,7 @@ 부채 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 295 + 302 apps/client/src/app/pages/features/features-page.html @@ -1888,7 +1900,7 @@ 순자산 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 317 + 324 @@ -1896,7 +1908,7 @@ 연환산 성과 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 331 + 338 @@ -1932,7 +1944,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 189 + 185 libs/ui/src/lib/activities-table/activities-table.component.html @@ -1948,7 +1960,7 @@ 데이터 결함 보고 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 451 + 456 @@ -2128,7 +2140,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 363 + 362 @@ -2136,11 +2148,11 @@ 연초 대비 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 199 + 205 libs/ui/src/lib/assistant/assistant.component.ts - 375 + 374 @@ -2148,11 +2160,11 @@ 1년 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 203 + 209 libs/ui/src/lib/assistant/assistant.component.ts - 385 + 384 @@ -2160,11 +2172,11 @@ 5년 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 207 + 213 libs/ui/src/lib/assistant/assistant.component.ts - 409 + 408 @@ -2180,11 +2192,11 @@ 맥스 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 211 + 217 libs/ui/src/lib/assistant/assistant.component.ts - 415 + 414 @@ -2284,7 +2296,7 @@ 자동 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 70 + 69 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -2296,7 +2308,7 @@ 이 로그인 방법을 정말로 제거하시겠습니까? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 282 + 279 @@ -2336,7 +2348,7 @@ 장소 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 512 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -2448,7 +2460,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 11 + 30 @@ -2480,7 +2492,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 195 + 194 @@ -2492,7 +2504,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 193 + 192 @@ -2508,7 +2520,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 196 + 195 @@ -2636,11 +2648,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 375 + 381 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 66 + 85 apps/client/src/app/pages/accounts/accounts-page.html @@ -2732,7 +2744,7 @@ 시장 데이터 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 398 + 403 libs/common/src/lib/routes/routes.ts @@ -2766,6 +2778,10 @@ Overview 개요 + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 7 + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 114 @@ -2784,11 +2800,11 @@ apps/client/src/app/pages/admin/admin-page.component.ts - 48 + 45 apps/client/src/app/pages/resources/resources-page.component.ts - 30 + 29 libs/common/src/lib/routes/routes.ts @@ -2912,11 +2928,11 @@ Could not parse scraper configuration apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 509 + 525 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 512 + 528 @@ -2932,7 +2948,7 @@ 이미 로그인되어 있으므로 데모 계정에 접근할 수 없습니다. apps/client/src/app/pages/demo/demo-page.component.ts - 35 + 32 @@ -3104,7 +3120,7 @@ apps/client/src/app/pages/public/public-page.html - 242 + 241 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -3156,7 +3172,7 @@ 시장 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 378 + 381 apps/client/src/app/components/footer/footer.component.html @@ -3180,7 +3196,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 40 + 39 libs/common/src/lib/routes/routes.ts @@ -3612,7 +3628,7 @@ 작업 ID apps/client/src/app/components/admin-jobs/admin-jobs.html - 34 + 43 @@ -3648,7 +3664,7 @@ apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 115 + 113 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -3668,11 +3684,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 342 + 348 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 75 + 94 apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -3692,7 +3708,7 @@ 정말로 이 활동을 삭제하시겠습니까? libs/ui/src/lib/activities-table/activities-table.component.ts - 278 + 282 @@ -3760,7 +3776,7 @@ 현금 잔액 업데이트 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 112 + 108 @@ -3768,7 +3784,7 @@ 단가 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 214 + 210 libs/ui/src/lib/activities-table/activities-table.component.html @@ -3796,7 +3812,7 @@ 배당금 가져오기 apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 137 + 136 libs/ui/src/lib/activities-table/activities-table.component.html @@ -3812,7 +3828,7 @@ 데이터 가져오는 중... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 175 + 174 @@ -3820,7 +3836,7 @@ 가져오기가 완료되었습니다. apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 185 + 184 @@ -3836,7 +3852,7 @@ 데이터 유효성을 검사하는 중... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 299 + 293 @@ -4008,7 +4024,7 @@ apps/client/src/app/pages/public/public-page.html - 151 + 150 @@ -4032,7 +4048,7 @@ apps/client/src/app/pages/public/public-page.html - 168 + 167 @@ -4040,7 +4056,7 @@ 최신 활동 apps/client/src/app/pages/public/public-page.html - 211 + 210 @@ -4052,7 +4068,7 @@ apps/client/src/app/pages/public/public-page.html - 177 + 176 @@ -4064,7 +4080,7 @@ apps/client/src/app/pages/public/public-page.html - 186 + 185 @@ -4124,7 +4140,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 365 + 372 apps/client/src/app/pages/features/features-page.html @@ -4132,11 +4148,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 202 + 198 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 76 + 75 libs/ui/src/lib/i18n.ts @@ -4156,7 +4172,7 @@ 보증금 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 377 + 404 @@ -4164,7 +4180,7 @@ 월간 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 91 + 90 @@ -4172,7 +4188,7 @@ 매년 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 92 + 91 @@ -4452,11 +4468,11 @@ Could not save asset profile apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 588 + 604 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 591 + 607 @@ -4480,7 +4496,7 @@ 대륙 apps/client/src/app/pages/public/public-page.html - 132 + 131 @@ -4496,7 +4512,7 @@ Ghostfolio는 귀하의 재산을 추적할 수 있도록 해줍니다. apps/client/src/app/pages/public/public-page.html - 238 + 237 @@ -4526,6 +4542,10 @@ apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html 88 + + libs/ui/src/lib/value/value.component.html + 18 + Personal Finance Tools @@ -4869,7 +4889,7 @@ 멤버십 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 48 + 67 libs/common/src/lib/routes/routes.ts @@ -4937,7 +4957,7 @@ 정말로 이 계정 잔액을 삭제하시겠습니까? libs/ui/src/lib/account-balances/account-balances.component.ts - 120 + 113 @@ -4993,7 +5013,7 @@ 정말로 이 활동을 삭제하시겠습니까? libs/ui/src/lib/activities-table/activities-table.component.ts - 288 + 292 @@ -5001,7 +5021,7 @@ 자산 프로필 apps/client/src/app/components/admin-settings/admin-settings.component.html - 106 + 123 libs/ui/src/lib/assistant/assistant.html @@ -5113,11 +5133,11 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 352 + 359 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 387 + 414 libs/ui/src/lib/i18n.ts @@ -5129,7 +5149,7 @@ 저금 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 397 + 424 @@ -5157,7 +5177,7 @@ 모두 표시 libs/ui/src/lib/holdings-table/holdings-table.component.html - 216 + 212 @@ -5201,7 +5221,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 326 + 327 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -5209,7 +5229,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 290 + 286 libs/ui/src/lib/i18n.ts @@ -5233,7 +5253,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 342 + 343 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -5241,7 +5261,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 309 + 305 libs/ui/src/lib/i18n.ts @@ -5285,7 +5305,7 @@ 비상자금 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 164 + 168 apps/client/src/app/pages/features/features-page.html @@ -5361,7 +5381,7 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 437 + 451 @@ -5372,6 +5392,14 @@ 27 + + No Activities + No Activities + + apps/client/src/app/components/admin-market-data/admin-market-data.component.ts + 145 + + Retirement Provision 퇴직금 @@ -5401,7 +5429,7 @@ 상징 apps/client/src/app/components/admin-jobs/admin-jobs.html - 68 + 77 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -5417,7 +5445,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 315 + 318 libs/ui/src/lib/i18n.ts @@ -5489,7 +5517,7 @@ 요금 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 262 + 258 libs/ui/src/lib/activities-table/activities-table.component.html @@ -5533,7 +5561,7 @@ 현금 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 212 + 219 libs/ui/src/lib/i18n.ts @@ -5581,7 +5609,7 @@ 입증 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 35 + 54 @@ -5725,7 +5753,7 @@ 유효기간 apps/client/src/app/components/admin-settings/admin-settings.component.html - 74 + 86 libs/ui/src/lib/membership-card/membership-card.component.html @@ -5749,7 +5777,7 @@ apps/client/src/app/pages/public/public-page.html - 196 + 195 libs/ui/src/lib/benchmark/benchmark.component.html @@ -5757,11 +5785,11 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 439 + 453 libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 452 + 467 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -5789,7 +5817,7 @@ 현재 시장가격은 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 706 + 722 @@ -5797,7 +5825,7 @@ 시험 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 568 + 571 @@ -5877,7 +5905,7 @@ 닫기 보유 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 442 + 447 @@ -5901,11 +5929,11 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 81 + 80 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 97 + 96 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -5941,7 +5969,7 @@ 연초 현재 libs/ui/src/lib/assistant/assistant.component.ts - 375 + 374 @@ -5949,7 +5977,7 @@ 이번주 현재까지 libs/ui/src/lib/assistant/assistant.component.ts - 367 + 366 @@ -5957,7 +5985,7 @@ 월간 누계 libs/ui/src/lib/assistant/assistant.component.ts - 371 + 370 @@ -5965,11 +5993,11 @@ MTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 195 + 201 libs/ui/src/lib/assistant/assistant.component.ts - 371 + 370 @@ -5977,11 +6005,11 @@ WTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 191 + 197 libs/ui/src/lib/assistant/assistant.component.ts - 367 + 366 @@ -6017,7 +6045,7 @@ 년도 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 203 + 209 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -6029,7 +6057,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 385 + 384 @@ -6037,11 +6065,11 @@ 연령 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 207 + 213 libs/ui/src/lib/assistant/assistant.component.ts - 409 + 408 @@ -6070,7 +6098,7 @@ 셀프 호스팅 apps/client/src/app/pages/faq/faq-page.component.ts - 60 + 52 libs/common/src/lib/routes/routes.ts @@ -6082,7 +6110,7 @@ 데이터 수집 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 587 + 594 apps/client/src/app/components/admin-overview/admin-overview.html @@ -6094,7 +6122,7 @@ 일반적인 apps/client/src/app/pages/faq/faq-page.component.ts - 49 + 41 @@ -6102,7 +6130,7 @@ 구름 apps/client/src/app/pages/faq/faq-page.component.ts - 54 + 46 libs/common/src/lib/routes/routes.ts @@ -6130,7 +6158,7 @@ 닫은 apps/client/src/app/components/home-holdings/home-holdings.component.ts - 65 + 64 @@ -6138,7 +6166,7 @@ 활동적인 apps/client/src/app/components/home-holdings/home-holdings.component.ts - 64 + 63 @@ -6170,7 +6198,7 @@ 작업 실행 apps/client/src/app/components/admin-jobs/admin-jobs.html - 220 + 229 @@ -6186,7 +6214,7 @@ 우선 사항 apps/client/src/app/components/admin-jobs/admin-jobs.html - 96 + 105 @@ -6242,7 +6270,7 @@ 정말로 Ghostfolio 계정을 폐쇄하시겠습니까? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 208 + 205 @@ -6282,7 +6310,7 @@ 포함 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 374 + 377 @@ -6290,7 +6318,7 @@ 이런! 생체 인증을 설정하는 중에 오류가 발생했습니다. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 336 + 333 @@ -6330,7 +6358,7 @@ 벤치마크 apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 126 + 125 @@ -6354,7 +6382,7 @@ 개인 투자 전략개선하시겠습니까? apps/client/src/app/pages/public/public-page.html - 234 + 233 @@ -6686,7 +6714,7 @@ 오류 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 697 + 713 @@ -6698,7 +6726,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 592 + 599 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6730,7 +6758,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 345 + 341 apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html @@ -6738,7 +6766,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 46 + 47 libs/ui/src/lib/i18n.ts @@ -6750,7 +6778,7 @@ 역할 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 14 + 33 @@ -6782,7 +6810,7 @@ 닫다 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 594 + 601 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6808,13 +6836,17 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 68 + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 127 + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html 107 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 347 + 343 libs/ui/src/lib/i18n.ts @@ -6874,7 +6906,7 @@ 포트폴리오 스냅샷 apps/client/src/app/components/admin-jobs/admin-jobs.html - 56 + 65 @@ -6933,6 +6965,14 @@ 42 + + has been copied to the clipboard + has been copied to the clipboard + + libs/ui/src/lib/value/value.component.ts + 180 + + offers a free plan 은(는) 무료 요금제를 제공합니다 @@ -7090,7 +7130,7 @@ API 키 설정 apps/client/src/app/components/admin-settings/admin-settings.component.html - 171 + 188 @@ -7126,7 +7166,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 45 + 44 libs/common/src/lib/routes/routes.ts @@ -7155,7 +7195,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 34 + 33 libs/common/src/lib/routes/routes.ts @@ -7204,7 +7244,7 @@ ~의 apps/client/src/app/components/admin-settings/admin-settings.component.html - 135 + 152 @@ -7212,7 +7252,7 @@ API 키를 정말로 삭제하시겠습니까? apps/client/src/app/components/admin-settings/admin-settings.component.ts - 127 + 133 @@ -7220,7 +7260,7 @@ API 키 제거 apps/client/src/app/components/admin-settings/admin-settings.component.html - 161 + 178 @@ -7228,7 +7268,7 @@ 일일 요청 apps/client/src/app/components/admin-settings/admin-settings.component.html - 137 + 154 @@ -7256,7 +7296,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 98 + 117 @@ -7312,7 +7352,7 @@ 구하다 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 603 + 610 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7348,11 +7388,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 356 + 352 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 48 + 49 @@ -7380,7 +7420,7 @@ apps/client/src/app/components/user-account-access/user-account-access.component.ts - 260 + 257 @@ -7388,7 +7428,7 @@ Ghostfolio API 키를 입력하세요. apps/client/src/app/components/admin-settings/admin-settings.component.ts - 146 + 152 @@ -7404,7 +7444,7 @@ AI 프롬프트가 클립보드에 복사되었습니다. apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 201 + 199 @@ -7420,7 +7460,7 @@ 방법 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 518 + 521 @@ -7428,7 +7468,7 @@ 기본 시장 가격 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 481 + 484 @@ -7436,7 +7476,7 @@ 선택자 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 534 + 537 @@ -7444,7 +7484,7 @@ 즉각적인 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 229 + 235 @@ -7452,7 +7492,7 @@ 게으른 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 225 + 231 @@ -7460,7 +7500,7 @@ HTTP 요청 헤더 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 494 + 497 @@ -7468,7 +7508,7 @@ 실시간 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 229 + 235 @@ -7476,7 +7516,7 @@ 하루의 끝 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 225 + 231 @@ -7484,7 +7524,7 @@ 오픈 Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 202 + 200 @@ -7504,7 +7544,7 @@ libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 377 @@ -7516,7 +7556,7 @@ apps/client/src/app/components/home-overview/home-overview.component.ts - 55 + 54 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -7524,11 +7564,11 @@ libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 377 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 381 + 390 @@ -7632,7 +7672,7 @@ 정말로 이 사용자에 대한 새 보안 토큰을 생성하시겠습니까? apps/client/src/app/components/admin-users/admin-users.component.ts - 241 + 240 @@ -7640,7 +7680,7 @@ 계정, 보유 또는 페이지 찾기... libs/ui/src/lib/assistant/assistant.component.ts - 151 + 115 @@ -7648,11 +7688,11 @@ 보안 토큰 apps/client/src/app/components/admin-users/admin-users.component.ts - 236 + 235 apps/client/src/app/components/user-account-access/user-account-access.component.ts - 170 + 167 @@ -7717,7 +7757,7 @@ ()은(는) 이미 사용 중입니다. apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 633 + 649 @@ -7725,7 +7765,7 @@ ()로 업데이트하는 동안 오류가 발생했습니다. apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 641 + 657 @@ -7765,7 +7805,7 @@ 누구 apps/client/src/app/pages/public/public-page.component.ts - 59 + 61 @@ -7797,7 +7837,7 @@ 이 항목을 정말로 삭제하시겠습니까? libs/ui/src/lib/benchmark/benchmark.component.ts - 144 + 139 @@ -7846,7 +7886,7 @@ 데모 사용자 계정이 동기화되었습니다. apps/client/src/app/components/admin-overview/admin-overview.component.ts - 274 + 277 @@ -7873,25 +7913,25 @@ 150 - + Fee Ratio - 수수료 비율 + Fee Ratio apps/client/src/app/pages/i18n/i18n-page.html 152 - - The fees do exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - 수수료가 초기 투자금(${feeRatio}%)의 ${thresholdMax}%를 초과합니다. + + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 154 - - The fees do not exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - 수수료는 초기 투자금의 ${thresholdMax}%(${feeRatio}%)를 초과하지 않습니다. + + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 158 @@ -8052,7 +8092,7 @@ 이번 달 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 195 + 201 @@ -8060,11 +8100,11 @@ 새로운 apps/client/src/app/components/admin-settings/admin-settings.component.html - 67 + 79 apps/client/src/app/pages/admin/admin-page.component.ts - 56 + 53 @@ -8237,7 +8277,7 @@ 정말로 새로운 보안 토큰을 생성하시겠습니까? apps/client/src/app/components/user-account-access/user-account-access.component.ts - 175 + 172 @@ -8245,7 +8285,7 @@ 암호화폐 apps/client/src/app/components/markets/markets.component.ts - 53 + 52 apps/client/src/app/pages/features/features-page.html @@ -8257,7 +8297,7 @@ 주식 apps/client/src/app/components/markets/markets.component.ts - 52 + 51 apps/client/src/app/pages/features/features-page.html @@ -8277,7 +8317,7 @@ 자산 프로필 관리 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 466 + 471 @@ -8697,7 +8737,7 @@ 등록일 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 26 + 45 diff --git a/apps/client/src/locales/messages.nl.xlf b/apps/client/src/locales/messages.nl.xlf index d7d0b71e8..039969da0 100644 --- a/apps/client/src/locales/messages.nl.xlf +++ b/apps/client/src/locales/messages.nl.xlf @@ -39,7 +39,7 @@ please - please + alsjeblieft apps/client/src/app/pages/pricing/pricing-page.html 333 @@ -50,7 +50,7 @@ Type apps/client/src/app/components/admin-jobs/admin-jobs.html - 48 + 57 apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html @@ -83,7 +83,7 @@ with - with + met apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 87 @@ -106,7 +106,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 309 + 310 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -118,7 +118,7 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 46 + 58 apps/client/src/app/components/admin-tag/admin-tag.component.html @@ -134,7 +134,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 139 + 135 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -178,15 +178,15 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 205 + 201 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 208 + 204 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 211 + 207 libs/ui/src/lib/account-balances/account-balances.component.html @@ -234,11 +234,11 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 74 + 78 apps/client/src/app/components/admin-tag/admin-tag.component.html - 67 + 71 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -266,11 +266,15 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 85 + 89 apps/client/src/app/components/admin-tag/admin-tag.component.html - 78 + 82 + + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 22 libs/ui/src/lib/account-balances/account-balances.component.html @@ -294,7 +298,7 @@ Wil je deze rekening echt verwijderen? libs/ui/src/lib/accounts-table/accounts-table.component.ts - 150 + 148 @@ -302,7 +306,7 @@ Taken verwijderen apps/client/src/app/components/admin-jobs/admin-jobs.html - 193 + 202 @@ -310,7 +314,7 @@ Gegevensbron apps/client/src/app/components/admin-jobs/admin-jobs.html - 82 + 91 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -322,7 +326,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 155 + 151 libs/ui/src/lib/i18n.ts @@ -334,7 +338,7 @@ Pogingen apps/client/src/app/components/admin-jobs/admin-jobs.html - 120 + 129 @@ -342,7 +346,7 @@ Aangemaakt apps/client/src/app/components/admin-jobs/admin-jobs.html - 134 + 143 @@ -350,7 +354,7 @@ Voltooid apps/client/src/app/components/admin-jobs/admin-jobs.html - 143 + 152 @@ -358,16 +362,16 @@ Status apps/client/src/app/components/admin-jobs/admin-jobs.html - 152 + 161 apps/client/src/app/components/admin-settings/admin-settings.component.html - 92 + 104 and is driven by the efforts of its contributors - and is driven by the efforts of its contributors + en wordt gedreven door de inspanningen van zijn bijdragers apps/client/src/app/pages/about/overview/about-overview-page.html 49 @@ -378,7 +382,7 @@ Activa Profiel apps/client/src/app/components/admin-settings/admin-settings.component.html - 106 + 123 libs/ui/src/lib/assistant/assistant.html @@ -390,11 +394,11 @@ Historische marktgegevens apps/client/src/app/components/admin-jobs/admin-jobs.html - 54 + 63 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 448 + 451 @@ -402,7 +406,7 @@ Bekijk gegevens apps/client/src/app/components/admin-jobs/admin-jobs.html - 208 + 217 @@ -410,7 +414,7 @@ Bekijk Stacktrace apps/client/src/app/components/admin-jobs/admin-jobs.html - 216 + 225 @@ -418,7 +422,7 @@ Taak verwijderen apps/client/src/app/components/admin-jobs/admin-jobs.html - 224 + 233 @@ -434,7 +438,7 @@ Datum apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 161 + 157 libs/ui/src/lib/account-balances/account-balances.component.html @@ -502,7 +506,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 44 + 40 @@ -510,7 +514,7 @@ Wil je deze coupon echt verwijderen? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 193 + 196 @@ -518,7 +522,7 @@ Wil je echt de cache legen? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 230 + 233 @@ -526,7 +530,7 @@ Stel je systeemboodschap in: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 250 + 253 @@ -651,7 +655,7 @@ No auto-renewal on membership. - No auto-renewal on membership. + Het lidmaatschap wordt niet automatisch verlengd. apps/client/src/app/components/user-account-membership/user-account-membership.html 74 @@ -666,7 +670,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 89 + 108 @@ -722,7 +726,7 @@ apps/client/src/app/pages/public/public-page.html - 242 + 241 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -738,7 +742,7 @@ apps/client/src/app/components/header/header.component.ts - 297 + 298 apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html @@ -758,15 +762,15 @@ Oeps! Onjuiste beveiligingstoken. apps/client/src/app/components/header/header.component.ts - 312 + 313 apps/client/src/app/components/user-account-access/user-account-access.component.ts - 154 + 152 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 193 + 191 @@ -774,7 +778,7 @@ Activiteiten beheren apps/client/src/app/components/home-holdings/home-holdings.html - 67 + 64 @@ -890,7 +894,7 @@ Absoluut bruto rendement apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 73 + 77 @@ -898,7 +902,7 @@ Absoluut netto rendement apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 107 + 111 apps/client/src/app/pages/portfolio/analysis/analysis-page.html @@ -910,7 +914,7 @@ Netto rendement apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 123 + 127 apps/client/src/app/pages/portfolio/analysis/analysis-page.html @@ -922,7 +926,7 @@ Totaal Activa apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 149 + 153 @@ -930,7 +934,7 @@ Koopkracht apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 241 + 248 @@ -938,7 +942,7 @@ Netto waarde apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 317 + 324 @@ -946,7 +950,7 @@ Rendement per jaar apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 331 + 338 @@ -966,7 +970,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 396 + 399 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -974,7 +978,7 @@ apps/client/src/app/pages/public/public-page.html - 114 + 113 @@ -986,7 +990,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 407 + 410 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -998,7 +1002,7 @@ Tags apps/client/src/app/components/admin-settings/admin-settings.component.html - 201 + 218 libs/ui/src/lib/tags-selector/tags-selector.component.html @@ -1014,7 +1018,7 @@ Gegevensstoring melden apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 451 + 456 @@ -1042,7 +1046,7 @@ Toon alle libs/ui/src/lib/holdings-table/holdings-table.component.html - 216 + 212 @@ -1054,7 +1058,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 363 + 362 @@ -1062,11 +1066,11 @@ YTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 199 + 205 libs/ui/src/lib/assistant/assistant.component.ts - 375 + 374 @@ -1074,11 +1078,11 @@ 1J apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 203 + 209 libs/ui/src/lib/assistant/assistant.component.ts - 385 + 384 @@ -1086,16 +1090,16 @@ 5J apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 207 + 213 libs/ui/src/lib/assistant/assistant.component.ts - 409 + 408 Performance with currency effect - Performance with currency effect + Prestaties met valuta-effect apps/client/src/app/pages/portfolio/analysis/analysis-page.html 135 @@ -1106,11 +1110,11 @@ Max apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 211 + 217 libs/ui/src/lib/assistant/assistant.component.ts - 415 + 414 @@ -1126,7 +1130,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 196 + 195 @@ -1218,7 +1222,7 @@ Wil je deze aanmeldingsmethode echt verwijderen? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 282 + 279 @@ -1278,7 +1282,7 @@ Locatie apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 512 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -1326,7 +1330,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 11 + 30 @@ -1374,11 +1378,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 375 + 381 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 66 + 85 apps/client/src/app/pages/accounts/accounts-page.html @@ -1418,7 +1422,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 316 + 317 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -1430,7 +1434,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 145 + 141 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -1610,7 +1614,7 @@ Aangezien je al ingelogd bent, heb je geen toegang tot de demo-account. apps/client/src/app/pages/demo/demo-page.component.ts - 35 + 32 @@ -1656,6 +1660,10 @@ Overview Overzicht + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 7 + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 114 @@ -1674,11 +1682,11 @@ apps/client/src/app/pages/admin/admin-page.component.ts - 48 + 45 apps/client/src/app/pages/resources/resources-page.component.ts - 30 + 29 libs/common/src/lib/routes/routes.ts @@ -1694,7 +1702,7 @@ Markten apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 378 + 381 apps/client/src/app/components/footer/footer.component.html @@ -1718,7 +1726,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 40 + 39 libs/common/src/lib/routes/routes.ts @@ -1818,7 +1826,7 @@ apps/client/src/app/pages/public/public-page.html - 151 + 150 @@ -1911,10 +1919,10 @@ Current week - Current week + Huidige week apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 191 + 197 @@ -1958,7 +1966,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 124 + 120 @@ -1970,7 +1978,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 189 + 185 libs/ui/src/lib/activities-table/activities-table.component.html @@ -1986,7 +1994,7 @@ Prijs per eenheid apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 214 + 210 libs/ui/src/lib/activities-table/activities-table.component.html @@ -1998,7 +2006,7 @@ Opmerking apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 432 + 435 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -2006,7 +2014,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 275 + 271 @@ -2018,7 +2026,7 @@ apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 115 + 113 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -2038,11 +2046,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 342 + 348 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 75 + 94 apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -2062,7 +2070,7 @@ Gegevens importeren... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 175 + 174 @@ -2070,12 +2078,12 @@ Importeren is voltooid apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 185 + 184 or start a discussion at - or start a discussion at + of start een discussie op apps/client/src/app/pages/about/overview/about-overview-page.html 94 @@ -2142,12 +2150,12 @@ Continenten apps/client/src/app/pages/public/public-page.html - 132 + 131 Sustainable retirement income - Sustainable retirement income + Duurzaam pensioeninkomen apps/client/src/app/pages/portfolio/fire/fire-page.html 41 @@ -2158,7 +2166,7 @@ Ghostfolio stelt je in staat om je vermogen bij te houden. apps/client/src/app/pages/public/public-page.html - 238 + 237 @@ -2188,6 +2196,10 @@ apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html 88 + + libs/ui/src/lib/value/value.component.html + 18 + Resources @@ -2306,7 +2318,7 @@ Wil je deze activiteit echt verwijderen? libs/ui/src/lib/activities-table/activities-table.component.ts - 288 + 292 @@ -2319,7 +2331,7 @@ contact us - contact us + contacteer ons apps/client/src/app/pages/pricing/pricing-page.html 336 @@ -2374,7 +2386,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 193 + 192 @@ -2390,12 +2402,12 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 195 + 194 Exclude from Analysis - Exclude from Analysis + Uitsluiten van analyse apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html 90 @@ -2414,15 +2426,15 @@ apps/client/src/app/pages/public/public-page.html - 168 + 167 Latest activities - Latest activities + Laatste activiteiten apps/client/src/app/pages/public/public-page.html - 211 + 210 @@ -2442,7 +2454,7 @@ apps/client/src/app/pages/public/public-page.html - 186 + 185 @@ -2454,7 +2466,7 @@ apps/client/src/app/pages/public/public-page.html - 177 + 176 @@ -2486,7 +2498,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 53 + 72 @@ -2510,7 +2522,7 @@ Besparingen libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 397 + 424 @@ -2522,11 +2534,11 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 352 + 359 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 387 + 414 libs/ui/src/lib/i18n.ts @@ -2535,7 +2547,7 @@ annual interest rate - annual interest rate + jaarlijkse rente apps/client/src/app/pages/portfolio/fire/fire-page.html 185 @@ -2546,7 +2558,7 @@ Storting libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 377 + 404 @@ -2554,7 +2566,7 @@ Maandelijks apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 91 + 90 @@ -2578,11 +2590,11 @@ Angst apps/client/src/app/components/home-market/home-market.component.ts - 42 + 41 apps/client/src/app/components/markets/markets.component.ts - 47 + 46 libs/ui/src/lib/i18n.ts @@ -2594,11 +2606,11 @@ Hebzucht apps/client/src/app/components/home-market/home-market.component.ts - 43 + 42 apps/client/src/app/components/markets/markets.component.ts - 48 + 47 libs/ui/src/lib/i18n.ts @@ -2610,7 +2622,7 @@ Filter op... apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 385 + 383 @@ -2646,7 +2658,7 @@ Benchmark apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 376 + 379 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -2655,14 +2667,14 @@ Could not validate form - Could not validate form + Het formulier kon niet worden gevalideerd. apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 554 + 570 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 557 + 573 @@ -2686,7 +2698,7 @@ Uitgesloten van analyse apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 267 + 274 @@ -2694,7 +2706,7 @@ Automatisch apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 70 + 69 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -2730,7 +2742,7 @@ Totaalbedrag apps/client/src/app/components/investment-chart/investment-chart.component.ts - 143 + 146 @@ -2782,7 +2794,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 326 + 327 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -2790,7 +2802,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 290 + 286 libs/ui/src/lib/i18n.ts @@ -2806,7 +2818,7 @@ Symbool apps/client/src/app/components/admin-jobs/admin-jobs.html - 68 + 77 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -2822,7 +2834,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 315 + 318 libs/ui/src/lib/i18n.ts @@ -2846,7 +2858,7 @@ Contant geld apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 212 + 219 libs/ui/src/lib/i18n.ts @@ -2891,10 +2903,10 @@ Authentication - Authentication + Authenticatie apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 35 + 54 @@ -2958,7 +2970,7 @@ Noodfonds apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 164 + 168 apps/client/src/app/pages/features/features-page.html @@ -2978,7 +2990,7 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 437 + 451 @@ -2990,7 +3002,7 @@ apps/client/src/app/pages/public/public-page.html - 196 + 195 libs/ui/src/lib/benchmark/benchmark.component.html @@ -2998,11 +3010,11 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 439 + 453 libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 452 + 467 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -3043,7 +3055,7 @@ If you retire today, you would be able to withdraw - If you retire today, you would be able to withdraw + Als u vandaag met pensioen gaat, kunt u apps/client/src/app/pages/portfolio/fire/fire-page.html 68 @@ -3106,12 +3118,12 @@ Symbool toewijzen apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 384 + 387 Looking for a student discount? - Looking for a student discount? + Op zoek naar studentenkorting? apps/client/src/app/pages/pricing/pricing-page.html 342 @@ -3130,7 +3142,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 365 + 372 apps/client/src/app/pages/features/features-page.html @@ -3138,11 +3150,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 202 + 198 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 76 + 75 libs/ui/src/lib/i18n.ts @@ -3170,7 +3182,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 342 + 343 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -3178,7 +3190,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 309 + 305 libs/ui/src/lib/i18n.ts @@ -3198,7 +3210,7 @@ Gegevens valideren... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 299 + 293 @@ -3214,7 +3226,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 71 + 67 @@ -3222,7 +3234,7 @@ Marktgegevens apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 398 + 403 libs/common/src/lib/routes/routes.ts @@ -3274,7 +3286,7 @@ Jaarlijks apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 92 + 91 @@ -3282,7 +3294,7 @@ Importeer dividenden apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 137 + 136 libs/ui/src/lib/activities-table/activities-table.component.html @@ -3298,7 +3310,7 @@ Geldig tot apps/client/src/app/components/admin-settings/admin-settings.component.html - 74 + 86 libs/ui/src/lib/membership-card/membership-card.component.html @@ -3337,6 +3349,14 @@ 22 + + No Activities + Geen activiteiten + + apps/client/src/app/components/admin-market-data/admin-market-data.component.ts + 145 + + Retirement Provision Pensioen @@ -3347,7 +3367,7 @@ Everything in Basic, plus - Everything in Basic, plus + Alles van Basic, plus apps/client/src/app/pages/pricing/pricing-page.html 199 @@ -3607,14 +3627,14 @@ Could not save asset profile - Could not save asset profile + Kon het assetprofiel niet opslaan apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 588 + 604 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 591 + 607 @@ -3634,7 +3654,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 88 + 92 @@ -3798,7 +3818,7 @@ Weet je zeker dat je alle activiteiten wilt verwijderen? libs/ui/src/lib/activities-table/activities-table.component.ts - 278 + 282 @@ -3809,9 +3829,17 @@ 306 + + Explore + Explore + + apps/client/src/app/pages/resources/overview/resources-overview.component.html + 11 + + By - By + Tegen apps/client/src/app/pages/portfolio/fire/fire-page.html 139 @@ -3827,10 +3855,10 @@ Current year - Current year + Huidig jaar apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 199 + 205 @@ -3846,11 +3874,11 @@ Url apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 419 + 422 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 550 + 553 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -3863,10 +3891,10 @@ Asset profile has been saved - Asset profile has been saved + Het activaprofiel is opgeslagen. apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 578 + 594 @@ -3874,7 +3902,7 @@ Wil je dit platform echt verwijderen? apps/client/src/app/components/admin-platform/admin-platform.component.ts - 106 + 111 @@ -3882,7 +3910,7 @@ Platforms apps/client/src/app/components/admin-settings/admin-settings.component.html - 195 + 212 @@ -3890,7 +3918,7 @@ Saldo bijwerken apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 112 + 108 @@ -4055,7 +4083,7 @@ View Details - View Details + Bekijk details apps/client/src/app/components/admin-users/admin-users.html 225 @@ -4070,7 +4098,7 @@ Verplichtingen apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 295 + 302 apps/client/src/app/pages/features/features-page.html @@ -4191,7 +4219,7 @@ per week - per week + per week apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 130 @@ -4215,7 +4243,7 @@ and we share aggregated key metrics of the platform’s performance - and we share aggregated key metrics of the platform’s performance + en we delen geaggregeerde belangrijke prestatiegegevens van het platform apps/client/src/app/pages/about/overview/about-overview-page.html 32 @@ -4226,7 +4254,7 @@ Scraper instellingen apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 471 + 474 @@ -4259,7 +4287,7 @@ Website of Thomas Kaul - Website of Thomas Kaul + Website van Thomas Kaul apps/client/src/app/pages/about/overview/about-overview-page.html 44 @@ -4439,7 +4467,7 @@ Sign in with OpenID Connect - Sign in with OpenID Connect + Meld je aan met OpenID Connect apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html 55 @@ -4470,7 +4498,7 @@ ETF’s zonder Landen apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 136 + 135 @@ -4478,7 +4506,7 @@ ETF’s zonder Sectoren apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 141 + 140 @@ -4486,7 +4514,7 @@ Assets apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 233 @@ -4531,7 +4559,7 @@ The source code is fully available as open source software (OSS) under the AGPL-3.0 license - The source code is fully available as open source software (OSS) under the AGPL-3.0 license + De broncode is volledig beschikbaar als open source software (OSS) onder de AGPL-3.0-licentie apps/client/src/app/pages/about/overview/about-overview-page.html 16 @@ -4603,7 +4631,7 @@ this is projected to increase to - this is projected to increase to + zal dit naar verwachting stijgen tot apps/client/src/app/pages/portfolio/fire/fire-page.html 147 @@ -4655,10 +4683,10 @@ Job ID - Job ID + Opdracht ID apps/client/src/app/components/admin-jobs/admin-jobs.html - 34 + 43 @@ -4714,11 +4742,11 @@ Valuta apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 131 + 130 apps/client/src/app/pages/public/public-page.html - 96 + 95 @@ -4739,7 +4767,7 @@ for - for + voor apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 128 @@ -4763,14 +4791,14 @@ Could not parse scraper configuration - Could not parse scraper configuration + De scraperconfiguratie kon niet worden geparseerd apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 509 + 525 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 512 + 528 @@ -4807,7 +4835,7 @@ Edit access - Edit access + Toegang bewerken apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 11 @@ -4879,7 +4907,7 @@ Get access to 80’000+ tickers from over 50 exchanges - Get access to 80’000+ tickers from over 50 exchanges + Krijg toegang tot meer dan 80.000+ tickers van meer dan 50 beurzen apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 84 @@ -5063,7 +5091,7 @@ less than - less than + minder dan apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 129 @@ -5353,7 +5381,7 @@ Ghostfolio Status - Ghostfolio Status + Ghostfolio Status apps/client/src/app/pages/about/overview/about-overview-page.html 62 @@ -5361,7 +5389,7 @@ with your university e-mail address - with your university e-mail address + met uw universitaire e-mailadres apps/client/src/app/pages/pricing/pricing-page.html 348 @@ -5381,7 +5409,7 @@ and a safe withdrawal rate (SWR) of - and a safe withdrawal rate (SWR) of + en een veilige opnameratio (SWR) van apps/client/src/app/pages/portfolio/fire/fire-page.html 108 @@ -5432,7 +5460,7 @@ Kosten apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 262 + 258 libs/ui/src/lib/activities-table/activities-table.component.html @@ -5464,7 +5492,7 @@ Weet u zetker dat u dit label wilt verwijderen? apps/client/src/app/components/admin-tag/admin-tag.component.ts - 103 + 108 @@ -5532,7 +5560,7 @@ Lidmaatschap apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 48 + 67 libs/common/src/lib/routes/routes.ts @@ -5545,7 +5573,7 @@ Request it - Request it + Aanvragen apps/client/src/app/pages/pricing/pricing-page.html 344 @@ -5564,7 +5592,7 @@ Bezittingen Profiel apps/client/src/app/components/admin-jobs/admin-jobs.html - 52 + 61 @@ -5601,7 +5629,7 @@ , - , + , apps/client/src/app/pages/portfolio/fire/fire-page.html 145 @@ -5617,7 +5645,7 @@ per month - per month + per maand apps/client/src/app/pages/portfolio/fire/fire-page.html 94 @@ -5688,7 +5716,7 @@ Oeps! Ophalen van historische data is mislukt. libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.ts - 262 + 284 @@ -5696,7 +5724,7 @@ Wilt u dit systeembericht echt verwijderen? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 206 + 209 @@ -5720,7 +5748,7 @@ Contant Saldo apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 148 + 146 @@ -5740,7 +5768,7 @@ Wilt u dit rekeningsaldo echt verwijderen? libs/ui/src/lib/account-balances/account-balances.component.ts - 120 + 113 @@ -5756,7 +5784,7 @@ De huidige markt waarde is apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 706 + 722 @@ -5764,7 +5792,7 @@ Test apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 568 + 571 @@ -5809,7 +5837,7 @@ Argentina - Argentina + Argentinië libs/ui/src/lib/i18n.ts 78 @@ -5852,11 +5880,11 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 81 + 80 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 97 + 96 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -5865,7 +5893,7 @@ here - here + hier apps/client/src/app/pages/pricing/pricing-page.html 347 @@ -5873,10 +5901,10 @@ Close Holding - Close Holding + Sluit Holding apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 442 + 447 @@ -5916,7 +5944,7 @@ Week tot nu toe libs/ui/src/lib/assistant/assistant.component.ts - 367 + 366 @@ -5924,11 +5952,11 @@ Week tot nu toe apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 191 + 197 libs/ui/src/lib/assistant/assistant.component.ts - 367 + 366 @@ -5936,7 +5964,7 @@ Maand tot nu toe libs/ui/src/lib/assistant/assistant.component.ts - 371 + 370 @@ -5944,11 +5972,11 @@ MTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 195 + 201 libs/ui/src/lib/assistant/assistant.component.ts - 371 + 370 @@ -5956,7 +5984,7 @@ Jaar tot nu toe libs/ui/src/lib/assistant/assistant.component.ts - 375 + 374 @@ -5992,7 +6020,7 @@ jaar apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 203 + 209 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -6004,7 +6032,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 385 + 384 @@ -6012,11 +6040,11 @@ jaren apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 207 + 213 libs/ui/src/lib/assistant/assistant.component.ts - 409 + 408 @@ -6032,7 +6060,7 @@ Data Verzamelen apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 587 + 594 apps/client/src/app/components/admin-overview/admin-overview.html @@ -6044,7 +6072,7 @@ Algemeen apps/client/src/app/pages/faq/faq-page.component.ts - 49 + 41 @@ -6052,7 +6080,7 @@ Cloud apps/client/src/app/pages/faq/faq-page.component.ts - 54 + 46 libs/common/src/lib/routes/routes.ts @@ -6064,7 +6092,7 @@ Zelf Hosten apps/client/src/app/pages/faq/faq-page.component.ts - 60 + 52 libs/common/src/lib/routes/routes.ts @@ -6105,7 +6133,7 @@ Actief apps/client/src/app/components/home-holdings/home-holdings.component.ts - 64 + 63 @@ -6113,7 +6141,7 @@ Gesloten apps/client/src/app/components/home-holdings/home-holdings.component.ts - 65 + 64 @@ -6145,7 +6173,7 @@ Opdracht Uitvoeren apps/client/src/app/components/admin-jobs/admin-jobs.html - 220 + 229 @@ -6153,7 +6181,7 @@ Prioriteit apps/client/src/app/components/admin-jobs/admin-jobs.html - 96 + 105 @@ -6209,7 +6237,7 @@ Wilt u uw Ghostfolio account echt sluiten? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 208 + 205 @@ -6254,10 +6282,10 @@ Include in - Include in + Opnemen in apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 374 + 377 @@ -6265,7 +6293,7 @@ Oeps! Er is een fout opgetreden met het instellen van de biometrische authenticatie. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 336 + 333 @@ -6281,7 +6309,7 @@ Benchmarks apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 126 + 125 @@ -6329,7 +6357,7 @@ Wilt u uw persoonlijke belegginngsstrategie verfijnen? apps/client/src/app/pages/public/public-page.html - 234 + 233 @@ -6538,7 +6566,7 @@ View Holding - View Holding + Bekijk Holding libs/ui/src/lib/activities-table/activities-table.component.html 450 @@ -6661,7 +6689,7 @@ Fout apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 697 + 713 @@ -6682,7 +6710,7 @@ Oops! Could not update access. - Oops! Could not update access. + Oops! Kan de toegang niet updaten. apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts 178 @@ -6690,7 +6718,7 @@ , based on your total assets of - , based on your total assets of + opnemen, dit is gebaseerd op uw totale vermogen van apps/client/src/app/pages/portfolio/fire/fire-page.html 96 @@ -6713,7 +6741,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 592 + 599 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6745,7 +6773,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 345 + 341 apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html @@ -6753,7 +6781,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 46 + 47 libs/ui/src/lib/i18n.ts @@ -6765,7 +6793,7 @@ Sluiten apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 594 + 601 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6791,13 +6819,17 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 68 + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 127 + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html 107 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 347 + 343 libs/ui/src/lib/i18n.ts @@ -6806,10 +6838,10 @@ Role - Role + Rol apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 14 + 33 @@ -6833,7 +6865,7 @@ Portfolio Momentopname apps/client/src/app/components/admin-jobs/admin-jobs.html - 56 + 65 @@ -6846,7 +6878,7 @@ If you plan to open an account at - If you plan to open an account at + Als u van plan bent een rekening te openen bij apps/client/src/app/pages/pricing/pricing-page.html 312 @@ -6878,7 +6910,7 @@ send an e-mail to - send an e-mail to + stuur een e-mail naar apps/client/src/app/pages/about/overview/about-overview-page.html 87 @@ -6900,6 +6932,14 @@ 42 + + has been copied to the clipboard + has been copied to the clipboard + + libs/ui/src/lib/value/value.component.ts + 180 + + From the beginning Vanaf het begin @@ -6950,7 +6990,7 @@ , assuming a - , assuming a + , uitgaande van apps/client/src/app/pages/portfolio/fire/fire-page.html 174 @@ -7038,7 +7078,7 @@ Ghostfolio is a lightweight wealth management application for individuals to keep track of stocks, ETFs or cryptocurrencies and make solid, data-driven investment decisions. - Ghostfolio is a lightweight wealth management application for individuals to keep track of stocks, ETFs or cryptocurrencies and make solid, data-driven investment decisions. + Ghostfolio is een gebruiksvriendelijke applicatie voor vermogensbeheer waarmee particulieren hun aandelen, ETF's of cryptovaluta kunnen volgen en weloverwogen, datagestuurde beleggingsbeslissingen kunnen nemen. apps/client/src/app/pages/about/overview/about-overview-page.html 10 @@ -7065,7 +7105,7 @@ API-sleutel instellen apps/client/src/app/components/admin-settings/admin-settings.component.html - 171 + 188 @@ -7101,7 +7141,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 45 + 44 libs/common/src/lib/routes/routes.ts @@ -7117,7 +7157,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 34 + 33 libs/common/src/lib/routes/routes.ts @@ -7171,7 +7211,7 @@ van apps/client/src/app/components/admin-settings/admin-settings.component.html - 135 + 152 @@ -7179,7 +7219,7 @@ dagelijkse verzoeken apps/client/src/app/components/admin-settings/admin-settings.component.html - 137 + 154 @@ -7187,7 +7227,7 @@ Verwijder API-sleutel apps/client/src/app/components/admin-settings/admin-settings.component.html - 161 + 178 @@ -7195,7 +7235,7 @@ Wilt u de API-sleutel echt verwijderen? apps/client/src/app/components/admin-settings/admin-settings.component.ts - 127 + 133 @@ -7215,7 +7255,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 98 + 117 @@ -7287,7 +7327,7 @@ Opslaan apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 603 + 610 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7323,11 +7363,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 356 + 352 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 48 + 49 @@ -7339,7 +7379,7 @@ apps/client/src/app/components/user-account-access/user-account-access.component.ts - 260 + 257 @@ -7363,12 +7403,12 @@ Voer uw Ghostfolio API-sleutel in. apps/client/src/app/components/admin-settings/admin-settings.component.ts - 146 + 152 Change with currency effect - Change with currency effect + Verandering met valuta-effect apps/client/src/app/pages/portfolio/analysis/analysis-page.html 116 @@ -7379,7 +7419,7 @@ AI-prompt is naar het klembord gekopieerd apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 201 + 199 @@ -7395,7 +7435,7 @@ Lui apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 225 + 231 @@ -7403,7 +7443,7 @@ Direct apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 229 + 235 @@ -7411,7 +7451,7 @@ Standaard Marktprijs apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 481 + 484 @@ -7419,7 +7459,7 @@ Modus apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 518 + 521 @@ -7427,7 +7467,7 @@ Kiezer apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 534 + 537 @@ -7435,7 +7475,7 @@ HTTP Verzoek Headers apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 494 + 497 @@ -7443,7 +7483,7 @@ eind van de dag apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 225 + 231 @@ -7451,7 +7491,7 @@ real-time apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 229 + 235 @@ -7459,7 +7499,7 @@ Open Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 202 + 200 @@ -7479,7 +7519,7 @@ libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 377 @@ -7491,7 +7531,7 @@ apps/client/src/app/components/home-overview/home-overview.component.ts - 55 + 54 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -7499,16 +7539,16 @@ libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 377 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 381 + 390 The project has been initiated by - The project has been initiated by + Het project is geïnitieerd door apps/client/src/app/pages/about/overview/about-overview-page.html 40 @@ -7532,7 +7572,7 @@ Total amount - Total amount + Totaal bedrag apps/client/src/app/pages/portfolio/analysis/analysis-page.html 95 @@ -7607,11 +7647,11 @@ Beveiligingstoken apps/client/src/app/components/admin-users/admin-users.component.ts - 236 + 235 apps/client/src/app/components/user-account-access/user-account-access.component.ts - 170 + 167 @@ -7619,15 +7659,15 @@ Wilt u echt een nieuw beveiligingstoken voor deze gebruiker aanmaken? apps/client/src/app/components/admin-users/admin-users.component.ts - 241 + 240 Find account, holding or page... - Find account, holding or page... + Vindt een account, holding of pagina... libs/ui/src/lib/assistant/assistant.component.ts - 151 + 115 @@ -7692,7 +7732,7 @@ () is al in gebruik. apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 633 + 649 @@ -7700,7 +7740,7 @@ Er is een fout opgetreden tijdens het updaten naar (). apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 641 + 657 @@ -7764,7 +7804,7 @@ iemand apps/client/src/app/pages/public/public-page.component.ts - 59 + 61 @@ -7796,7 +7836,7 @@ Wilt u dit item echt verwijderen? libs/ui/src/lib/benchmark/benchmark.component.ts - 144 + 139 @@ -7837,7 +7877,7 @@ Demo-gebruikersaccount is gesynchroniseerd. apps/client/src/app/components/admin-overview/admin-overview.component.ts - 274 + 277 @@ -7872,7 +7912,7 @@ 150 - + Fee Ratio Vergoedingsverhouding @@ -7880,17 +7920,17 @@ 152 - - The fees do exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - De kosten overschrijden ${thresholdMax}% van uw initiële investering (${feeRatio}%) + + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + De kosten overschrijden ${thresholdMax}% van uw totale investeringsvolume (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 154 - - The fees do not exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - De kosten bedragen niet meer dan ${thresholdMax}% van uw initiële investering (${feeRatio}%) + + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + De kosten bedragen maximaal ${thresholdMax}% van uw totale investeringsvolume (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 158 @@ -8048,10 +8088,10 @@ Current month - Current month + Huidige maand apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 195 + 201 @@ -8059,11 +8099,11 @@ nieuw apps/client/src/app/components/admin-settings/admin-settings.component.html - 67 + 79 apps/client/src/app/pages/admin/admin-page.component.ts - 56 + 53 @@ -8220,7 +8260,7 @@ Wilt u echt een nieuwe securitytoken genereren? apps/client/src/app/components/user-account-access/user-account-access.component.ts - 175 + 172 @@ -8233,7 +8273,7 @@ If you encounter a bug, would like to suggest an improvement or a new feature, please join the Ghostfolio Slack community, post to @ghostfolio_ - If you encounter a bug, would like to suggest an improvement or a new feature, please join the Ghostfolio Slack community, post to @ghostfolio_ + Als je een bug tegenkomt, een verbetering wilt voorstellen of een nieuwe functie wilt toevoegen, word dan lid van de Ghostfolio Slack-community. Stuur een bericht naar @ghostfolio_ apps/client/src/app/pages/about/overview/about-overview-page.html 69 @@ -8244,7 +8284,7 @@ Aandelen apps/client/src/app/components/markets/markets.component.ts - 52 + 51 apps/client/src/app/pages/features/features-page.html @@ -8256,7 +8296,7 @@ Cryptovaluta apps/client/src/app/components/markets/markets.component.ts - 53 + 52 apps/client/src/app/pages/features/features-page.html @@ -8276,7 +8316,7 @@ Beheer activaprofiel apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 466 + 471 @@ -8357,7 +8397,7 @@ Liquidity - Liquidity + Liquiditeit apps/client/src/app/pages/i18n/i18n-page.html 70 @@ -8365,7 +8405,7 @@ Buying Power - Buying Power + Koopkracht apps/client/src/app/pages/i18n/i18n-page.html 71 @@ -8373,7 +8413,7 @@ Your buying power is below ${thresholdMin} ${baseCurrency} - Your buying power is below ${thresholdMin} ${baseCurrency} + Uw koopkracht ligt onder ${thresholdMin} ${baseCurrency} apps/client/src/app/pages/i18n/i18n-page.html 73 @@ -8381,7 +8421,7 @@ Your buying power is 0 ${baseCurrency} - Your buying power is 0 ${baseCurrency} + Uw koopkracht is 0 ${baseCurrency} apps/client/src/app/pages/i18n/i18n-page.html 77 @@ -8389,7 +8429,7 @@ Your buying power exceeds ${thresholdMin} ${baseCurrency} - Your buying power exceeds ${thresholdMin} ${baseCurrency} + Uw koopkracht overschrijdt ${thresholdMin} ${baseCurrency} apps/client/src/app/pages/i18n/i18n-page.html 80 @@ -8693,10 +8733,10 @@ Registration Date - Registration Date + Registratiedatum apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 26 + 45 diff --git a/apps/client/src/locales/messages.pl.xlf b/apps/client/src/locales/messages.pl.xlf index a94a76d2f..a15609e6a 100644 --- a/apps/client/src/locales/messages.pl.xlf +++ b/apps/client/src/locales/messages.pl.xlf @@ -240,7 +240,7 @@ please - please + proszę apps/client/src/app/pages/pricing/pricing-page.html 333 @@ -251,7 +251,7 @@ Typ apps/client/src/app/components/admin-jobs/admin-jobs.html - 48 + 57 apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html @@ -284,7 +284,7 @@ with - with + z apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 87 @@ -351,7 +351,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 309 + 310 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -363,7 +363,7 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 46 + 58 apps/client/src/app/components/admin-tag/admin-tag.component.html @@ -379,7 +379,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 139 + 135 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -423,7 +423,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 316 + 317 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -435,7 +435,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 145 + 141 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -455,15 +455,15 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 205 + 201 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 208 + 204 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 211 + 207 libs/ui/src/lib/account-balances/account-balances.component.html @@ -511,11 +511,11 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 74 + 78 apps/client/src/app/components/admin-tag/admin-tag.component.html - 67 + 71 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -543,11 +543,15 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 85 + 89 apps/client/src/app/components/admin-tag/admin-tag.component.html - 78 + 82 + + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 22 libs/ui/src/lib/account-balances/account-balances.component.html @@ -571,7 +575,7 @@ Czy na pewno chcesz usunąć to konto? libs/ui/src/lib/accounts-table/accounts-table.component.ts - 150 + 148 @@ -579,7 +583,7 @@ Profil Aktywów apps/client/src/app/components/admin-jobs/admin-jobs.html - 52 + 61 @@ -587,11 +591,11 @@ Historyczne Dane Rynkowe apps/client/src/app/components/admin-jobs/admin-jobs.html - 54 + 63 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 448 + 451 @@ -599,7 +603,7 @@ Źródło Danych apps/client/src/app/components/admin-jobs/admin-jobs.html - 82 + 91 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -611,7 +615,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 155 + 151 libs/ui/src/lib/i18n.ts @@ -623,7 +627,7 @@ Próby apps/client/src/app/components/admin-jobs/admin-jobs.html - 120 + 129 @@ -631,7 +635,7 @@ Utworzono apps/client/src/app/components/admin-jobs/admin-jobs.html - 134 + 143 @@ -639,7 +643,7 @@ Zakończono apps/client/src/app/components/admin-jobs/admin-jobs.html - 143 + 152 @@ -647,16 +651,16 @@ Status apps/client/src/app/components/admin-jobs/admin-jobs.html - 152 + 161 apps/client/src/app/components/admin-settings/admin-settings.component.html - 92 + 104 and is driven by the efforts of its contributors - and is driven by the efforts of its contributors + i jest rozwijany dzięki pracy jego współtwórców apps/client/src/app/pages/about/overview/about-overview-page.html 49 @@ -667,7 +671,7 @@ Usuń Zadania apps/client/src/app/components/admin-jobs/admin-jobs.html - 193 + 202 @@ -675,7 +679,7 @@ Zobacz Dane apps/client/src/app/components/admin-jobs/admin-jobs.html - 208 + 217 @@ -683,7 +687,7 @@ Wyświetl Stos Wywołań apps/client/src/app/components/admin-jobs/admin-jobs.html - 216 + 225 @@ -691,7 +695,7 @@ Usuń Zadanie apps/client/src/app/components/admin-jobs/admin-jobs.html - 224 + 233 @@ -707,7 +711,7 @@ Data apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 161 + 157 libs/ui/src/lib/account-balances/account-balances.component.html @@ -743,11 +747,11 @@ Waluty apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 131 + 130 apps/client/src/app/pages/public/public-page.html - 96 + 95 @@ -755,7 +759,7 @@ ETF-y bez Krajów apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 136 + 135 @@ -763,7 +767,7 @@ ETF-y bez Sektorów apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 141 + 140 @@ -779,7 +783,7 @@ Filtruj według... apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 385 + 383 @@ -819,7 +823,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 44 + 40 @@ -855,7 +859,7 @@ Ups! Nie udało się sparsować danych historycznych. libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.ts - 262 + 284 @@ -879,7 +883,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 71 + 67 @@ -911,7 +915,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 53 + 72 @@ -923,7 +927,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 396 + 399 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -931,7 +935,7 @@ apps/client/src/app/pages/public/public-page.html - 114 + 113 @@ -943,7 +947,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 407 + 410 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -955,7 +959,7 @@ Mapowanie Symboli apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 384 + 387 @@ -971,7 +975,7 @@ Konfiguracja Scrapera apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 471 + 474 @@ -979,7 +983,7 @@ Notatka apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 432 + 435 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -987,7 +991,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 275 + 271 @@ -1031,7 +1035,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 124 + 120 @@ -1039,7 +1043,7 @@ Czy naprawdę chcesz usunąć ten kupon? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 193 + 196 @@ -1047,7 +1051,7 @@ Czy naprawdę chcesz usunąć tę wiadomość systemową? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 206 + 209 @@ -1055,7 +1059,7 @@ Czy naprawdę chcesz wyczyścić pamięć podręczną? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 230 + 233 @@ -1063,7 +1067,7 @@ Proszę ustawić swoją wiadomość systemową: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 250 + 253 @@ -1187,11 +1191,11 @@ Url apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 419 + 422 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 550 + 553 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -1204,10 +1208,10 @@ Asset profile has been saved - Asset profile has been saved + Profil zasobu został zapisany apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 578 + 594 @@ -1215,12 +1219,20 @@ Czy naprawdę chcesz usunąć tę platformę? apps/client/src/app/components/admin-platform/admin-platform.component.ts - 106 + 111 + + + + Explore + Eksploruj + + apps/client/src/app/pages/resources/overview/resources-overview.component.html + 11 By - By + Przez apps/client/src/app/pages/portfolio/fire/fire-page.html 139 @@ -1236,10 +1248,10 @@ Current year - Current year + Obecny rok apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 199 + 205 @@ -1255,7 +1267,7 @@ Platformy apps/client/src/app/components/admin-settings/admin-settings.component.html - 195 + 212 @@ -1263,7 +1275,7 @@ Tagi apps/client/src/app/components/admin-settings/admin-settings.component.html - 201 + 218 libs/ui/src/lib/tags-selector/tags-selector.component.html @@ -1287,7 +1299,7 @@ Czy naprawdę chcesz usunąć ten tag? apps/client/src/app/components/admin-tag/admin-tag.component.ts - 103 + 108 @@ -1332,7 +1344,7 @@ No auto-renewal on membership. - No auto-renewal on membership. + Brak automatycznego odnawiania członkostwa. apps/client/src/app/components/user-account-membership/user-account-membership.html 74 @@ -1347,7 +1359,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 89 + 108 @@ -1379,11 +1391,11 @@ Could not validate form apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 554 + 570 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 557 + 573 @@ -1431,7 +1443,7 @@ Poziom Odniesienia (Benchmark) apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 376 + 379 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -1467,7 +1479,7 @@ apps/client/src/app/components/header/header.component.ts - 297 + 298 apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html @@ -1487,15 +1499,15 @@ Ups! Nieprawidłowy token bezpieczeństwa. apps/client/src/app/components/header/header.component.ts - 312 + 313 apps/client/src/app/components/user-account-access/user-account-access.component.ts - 154 + 152 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 193 + 191 @@ -1503,7 +1515,7 @@ Zarządzaj Aktywnościami apps/client/src/app/components/home-holdings/home-holdings.html - 67 + 64 @@ -1511,11 +1523,11 @@ Zagrożenie apps/client/src/app/components/home-market/home-market.component.ts - 42 + 41 apps/client/src/app/components/markets/markets.component.ts - 47 + 46 libs/ui/src/lib/i18n.ts @@ -1527,11 +1539,11 @@ Zachłanność apps/client/src/app/components/home-market/home-market.component.ts - 43 + 42 apps/client/src/app/components/markets/markets.component.ts - 48 + 47 libs/ui/src/lib/i18n.ts @@ -1568,7 +1580,7 @@ The source code is fully available as open source software (OSS) under the AGPL-3.0 license - The source code is fully available as open source software (OSS) under the AGPL-3.0 license + Kod źródłowy jest w pełni dostępny jako oprogramowanie open source (OSS) na licencji AGPL-3.0 license apps/client/src/app/pages/about/overview/about-overview-page.html 16 @@ -1632,10 +1644,10 @@ Current week - Current week + Obecny tydzień apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 191 + 197 @@ -1655,7 +1667,7 @@ Całkowita Kwota apps/client/src/app/components/investment-chart/investment-chart.component.ts - 143 + 146 @@ -1767,7 +1779,7 @@ Bezwzględne Osiągi Brutto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 73 + 77 @@ -1779,7 +1791,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 88 + 92 @@ -1787,7 +1799,7 @@ Bezwzględne Osiągi Netto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 107 + 111 apps/client/src/app/pages/portfolio/analysis/analysis-page.html @@ -1799,7 +1811,7 @@ Osiągi Netto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 123 + 127 apps/client/src/app/pages/portfolio/analysis/analysis-page.html @@ -1811,7 +1823,7 @@ Suma Aktywów apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 149 + 153 @@ -1819,7 +1831,7 @@ Aktywa apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 233 @@ -1827,7 +1839,7 @@ Siła Nabywcza apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 241 + 248 @@ -1835,7 +1847,7 @@ Wykluczone z Analizy apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 267 + 274 @@ -1843,7 +1855,7 @@ Pasywa (Zobowiązania Finansowe) apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 295 + 302 apps/client/src/app/pages/features/features-page.html @@ -1855,7 +1867,7 @@ Wartość Netto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 317 + 324 @@ -1863,7 +1875,7 @@ Osiągi w Ujęciu Rocznym apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 331 + 338 @@ -1899,7 +1911,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 189 + 185 libs/ui/src/lib/activities-table/activities-table.component.html @@ -1915,7 +1927,7 @@ Zgłoś Błąd Danych apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 451 + 456 @@ -2095,7 +2107,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 363 + 362 @@ -2103,11 +2115,11 @@ Liczony od początku roku (year-to-date) apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 199 + 205 libs/ui/src/lib/assistant/assistant.component.ts - 375 + 374 @@ -2115,11 +2127,11 @@ 1 rok apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 203 + 209 libs/ui/src/lib/assistant/assistant.component.ts - 385 + 384 @@ -2127,16 +2139,16 @@ 5 lat apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 207 + 213 libs/ui/src/lib/assistant/assistant.component.ts - 409 + 408 Performance with currency effect - Performance with currency effect + Wynik z efektem walutowym apps/client/src/app/pages/portfolio/analysis/analysis-page.html 135 @@ -2147,11 +2159,11 @@ Maksimum apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 211 + 217 libs/ui/src/lib/assistant/assistant.component.ts - 415 + 414 @@ -2251,7 +2263,7 @@ Auto apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 70 + 69 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -2263,7 +2275,7 @@ Czy na pewno chcesz usunąć tą metode logowania? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 282 + 279 @@ -2303,7 +2315,7 @@ Ustawienia Regionalne apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 512 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -2364,7 +2376,7 @@ this is projected to increase to - this is projected to increase to + prognozuje się wzrost tej kwoty do apps/client/src/app/pages/portfolio/fire/fire-page.html 147 @@ -2415,7 +2427,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 11 + 30 @@ -2447,7 +2459,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 195 + 194 @@ -2459,7 +2471,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 193 + 192 @@ -2475,7 +2487,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 196 + 195 @@ -2576,7 +2588,7 @@ for - for + dla apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 128 @@ -2603,11 +2615,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 375 + 381 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 66 + 85 apps/client/src/app/pages/accounts/accounts-page.html @@ -2699,7 +2711,7 @@ Dane Rynkowe apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 398 + 403 libs/common/src/lib/routes/routes.ts @@ -2733,6 +2745,10 @@ Overview Przegląd + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 7 + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 114 @@ -2751,11 +2767,11 @@ apps/client/src/app/pages/admin/admin-page.component.ts - 48 + 45 apps/client/src/app/pages/resources/resources-page.component.ts - 30 + 29 libs/common/src/lib/routes/routes.ts @@ -2876,14 +2892,14 @@ Could not parse scraper configuration - Could not parse scraper configuration + Nie udało się przetworzyć konfiguracji scrapera apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 509 + 525 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 512 + 528 @@ -2899,7 +2915,7 @@ Ponieważ jesteś już zalogowany, nie możesz uzyskać dostępu do konta demo. apps/client/src/app/pages/demo/demo-page.component.ts - 35 + 32 @@ -3032,7 +3048,7 @@ per week - per week + na tydzień apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 130 @@ -3071,7 +3087,7 @@ apps/client/src/app/pages/public/public-page.html - 242 + 241 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -3123,7 +3139,7 @@ Rynki apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 378 + 381 apps/client/src/app/components/footer/footer.component.html @@ -3147,7 +3163,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 40 + 39 libs/common/src/lib/routes/routes.ts @@ -3208,7 +3224,7 @@ Edit access - Edit access + Edytuj dostęp apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 11 @@ -3312,7 +3328,7 @@ Get access to 80’000+ tickers from over 50 exchanges - Get access to 80’000+ tickers from over 50 exchanges + Uzyskaj dostęp do 80 000+ tickerów z ponad 50 giełd apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 84 @@ -3448,7 +3464,7 @@ less than - less than + mniej niż apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 129 @@ -3512,7 +3528,7 @@ Ghostfolio Status - Ghostfolio Status + Ghostfolio Status apps/client/src/app/pages/about/overview/about-overview-page.html 62 @@ -3520,7 +3536,7 @@ with your university e-mail address - with your university e-mail address + używając swojego adresu e-mail uczelni apps/client/src/app/pages/pricing/pricing-page.html 348 @@ -3552,7 +3568,7 @@ and a safe withdrawal rate (SWR) of - and a safe withdrawal rate (SWR) of + oraz bezpiecznej stopy wypłaty (SWR) na poziomie apps/client/src/app/pages/portfolio/fire/fire-page.html 108 @@ -3579,7 +3595,7 @@ Job ID apps/client/src/app/components/admin-jobs/admin-jobs.html - 34 + 43 @@ -3615,7 +3631,7 @@ apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 115 + 113 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -3635,11 +3651,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 342 + 348 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 75 + 94 apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -3659,7 +3675,7 @@ Czy na pewno chcesz usunąć te aktywności? libs/ui/src/lib/activities-table/activities-table.component.ts - 278 + 282 @@ -3727,7 +3743,7 @@ Zaktualizuj Saldo Gotówkowe apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 112 + 108 @@ -3735,7 +3751,7 @@ Cena Jednostkowa apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 214 + 210 libs/ui/src/lib/activities-table/activities-table.component.html @@ -3763,7 +3779,7 @@ Impotruj Dywidendy apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 137 + 136 libs/ui/src/lib/activities-table/activities-table.component.html @@ -3779,7 +3795,7 @@ Importowanie danych... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 175 + 174 @@ -3787,12 +3803,12 @@ Importowanie zakończone apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 185 + 184 or start a discussion at - or start a discussion at + lub rozpocznij dyskusję n apps/client/src/app/pages/about/overview/about-overview-page.html 94 @@ -3803,7 +3819,7 @@ Weryfikacja danych... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 299 + 293 @@ -3975,7 +3991,7 @@ apps/client/src/app/pages/public/public-page.html - 151 + 150 @@ -3999,15 +4015,15 @@ apps/client/src/app/pages/public/public-page.html - 168 + 167 Latest activities - Latest activities + Ostatnie transakcje apps/client/src/app/pages/public/public-page.html - 211 + 210 @@ -4019,7 +4035,7 @@ apps/client/src/app/pages/public/public-page.html - 177 + 176 @@ -4031,7 +4047,7 @@ apps/client/src/app/pages/public/public-page.html - 186 + 185 @@ -4072,7 +4088,7 @@ Looking for a student discount? - Looking for a student discount? + Szukasz zniżki studenckiej? apps/client/src/app/pages/pricing/pricing-page.html 342 @@ -4091,7 +4107,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 365 + 372 apps/client/src/app/pages/features/features-page.html @@ -4099,11 +4115,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 202 + 198 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 76 + 75 libs/ui/src/lib/i18n.ts @@ -4112,7 +4128,7 @@ annual interest rate - annual interest rate + rocznej stopy zwrotu apps/client/src/app/pages/portfolio/fire/fire-page.html 185 @@ -4123,7 +4139,7 @@ Depozyt libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 377 + 404 @@ -4131,7 +4147,7 @@ Miesięcznie apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 91 + 90 @@ -4139,7 +4155,7 @@ Rocznie apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 92 + 91 @@ -4419,11 +4435,11 @@ Could not save asset profile apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 588 + 604 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 591 + 607 @@ -4447,12 +4463,12 @@ Kontynenty apps/client/src/app/pages/public/public-page.html - 132 + 131 Sustainable retirement income - Sustainable retirement income + Zrównoważony dochód na emeryturze apps/client/src/app/pages/portfolio/fire/fire-page.html 41 @@ -4463,7 +4479,7 @@ Ghostfolio umożliwia śledzenie wartości swojego majątku. apps/client/src/app/pages/public/public-page.html - 238 + 237 @@ -4493,6 +4509,10 @@ apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html 88 + + libs/ui/src/lib/value/value.component.html + 18 + Personal Finance Tools @@ -4585,7 +4605,7 @@ per month - per month + miesięcznie apps/client/src/app/pages/portfolio/fire/fire-page.html 94 @@ -4605,7 +4625,7 @@ Website of Thomas Kaul - Website of Thomas Kaul + Strona internetowa Thomas'a Kaul'a apps/client/src/app/pages/about/overview/about-overview-page.html 44 @@ -4824,7 +4844,7 @@ Członkostwo apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 48 + 67 libs/common/src/lib/routes/routes.ts @@ -4837,7 +4857,7 @@ Request it - Request it + Porpoś o apps/client/src/app/pages/pricing/pricing-page.html 344 @@ -4940,7 +4960,7 @@ Czy na pewno chcesz usunąć tę działalność? libs/ui/src/lib/activities-table/activities-table.component.ts - 288 + 292 @@ -4948,7 +4968,7 @@ Profile aktywów apps/client/src/app/components/admin-settings/admin-settings.component.html - 106 + 123 libs/ui/src/lib/assistant/assistant.html @@ -4957,7 +4977,7 @@ , - , + , apps/client/src/app/pages/portfolio/fire/fire-page.html 145 @@ -4981,7 +5001,7 @@ contact us - contact us + skontaktuj się z nami apps/client/src/app/pages/pricing/pricing-page.html 336 @@ -5037,18 +5057,18 @@ Interest - Udział + Odsetki apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html 69 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 352 + 359 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 387 + 414 libs/ui/src/lib/i18n.ts @@ -5060,7 +5080,7 @@ Oszczędności libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 397 + 424 @@ -5088,7 +5108,7 @@ Pokaż wszystko libs/ui/src/lib/holdings-table/holdings-table.component.html - 216 + 212 @@ -5132,7 +5152,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 326 + 327 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -5140,7 +5160,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 290 + 286 libs/ui/src/lib/i18n.ts @@ -5164,7 +5184,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 342 + 343 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -5172,7 +5192,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 309 + 305 libs/ui/src/lib/i18n.ts @@ -5216,7 +5236,7 @@ Fundusz Rezerwowy apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 164 + 168 apps/client/src/app/pages/features/features-page.html @@ -5292,7 +5312,7 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 437 + 451 @@ -5303,6 +5323,14 @@ 27 + + No Activities + Brak transakcji + + apps/client/src/app/components/admin-market-data/admin-market-data.component.ts + 145 + + Retirement Provision Świadczenia Emerytalne @@ -5332,7 +5360,7 @@ Symbol apps/client/src/app/components/admin-jobs/admin-jobs.html - 68 + 77 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -5348,7 +5376,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 315 + 318 libs/ui/src/lib/i18n.ts @@ -5377,7 +5405,7 @@ View Details - View Details + Zobacz szczegóły apps/client/src/app/components/admin-users/admin-users.html 225 @@ -5397,7 +5425,7 @@ Sign in with OpenID Connect - Sign in with OpenID Connect + Zaloguj się za pomocą OpenID Connect apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html 55 @@ -5405,7 +5433,7 @@ Buy - Zakup + Kupno apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html 31 @@ -5420,7 +5448,7 @@ Opłata apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 262 + 258 libs/ui/src/lib/activities-table/activities-table.component.html @@ -5449,7 +5477,7 @@ Sell - Sprzedaj + Sprzedaż apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html 44 @@ -5464,7 +5492,7 @@ Gotówka apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 212 + 219 libs/ui/src/lib/i18n.ts @@ -5509,10 +5537,10 @@ Authentication - Authentication + Uwierzytelnianie apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 35 + 54 @@ -5605,7 +5633,7 @@ If you retire today, you would be able to withdraw - If you retire today, you would be able to withdraw + Gdybyś przeszedł na emeryturę dziś, mógłbyś wypłacać apps/client/src/app/pages/portfolio/fire/fire-page.html 68 @@ -5656,7 +5684,7 @@ Ważność do apps/client/src/app/components/admin-settings/admin-settings.component.html - 74 + 86 libs/ui/src/lib/membership-card/membership-card.component.html @@ -5680,7 +5708,7 @@ apps/client/src/app/pages/public/public-page.html - 196 + 195 libs/ui/src/lib/benchmark/benchmark.component.html @@ -5688,11 +5716,11 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 439 + 453 libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 452 + 467 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -5720,7 +5748,7 @@ Salda Gotówkowe apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 148 + 146 @@ -5740,7 +5768,7 @@ Czy na pewno chcesz usunąć saldo tego konta? libs/ui/src/lib/account-balances/account-balances.component.ts - 120 + 113 @@ -5756,7 +5784,7 @@ Obecna cena rynkowa wynosi apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 706 + 722 @@ -5764,7 +5792,7 @@ Test apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 568 + 571 @@ -5809,7 +5837,7 @@ Argentina - Argentina + Argentyna libs/ui/src/lib/i18n.ts 78 @@ -5852,11 +5880,11 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 81 + 80 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 97 + 96 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -5865,7 +5893,7 @@ here - here + tutaj apps/client/src/app/pages/pricing/pricing-page.html 347 @@ -5873,10 +5901,10 @@ Close Holding - Close Holding + Zamknij pozycję apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 442 + 447 @@ -5916,7 +5944,7 @@ Dotychczasowy tydzień libs/ui/src/lib/assistant/assistant.component.ts - 367 + 366 @@ -5924,11 +5952,11 @@ WTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 191 + 197 libs/ui/src/lib/assistant/assistant.component.ts - 367 + 366 @@ -5936,7 +5964,7 @@ Od początku miesiąca libs/ui/src/lib/assistant/assistant.component.ts - 371 + 370 @@ -5944,11 +5972,11 @@ MTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 195 + 201 libs/ui/src/lib/assistant/assistant.component.ts - 371 + 370 @@ -5956,7 +5984,7 @@ Od początku roku libs/ui/src/lib/assistant/assistant.component.ts - 375 + 374 @@ -5992,7 +6020,7 @@ rok apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 203 + 209 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -6004,7 +6032,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 385 + 384 @@ -6012,11 +6040,11 @@ lata apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 207 + 213 libs/ui/src/lib/assistant/assistant.component.ts - 409 + 408 @@ -6032,7 +6060,7 @@ Gromadzenie Danych apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 587 + 594 apps/client/src/app/components/admin-overview/admin-overview.html @@ -6044,7 +6072,7 @@ Informacje Ogólne apps/client/src/app/pages/faq/faq-page.component.ts - 49 + 41 @@ -6052,7 +6080,7 @@ Rozwiązanie w Chmurze apps/client/src/app/pages/faq/faq-page.component.ts - 54 + 46 libs/common/src/lib/routes/routes.ts @@ -6064,7 +6092,7 @@ Własny Hosting apps/client/src/app/pages/faq/faq-page.component.ts - 60 + 52 libs/common/src/lib/routes/routes.ts @@ -6105,7 +6133,7 @@ Antywne apps/client/src/app/components/home-holdings/home-holdings.component.ts - 64 + 63 @@ -6113,7 +6141,7 @@ Zamknięte apps/client/src/app/components/home-holdings/home-holdings.component.ts - 65 + 64 @@ -6145,7 +6173,7 @@ Wykonaj Zadanie apps/client/src/app/components/admin-jobs/admin-jobs.html - 220 + 229 @@ -6153,7 +6181,7 @@ Priorytet apps/client/src/app/components/admin-jobs/admin-jobs.html - 96 + 105 @@ -6209,7 +6237,7 @@ Czy na pewno chcesz zamknąć swoje konto Ghostfolio? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 208 + 205 @@ -6254,10 +6282,10 @@ Include in - Include in + Uwzględnij w apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 374 + 377 @@ -6265,7 +6293,7 @@ Ups! Wystąpił błąd podczas konfigurowania uwierzytelniania biometrycznego. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 336 + 333 @@ -6281,7 +6309,7 @@ Punkty Odniesienia apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 126 + 125 @@ -6329,7 +6357,7 @@ Chcesz udoskonalić swoją osobistą strategię inwestycyjną? apps/client/src/app/pages/public/public-page.html - 234 + 233 @@ -6538,7 +6566,7 @@ View Holding - View Holding + Podgląd inwestycji libs/ui/src/lib/activities-table/activities-table.component.html 450 @@ -6661,7 +6689,7 @@ Błąd apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 697 + 713 @@ -6682,7 +6710,7 @@ Oops! Could not update access. - Oops! Could not update access. + Ups! Nie udało się zaktualizować dostępu. apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts 178 @@ -6690,7 +6718,7 @@ , based on your total assets of - , based on your total assets of + , na podstawie całkowitej wartości aktywów wynoszącej apps/client/src/app/pages/portfolio/fire/fire-page.html 96 @@ -6713,7 +6741,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 592 + 599 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6745,7 +6773,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 345 + 341 apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html @@ -6753,7 +6781,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 46 + 47 libs/ui/src/lib/i18n.ts @@ -6765,7 +6793,7 @@ Zamknij apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 594 + 601 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6791,13 +6819,17 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 68 + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 127 + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html 107 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 347 + 343 libs/ui/src/lib/i18n.ts @@ -6806,10 +6838,10 @@ Role - Role + Rola apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 14 + 33 @@ -6833,7 +6865,7 @@ Przegląd portfela apps/client/src/app/components/admin-jobs/admin-jobs.html - 56 + 65 @@ -6846,7 +6878,7 @@ If you plan to open an account at - If you plan to open an account at + Jeśli planujesz otworzyć konto w apps/client/src/app/pages/pricing/pricing-page.html 312 @@ -6878,7 +6910,7 @@ send an e-mail to - send an e-mail to + wyślij e-mail do apps/client/src/app/pages/about/overview/about-overview-page.html 87 @@ -6900,6 +6932,14 @@ 42 + + has been copied to the clipboard + has been copied to the clipboard + + libs/ui/src/lib/value/value.component.ts + 180 + + From the beginning Od samego początku @@ -6950,7 +6990,7 @@ , assuming a - , assuming a + , przyjmując apps/client/src/app/pages/portfolio/fire/fire-page.html 174 @@ -6958,7 +6998,7 @@ to use our referral link and get a Ghostfolio Premium membership for one year - to use our referral link and get a Ghostfolio Premium membership for one year + aby skorzystać z naszego linku polecającego i otrzymać roczną subskrypcję Ghostfolio Premium apps/client/src/app/pages/pricing/pricing-page.html 340 @@ -6966,7 +7006,7 @@ can be self-hosted - może być hostowany samodzielnie + może być hostowana samodzielnie apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 178 @@ -6990,7 +7030,7 @@ can be used anonymously - może być używany anonimowo + może być używana anonimowo apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 217 @@ -7002,7 +7042,7 @@ cannot be used anonymously - nie może być używany anonimowo + nie może być używana anonimowo apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 224 @@ -7038,7 +7078,7 @@ Ghostfolio is a lightweight wealth management application for individuals to keep track of stocks, ETFs or cryptocurrencies and make solid, data-driven investment decisions. - Ghostfolio is a lightweight wealth management application for individuals to keep track of stocks, ETFs or cryptocurrencies and make solid, data-driven investment decisions. + Ghostfolio to aplikacja do zarządzania majątkiem, przeznaczona dla osób prywatnych do śledzenia akcji, ETF‑ów i kryptowalut oraz podejmowania solidnych, opartych na danych decyzji inwestycyjnych. apps/client/src/app/pages/about/overview/about-overview-page.html 10 @@ -7065,7 +7105,7 @@ Skonfiguruj klucz API apps/client/src/app/components/admin-settings/admin-settings.component.html - 171 + 188 @@ -7101,7 +7141,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 45 + 44 libs/common/src/lib/routes/routes.ts @@ -7117,7 +7157,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 34 + 33 libs/common/src/lib/routes/routes.ts @@ -7171,7 +7211,7 @@ z apps/client/src/app/components/admin-settings/admin-settings.component.html - 135 + 152 @@ -7179,7 +7219,7 @@ codzienne żądania apps/client/src/app/components/admin-settings/admin-settings.component.html - 137 + 154 @@ -7187,7 +7227,7 @@ Usuń klucz API apps/client/src/app/components/admin-settings/admin-settings.component.html - 161 + 178 @@ -7195,7 +7235,7 @@ Czy na pewno chcesz usunąć klucz API?? apps/client/src/app/components/admin-settings/admin-settings.component.ts - 127 + 133 @@ -7215,7 +7255,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 98 + 117 @@ -7287,7 +7327,7 @@ Zapisz apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 603 + 610 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7323,11 +7363,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 356 + 352 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 48 + 49 @@ -7339,7 +7379,7 @@ apps/client/src/app/components/user-account-access/user-account-access.component.ts - 260 + 257 @@ -7352,7 +7392,7 @@ Check the system status at - Check the system status at + Sprawdź status systemu n apps/client/src/app/pages/about/overview/about-overview-page.html 57 @@ -7363,12 +7403,12 @@ Wprowadź swój klucz API Ghostfolio. apps/client/src/app/components/admin-settings/admin-settings.component.ts - 146 + 152 Change with currency effect - Change with currency effect + Zmiana z efektem walutowym apps/client/src/app/pages/portfolio/analysis/analysis-page.html 116 @@ -7379,7 +7419,7 @@ Prompt AI został skopiowany do schowka apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 201 + 199 @@ -7395,7 +7435,7 @@ Leniwy apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 225 + 231 @@ -7403,7 +7443,7 @@ Natychmiastowy apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 229 + 235 @@ -7411,7 +7451,7 @@ Domyślna cena rynkowa apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 481 + 484 @@ -7419,7 +7459,7 @@ Tryb apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 518 + 521 @@ -7427,7 +7467,7 @@ Selektor apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 534 + 537 @@ -7435,7 +7475,7 @@ Nagłówki żądań HTTP apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 494 + 497 @@ -7443,7 +7483,7 @@ koniec dnia apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 225 + 231 @@ -7451,7 +7491,7 @@ w czasie rzeczywistym apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 229 + 235 @@ -7459,7 +7499,7 @@ Otwórz Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 202 + 200 @@ -7479,7 +7519,7 @@ libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 377 @@ -7491,7 +7531,7 @@ apps/client/src/app/components/home-overview/home-overview.component.ts - 55 + 54 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -7499,16 +7539,16 @@ libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 377 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 381 + 390 The project has been initiated by - The project has been initiated by + Projekt został zainicjowany przez apps/client/src/app/pages/about/overview/about-overview-page.html 40 @@ -7532,7 +7572,7 @@ Total amount - Total amount + Wartość portfela apps/client/src/app/pages/portfolio/analysis/analysis-page.html 95 @@ -7607,11 +7647,11 @@ Token bezpieczeństwa apps/client/src/app/components/admin-users/admin-users.component.ts - 236 + 235 apps/client/src/app/components/user-account-access/user-account-access.component.ts - 170 + 167 @@ -7619,15 +7659,15 @@ Czy napewno chcesz wygenerować nowy token bezpieczeństwa dla tego użytkownika? apps/client/src/app/components/admin-users/admin-users.component.ts - 241 + 240 Find account, holding or page... - Find account, holding or page... + Znajdź konto, pozycję lub stronę... libs/ui/src/lib/assistant/assistant.component.ts - 151 + 115 @@ -7692,7 +7732,7 @@ () jest już w użyciu. apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 633 + 649 @@ -7700,7 +7740,7 @@ Wystąpił błąd podczas aktualizacji do (). apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 641 + 657 @@ -7764,7 +7804,7 @@ ktoś apps/client/src/app/pages/public/public-page.component.ts - 59 + 61 @@ -7796,7 +7836,7 @@ Czy na pewno chcesz usunąć ten element? libs/ui/src/lib/benchmark/benchmark.component.ts - 144 + 139 @@ -7837,7 +7877,7 @@ Konto użytkownika demonstracyjnego zostało zsynchronizowane. apps/client/src/app/components/admin-overview/admin-overview.component.ts - 274 + 277 @@ -7872,25 +7912,25 @@ 150 - + Fee Ratio - Stosunek opłat + Wskaźnik opłat apps/client/src/app/pages/i18n/i18n-page.html 152 - - The fees do exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - Opłaty przekraczają ${thresholdMax}% początkowej inwestycji (${feeRatio}%) + + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + Opłaty przekraczają ${thresholdMax}% twojej całkowitej wartości inwestycji (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 154 - - The fees do not exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - Opłaty nie przekraczają ${thresholdMax}% początkowej inwestycji (${feeRatio}%) + + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + Opłaty nie przekraczają ${thresholdMax}% twojej całkowitej wartości inwestycji (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 158 @@ -8048,10 +8088,10 @@ Current month - Current month + Bieżący miesiąc apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 195 + 201 @@ -8059,11 +8099,11 @@ nowy apps/client/src/app/components/admin-settings/admin-settings.component.html - 67 + 79 apps/client/src/app/pages/admin/admin-page.component.ts - 56 + 53 @@ -8220,7 +8260,7 @@ Czy na pewno chcesz wygenerować nowy token bezpieczeństwa? apps/client/src/app/components/user-account-access/user-account-access.component.ts - 175 + 172 @@ -8244,7 +8284,7 @@ Akcje apps/client/src/app/components/markets/markets.component.ts - 52 + 51 apps/client/src/app/pages/features/features-page.html @@ -8256,7 +8296,7 @@ Kryptowaluty apps/client/src/app/components/markets/markets.component.ts - 53 + 52 apps/client/src/app/pages/features/features-page.html @@ -8276,7 +8316,7 @@ Zarządzaj profilem aktywów apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 466 + 471 @@ -8309,7 +8349,7 @@ Account Cluster Risks - Account Cluster Risks + Ryzyka skupienia w obrębie rachunków apps/client/src/app/pages/i18n/i18n-page.html 14 @@ -8317,7 +8357,7 @@ Asset Class Cluster Risks - Asset Class Cluster Risks + Ryzyka skupienia w obrębie klas aktywów apps/client/src/app/pages/i18n/i18n-page.html 39 @@ -8325,7 +8365,7 @@ Currency Cluster Risks - Currency Cluster Risks + Ryzyka koncentracji walutowej apps/client/src/app/pages/i18n/i18n-page.html 83 @@ -8333,7 +8373,7 @@ Economic Market Cluster Risks - Economic Market Cluster Risks + Ryzyka skupienia w obrębie segmentów rynku gospodarczego apps/client/src/app/pages/i18n/i18n-page.html 106 @@ -8341,7 +8381,7 @@ Emergency Fund - Emergency Fund + Fundusz Awaryjny apps/client/src/app/pages/i18n/i18n-page.html 144 @@ -8349,7 +8389,7 @@ Fees - Fees + Opłaty apps/client/src/app/pages/i18n/i18n-page.html 161 @@ -8357,7 +8397,7 @@ Liquidity - Liquidity + Płynność apps/client/src/app/pages/i18n/i18n-page.html 70 @@ -8365,7 +8405,7 @@ Buying Power - Buying Power + Siła nabywcza apps/client/src/app/pages/i18n/i18n-page.html 71 @@ -8373,7 +8413,7 @@ Your buying power is below ${thresholdMin} ${baseCurrency} - Your buying power is below ${thresholdMin} ${baseCurrency} + Twoja siła nabywcza jest niższa niż ${thresholdMin} ${baseCurrency} apps/client/src/app/pages/i18n/i18n-page.html 73 @@ -8381,7 +8421,7 @@ Your buying power is 0 ${baseCurrency} - Your buying power is 0 ${baseCurrency} + Twoja siła nabywcza to 0 ${baseCurrency} apps/client/src/app/pages/i18n/i18n-page.html 77 @@ -8389,7 +8429,7 @@ Your buying power exceeds ${thresholdMin} ${baseCurrency} - Your buying power exceeds ${thresholdMin} ${baseCurrency} + Twoja siła nabywcza przekracza ${thresholdMin} ${baseCurrency} apps/client/src/app/pages/i18n/i18n-page.html 80 @@ -8397,7 +8437,7 @@ Regional Market Cluster Risks - Regional Market Cluster Risks + Ryzyka skupienia w obrębie regionów rynkowych apps/client/src/app/pages/i18n/i18n-page.html 163 @@ -8405,7 +8445,7 @@ No results found... - No results found... + Nie znaleziono wyników... libs/ui/src/lib/assistant/assistant.html 51 @@ -8413,7 +8453,7 @@ Developed Markets - Developed Markets + Rynki rozwinięte apps/client/src/app/pages/i18n/i18n-page.html 109 @@ -8421,7 +8461,7 @@ The developed markets contribution of your current investment (${developedMarketsValueRatio}%) exceeds ${thresholdMax}% - The developed markets contribution of your current investment (${developedMarketsValueRatio}%) exceeds ${thresholdMax}% + Udział rynków rozwiniętych w Twojej obecnej inwestycji (${developedMarketsValueRatio}%) przekracza ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 112 @@ -8429,7 +8469,7 @@ The developed markets contribution of your current investment (${developedMarketsValueRatio}%) is below ${thresholdMin}% - The developed markets contribution of your current investment (${developedMarketsValueRatio}%) is below ${thresholdMin}% + Udział rynków rozwiniętych w Twojej obecnej inwestycji (${developedMarketsValueRatio}%) jest poniżej ${thresholdMin}% apps/client/src/app/pages/i18n/i18n-page.html 117 @@ -8437,7 +8477,7 @@ The developed markets contribution of your current investment (${developedMarketsValueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% - The developed markets contribution of your current investment (${developedMarketsValueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% + Udział rynków rozwiniętych w Twojej obecnej inwestycji (${developedMarketsValueRatio}%) mieści się w zakresie ${thresholdMin}% i ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 122 @@ -8445,7 +8485,7 @@ Emerging Markets - Emerging Markets + Rynki wschodzące apps/client/src/app/pages/i18n/i18n-page.html 127 @@ -8453,7 +8493,7 @@ The emerging markets contribution of your current investment (${emergingMarketsValueRatio}%) exceeds ${thresholdMax}% - The emerging markets contribution of your current investment (${emergingMarketsValueRatio}%) exceeds ${thresholdMax}% + Udział rynków wschodzących w obecnej inwestycji (${emergingMarketsValueRatio}%) przekracza ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 130 @@ -8461,7 +8501,7 @@ The emerging markets contribution of your current investment (${emergingMarketsValueRatio}%) is below ${thresholdMin}% - The emerging markets contribution of your current investment (${emergingMarketsValueRatio}%) is below ${thresholdMin}% + Udział rynków wschodzących w obecnej inwestycji (${emergingMarketsValueRatio}%) jest poniżej ${thresholdMin}% apps/client/src/app/pages/i18n/i18n-page.html 135 @@ -8469,7 +8509,7 @@ The emerging markets contribution of your current investment (${emergingMarketsValueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% - The emerging markets contribution of your current investment (${emergingMarketsValueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% + Udział rynków wschodzących w obecnej inwestycji (${emergingMarketsValueRatio}%) mieści się w zakresie ${thresholdMin}% i ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 140 @@ -8477,7 +8517,7 @@ No accounts have been set up - No accounts have been set up + Nie utworzono żadnych kont apps/client/src/app/pages/i18n/i18n-page.html 21 @@ -8485,7 +8525,7 @@ Your net worth is managed by 0 accounts - Your net worth is managed by 0 accounts + Twój majątek jest zarządzany przez 0 kont apps/client/src/app/pages/i18n/i18n-page.html 33 @@ -8493,7 +8533,7 @@ Asia-Pacific - Asia-Pacific + Asia-Pacific apps/client/src/app/pages/i18n/i18n-page.html 165 @@ -8501,7 +8541,7 @@ The Asia-Pacific market contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% - The Asia-Pacific market contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% + Udział rynku Azji i Pacyfiku w Twojej obecnej inwestycji (${valueRatio}%) przekracza ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 167 @@ -8509,7 +8549,7 @@ The Asia-Pacific market contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% - The Asia-Pacific market contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% + Udział rynku Azji i Pacyfiku w Twojej obecnej inwestycji (${valueRatio}%) jest poniżej ${thresholdMin}% apps/client/src/app/pages/i18n/i18n-page.html 171 @@ -8517,7 +8557,7 @@ The Asia-Pacific market contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% - The Asia-Pacific market contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% + Udział rynku Azji i Pacyfiku w Twojej obecnej inwestycji (${valueRatio}%) mieści się w zakresie ${thresholdMin}% i ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 175 @@ -8525,7 +8565,7 @@ Emerging Markets - Emerging Markets + Rynki wschodzące apps/client/src/app/pages/i18n/i18n-page.html 180 @@ -8533,7 +8573,7 @@ The Emerging Markets contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% - The Emerging Markets contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% + Udział rynków wschodzących w Twojej obecnej inwestycji (${valueRatio}%) przekracza ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 183 @@ -8541,7 +8581,7 @@ The Emerging Markets contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% - The Emerging Markets contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% + Udział rynków wschodzących w Twojej obecnej inwestycji (${valueRatio}%) jest poniżej ${thresholdMin}% apps/client/src/app/pages/i18n/i18n-page.html 187 @@ -8549,7 +8589,7 @@ The Emerging Markets contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% - The Emerging Markets contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% + Udział rynków wschodzących w Twojej obecnej inwestycji (${valueRatio}%) mieści się w zakresie ${thresholdMin}% i ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 191 @@ -8557,7 +8597,7 @@ Europe - Europe + Europa apps/client/src/app/pages/i18n/i18n-page.html 195 @@ -8565,7 +8605,7 @@ The Europe market contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% - The Europe market contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% + Udział rynku europejskiego w obecnej inwestycji (${valueRatio}%) przekracza ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 197 @@ -8573,7 +8613,7 @@ The Europe market contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% - The Europe market contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% + Udział rynku europejskiego w obecnej inwestycji (${valueRatio}%) jest poniżej ${thresholdMin}% apps/client/src/app/pages/i18n/i18n-page.html 201 @@ -8581,7 +8621,7 @@ The Europe market contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% - The Europe market contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% + Udział rynku europejskiego w obecnej inwestycji (${valueRatio}%) mieści się w zakresie ${thresholdMin}% i ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 205 @@ -8589,7 +8629,7 @@ Japan - Japan + Japonia apps/client/src/app/pages/i18n/i18n-page.html 209 @@ -8597,7 +8637,7 @@ The Japan market contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% - The Japan market contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% + Udział rynku japońskiego w obecnej inwestycj (${valueRatio}%) przekracza ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 211 @@ -8605,7 +8645,7 @@ The Japan market contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% - The Japan market contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% + Udział rynku japońskiego w obecnej inwestycj (${valueRatio}%) jest poniżej ${thresholdMin}% apps/client/src/app/pages/i18n/i18n-page.html 215 @@ -8613,7 +8653,7 @@ The Japan market contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% - The Japan market contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% + Udział rynku japońskiego w obecnej inwestycj (${valueRatio}%) mieści się w zakresie ${thresholdMin}% i ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 219 @@ -8621,7 +8661,7 @@ North America - North America + Północna Ameryka apps/client/src/app/pages/i18n/i18n-page.html 223 @@ -8629,7 +8669,7 @@ The North America market contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% - The North America market contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% + Udział rynku Ameryki Północnej w obecnej inwestycji (${valueRatio}%) przekracza ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 225 @@ -8637,7 +8677,7 @@ The North America market contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% - The North America market contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% + Udział rynku Ameryki Północnej w obecnej inwestycji (${valueRatio}%) jest poniżej ${thresholdMin}% apps/client/src/app/pages/i18n/i18n-page.html 229 @@ -8645,7 +8685,7 @@ The North America market contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% - The North America market contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% + Udział rynku Ameryki Północnej w obecnej inwestycji (${valueRatio}%) mieści się w zakresie ${thresholdMin}% i ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 233 @@ -8653,7 +8693,7 @@ Find Ghostfolio on GitHub - Find Ghostfolio on GitHub + Znajdź Ghostfolio na GitHub apps/client/src/app/pages/about/overview/about-overview-page.html 99 @@ -8665,7 +8705,7 @@ Join the Ghostfolio Slack community - Join the Ghostfolio Slack community + Dołącz do społeczności Ghostfolio na Slacku apps/client/src/app/pages/about/overview/about-overview-page.html 109 @@ -8673,7 +8713,7 @@ Follow Ghostfolio on X (formerly Twitter) - Follow Ghostfolio on X (formerly Twitter) + Śledź Ghostfolio na X (poprzednio Twitter) apps/client/src/app/pages/about/overview/about-overview-page.html 118 @@ -8681,7 +8721,7 @@ Send an e-mail - Send an e-mail + Wyślij e-mail apps/client/src/app/pages/about/overview/about-overview-page.html 89 @@ -8693,15 +8733,15 @@ Registration Date - Registration Date + Data rejestracji apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 26 + 45 Follow Ghostfolio on LinkedIn - Follow Ghostfolio on LinkedIn + Śledź Ghostfolio na LinkedIn apps/client/src/app/pages/about/overview/about-overview-page.html 147 @@ -8709,7 +8749,7 @@ Ghostfolio is an independent & bootstrapped business - Ghostfolio is an independent & bootstrapped business + Ghostfolio to niezależna & samofinansująca się firma apps/client/src/app/pages/about/overview/about-overview-page.html 157 @@ -8717,7 +8757,7 @@ Support Ghostfolio - Support Ghostfolio + Wesprzyj Ghostfolio apps/client/src/app/pages/about/overview/about-overview-page.html 166 diff --git a/apps/client/src/locales/messages.pt.xlf b/apps/client/src/locales/messages.pt.xlf index 2bcd7c401..3531f84d7 100644 --- a/apps/client/src/locales/messages.pt.xlf +++ b/apps/client/src/locales/messages.pt.xlf @@ -42,7 +42,7 @@ Tipo apps/client/src/app/components/admin-jobs/admin-jobs.html - 48 + 57 apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html @@ -114,7 +114,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 309 + 310 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -126,7 +126,7 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 46 + 58 apps/client/src/app/components/admin-tag/admin-tag.component.html @@ -142,7 +142,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 139 + 135 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -186,7 +186,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 316 + 317 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -198,7 +198,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 145 + 141 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -234,15 +234,15 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 205 + 201 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 208 + 204 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 211 + 207 libs/ui/src/lib/account-balances/account-balances.component.html @@ -290,11 +290,11 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 74 + 78 apps/client/src/app/components/admin-tag/admin-tag.component.html - 67 + 71 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -322,11 +322,15 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 85 + 89 apps/client/src/app/components/admin-tag/admin-tag.component.html - 78 + 82 + + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 22 libs/ui/src/lib/account-balances/account-balances.component.html @@ -350,7 +354,7 @@ Pretende realmente eliminar esta conta? libs/ui/src/lib/accounts-table/accounts-table.component.ts - 150 + 148 @@ -358,7 +362,7 @@ Fonte de dados apps/client/src/app/components/admin-jobs/admin-jobs.html - 82 + 91 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -370,7 +374,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 155 + 151 libs/ui/src/lib/i18n.ts @@ -382,7 +386,7 @@ Tentativas apps/client/src/app/components/admin-jobs/admin-jobs.html - 120 + 129 @@ -390,7 +394,7 @@ Criado apps/client/src/app/components/admin-jobs/admin-jobs.html - 134 + 143 @@ -398,7 +402,7 @@ Terminado apps/client/src/app/components/admin-jobs/admin-jobs.html - 143 + 152 @@ -406,11 +410,11 @@ Estado apps/client/src/app/components/admin-jobs/admin-jobs.html - 152 + 161 apps/client/src/app/components/admin-settings/admin-settings.component.html - 92 + 104 @@ -426,7 +430,7 @@ Eliminar Tarefas apps/client/src/app/components/admin-jobs/admin-jobs.html - 193 + 202 @@ -434,7 +438,7 @@ Perfil de Ativos apps/client/src/app/components/admin-settings/admin-settings.component.html - 106 + 123 libs/ui/src/lib/assistant/assistant.html @@ -446,11 +450,11 @@ Histórico de Dados de Mercado apps/client/src/app/components/admin-jobs/admin-jobs.html - 54 + 63 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 448 + 451 @@ -458,7 +462,7 @@ Visualizar dados apps/client/src/app/components/admin-jobs/admin-jobs.html - 208 + 217 @@ -466,7 +470,7 @@ Ver Stacktrace apps/client/src/app/components/admin-jobs/admin-jobs.html - 216 + 225 @@ -474,7 +478,7 @@ Apagar Tarefa apps/client/src/app/components/admin-jobs/admin-jobs.html - 224 + 233 @@ -490,7 +494,7 @@ Data apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 161 + 157 libs/ui/src/lib/account-balances/account-balances.component.html @@ -526,7 +530,7 @@ Filtrar por... apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 385 + 383 @@ -566,7 +570,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 44 + 40 @@ -602,7 +606,7 @@ Deseja realmente eliminar este cupão? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 193 + 196 @@ -610,7 +614,7 @@ Deseja realmente limpar a cache? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 230 + 233 @@ -618,7 +622,7 @@ Por favor, defina a sua mensagem do sistema: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 250 + 253 @@ -746,7 +750,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 89 + 108 @@ -762,11 +766,11 @@ Could not validate form apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 554 + 570 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 557 + 573 @@ -806,7 +810,7 @@ Referência apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 376 + 379 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -842,7 +846,7 @@ apps/client/src/app/components/header/header.component.ts - 297 + 298 apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html @@ -862,15 +866,15 @@ Oops! Token de Segurança Incorreto. apps/client/src/app/components/header/header.component.ts - 312 + 313 apps/client/src/app/components/user-account-access/user-account-access.component.ts - 154 + 152 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 193 + 191 @@ -878,7 +882,7 @@ Gerir Atividades apps/client/src/app/components/home-holdings/home-holdings.html - 67 + 64 @@ -886,11 +890,11 @@ Medo apps/client/src/app/components/home-market/home-market.component.ts - 42 + 41 apps/client/src/app/components/markets/markets.component.ts - 47 + 46 libs/ui/src/lib/i18n.ts @@ -902,11 +906,11 @@ Ganância apps/client/src/app/components/home-market/home-market.component.ts - 43 + 42 apps/client/src/app/components/markets/markets.component.ts - 48 + 47 libs/ui/src/lib/i18n.ts @@ -938,7 +942,7 @@ Depósito libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 377 + 404 @@ -946,7 +950,7 @@ Valor Total apps/client/src/app/components/investment-chart/investment-chart.component.ts - 143 + 146 @@ -1058,7 +1062,7 @@ Desempenho Bruto Absoluto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 73 + 77 @@ -1066,7 +1070,7 @@ Desempenho Líquido Absoluto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 107 + 111 apps/client/src/app/pages/portfolio/analysis/analysis-page.html @@ -1078,7 +1082,7 @@ Desempenho Líquido apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 123 + 127 apps/client/src/app/pages/portfolio/analysis/analysis-page.html @@ -1090,7 +1094,7 @@ Ativos Totais apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 149 + 153 @@ -1098,7 +1102,7 @@ Poder de Compra apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 241 + 248 @@ -1106,7 +1110,7 @@ Excluído da Análise apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 267 + 274 @@ -1114,7 +1118,7 @@ Valor Líquido apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 317 + 324 @@ -1122,7 +1126,7 @@ Desempenho Anual apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 331 + 338 @@ -1158,7 +1162,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 189 + 185 libs/ui/src/lib/activities-table/activities-table.component.html @@ -1198,7 +1202,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 53 + 72 @@ -1210,7 +1214,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 396 + 399 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -1218,7 +1222,7 @@ apps/client/src/app/pages/public/public-page.html - 114 + 113 @@ -1230,7 +1234,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 407 + 410 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -1242,7 +1246,7 @@ Marcadores apps/client/src/app/components/admin-settings/admin-settings.component.html - 201 + 218 libs/ui/src/lib/tags-selector/tags-selector.component.html @@ -1258,7 +1262,7 @@ Dados do Relatório com Problema apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 451 + 456 @@ -1286,7 +1290,7 @@ Mostrar tudo libs/ui/src/lib/holdings-table/holdings-table.component.html - 216 + 212 @@ -1298,7 +1302,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 363 + 362 @@ -1306,11 +1310,11 @@ AATD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 199 + 205 libs/ui/src/lib/assistant/assistant.component.ts - 375 + 374 @@ -1318,11 +1322,11 @@ 1A apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 203 + 209 libs/ui/src/lib/assistant/assistant.component.ts - 385 + 384 @@ -1330,11 +1334,11 @@ 5A apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 207 + 213 libs/ui/src/lib/assistant/assistant.component.ts - 409 + 408 @@ -1350,11 +1354,11 @@ Máx apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 211 + 217 libs/ui/src/lib/assistant/assistant.component.ts - 415 + 414 @@ -1378,7 +1382,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 195 + 194 @@ -1390,7 +1394,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 193 + 192 @@ -1406,7 +1410,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 196 + 195 @@ -1466,7 +1470,7 @@ Auto apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 70 + 69 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -1510,7 +1514,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 - 282 + 279 @@ -1586,7 +1590,7 @@ Localidade apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 512 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -1666,7 +1670,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 11 + 30 @@ -1714,11 +1718,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 375 + 381 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 66 + 85 apps/client/src/app/pages/accounts/accounts-page.html @@ -1886,7 +1890,7 @@ Como já tem sessão iniciada, não pode aceder à conta de demonstração. apps/client/src/app/pages/demo/demo-page.component.ts - 35 + 32 @@ -1932,6 +1936,10 @@ Overview Visão geral + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 7 + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 114 @@ -1950,11 +1958,11 @@ apps/client/src/app/pages/admin/admin-page.component.ts - 48 + 45 apps/client/src/app/pages/resources/resources-page.component.ts - 30 + 29 libs/common/src/lib/routes/routes.ts @@ -1970,7 +1978,7 @@ Mercados apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 378 + 381 apps/client/src/app/components/footer/footer.component.html @@ -1994,7 +2002,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 40 + 39 libs/common/src/lib/routes/routes.ts @@ -2022,7 +2030,7 @@ apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 115 + 113 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -2042,11 +2050,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 342 + 348 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 75 + 94 apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -2074,7 +2082,7 @@ Current week apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 191 + 197 @@ -2118,7 +2126,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 124 + 120 @@ -2126,7 +2134,7 @@ Preço por Unidade apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 214 + 210 libs/ui/src/lib/activities-table/activities-table.component.html @@ -2138,7 +2146,7 @@ Nota apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 432 + 435 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -2146,7 +2154,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 275 + 271 @@ -2154,7 +2162,7 @@ A importar dados... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 175 + 174 @@ -2162,7 +2170,7 @@ A importação foi concluída apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 185 + 184 @@ -2282,7 +2290,7 @@ apps/client/src/app/pages/public/public-page.html - 151 + 150 @@ -2306,7 +2314,7 @@ apps/client/src/app/pages/public/public-page.html - 168 + 167 @@ -2314,7 +2322,7 @@ Latest activities apps/client/src/app/pages/public/public-page.html - 211 + 210 @@ -2326,7 +2334,7 @@ apps/client/src/app/pages/public/public-page.html - 177 + 176 @@ -2338,7 +2346,7 @@ apps/client/src/app/pages/public/public-page.html - 186 + 185 @@ -2358,7 +2366,7 @@ Mensalmente apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 91 + 90 @@ -2482,7 +2490,7 @@ Continentes apps/client/src/app/pages/public/public-page.html - 132 + 131 @@ -2498,7 +2506,7 @@ O Ghostfolio permite-lhe estar a par e gerir a sua riqueza. apps/client/src/app/pages/public/public-page.html - 238 + 237 @@ -2526,7 +2534,7 @@ apps/client/src/app/pages/public/public-page.html - 242 + 241 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -2580,6 +2588,10 @@ apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html 88 + + libs/ui/src/lib/value/value.component.html + 18 + Resources @@ -2698,7 +2710,7 @@ Deseja realmente eliminar esta atividade? libs/ui/src/lib/activities-table/activities-table.component.ts - 288 + 292 @@ -2750,11 +2762,11 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 352 + 359 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 387 + 414 libs/ui/src/lib/i18n.ts @@ -2766,7 +2778,7 @@ Poupanças libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 397 + 424 @@ -2802,7 +2814,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 326 + 327 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -2810,7 +2822,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 290 + 286 libs/ui/src/lib/i18n.ts @@ -2826,7 +2838,7 @@ Fundo de Emergência apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 164 + 168 apps/client/src/app/pages/features/features-page.html @@ -2846,7 +2858,7 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 437 + 451 @@ -2854,7 +2866,7 @@ Símbolo apps/client/src/app/components/admin-jobs/admin-jobs.html - 68 + 77 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -2870,7 +2882,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 315 + 318 libs/ui/src/lib/i18n.ts @@ -2894,7 +2906,7 @@ Dinheiro apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 212 + 219 libs/ui/src/lib/i18n.ts @@ -2942,7 +2954,7 @@ Authentication apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 35 + 54 @@ -3074,7 +3086,7 @@ apps/client/src/app/pages/public/public-page.html - 196 + 195 libs/ui/src/lib/benchmark/benchmark.component.html @@ -3082,11 +3094,11 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 439 + 453 libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 452 + 467 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -3114,7 +3126,7 @@ Mapeamento de Símbolo apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 384 + 387 @@ -3130,7 +3142,7 @@ Dados de Mercado apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 398 + 403 libs/common/src/lib/routes/routes.ts @@ -3154,7 +3166,7 @@ A validar dados... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 299 + 293 @@ -3170,7 +3182,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 71 + 67 @@ -3194,7 +3206,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 365 + 372 apps/client/src/app/pages/features/features-page.html @@ -3202,11 +3214,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 202 + 198 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 76 + 75 libs/ui/src/lib/i18n.ts @@ -3234,7 +3246,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 342 + 343 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -3242,7 +3254,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 309 + 305 libs/ui/src/lib/i18n.ts @@ -3274,7 +3286,7 @@ Anualmente apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 92 + 91 @@ -3282,7 +3294,7 @@ Importar Dividendos apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 137 + 136 libs/ui/src/lib/activities-table/activities-table.component.html @@ -3298,7 +3310,7 @@ Válido até apps/client/src/app/components/admin-settings/admin-settings.component.html - 74 + 86 libs/ui/src/lib/membership-card/membership-card.component.html @@ -3337,6 +3349,14 @@ 22 + + No Activities + No Activities + + apps/client/src/app/components/admin-market-data/admin-market-data.component.ts + 145 + + Retirement Provision Provisão de Reforma @@ -3610,11 +3630,11 @@ Could not save asset profile apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 588 + 604 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 591 + 607 @@ -3634,7 +3654,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 88 + 92 @@ -3798,7 +3818,7 @@ Deseja mesmo eliminar estas atividades? libs/ui/src/lib/activities-table/activities-table.component.ts - 278 + 282 @@ -3809,6 +3829,14 @@ 306 + + Explore + Explore + + apps/client/src/app/pages/resources/overview/resources-overview.component.html + 11 + + By By @@ -3830,7 +3858,7 @@ Current year apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 199 + 205 @@ -3846,11 +3874,11 @@ Url apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 419 + 422 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 550 + 553 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -3866,7 +3894,7 @@ Asset profile has been saved apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 578 + 594 @@ -3874,7 +3902,7 @@ Deseja mesmo eliminar esta plataforma? apps/client/src/app/components/admin-platform/admin-platform.component.ts - 106 + 111 @@ -3882,7 +3910,7 @@ Plataformas apps/client/src/app/components/admin-settings/admin-settings.component.html - 195 + 212 @@ -3890,7 +3918,7 @@ Atualizar saldo em Dinheiro apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 112 + 108 @@ -4070,7 +4098,7 @@ Responsabilidades apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 295 + 302 apps/client/src/app/pages/features/features-page.html @@ -4226,7 +4254,7 @@ Configuração do raspador apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 471 + 474 @@ -4470,7 +4498,7 @@ ETFs sem países apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 136 + 135 @@ -4478,7 +4506,7 @@ ETFs sem setores apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 141 + 140 @@ -4486,7 +4514,7 @@ Ativos apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 233 @@ -4658,7 +4686,7 @@ Job ID apps/client/src/app/components/admin-jobs/admin-jobs.html - 34 + 43 @@ -4714,11 +4742,11 @@ Moedas apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 131 + 130 apps/client/src/app/pages/public/public-page.html - 96 + 95 @@ -4766,11 +4794,11 @@ Could not parse scraper configuration apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 509 + 525 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 512 + 528 @@ -5432,7 +5460,7 @@ Taxa apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 262 + 258 libs/ui/src/lib/activities-table/activities-table.component.html @@ -5464,7 +5492,7 @@ Você realmente deseja excluir esta tag? apps/client/src/app/components/admin-tag/admin-tag.component.ts - 103 + 108 @@ -5532,7 +5560,7 @@ Associação apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 48 + 67 libs/common/src/lib/routes/routes.ts @@ -5564,7 +5592,7 @@ Perfil de ativos apps/client/src/app/components/admin-jobs/admin-jobs.html - 52 + 61 @@ -5688,7 +5716,7 @@ Ops! Não foi possível analisar os dados históricos. libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.ts - 262 + 284 @@ -5696,7 +5724,7 @@ Você realmente deseja excluir esta mensagem do sistema? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 206 + 209 @@ -5720,7 +5748,7 @@ Saldos de caixa apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 148 + 146 @@ -5740,7 +5768,7 @@ Você realmente deseja excluir o saldo desta conta? libs/ui/src/lib/account-balances/account-balances.component.ts - 120 + 113 @@ -5756,7 +5784,7 @@ O preço de mercado atual é apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 706 + 722 @@ -5764,7 +5792,7 @@ Teste apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 568 + 571 @@ -5852,11 +5880,11 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 81 + 80 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 97 + 96 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -5876,7 +5904,7 @@ Close Holding apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 442 + 447 @@ -5916,7 +5944,7 @@ Semana até agora libs/ui/src/lib/assistant/assistant.component.ts - 367 + 366 @@ -5924,11 +5952,11 @@ WTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 191 + 197 libs/ui/src/lib/assistant/assistant.component.ts - 367 + 366 @@ -5936,7 +5964,7 @@ Do mês até a data libs/ui/src/lib/assistant/assistant.component.ts - 371 + 370 @@ -5944,11 +5972,11 @@ MTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 195 + 201 libs/ui/src/lib/assistant/assistant.component.ts - 371 + 370 @@ -5956,7 +5984,7 @@ No acumulado do ano libs/ui/src/lib/assistant/assistant.component.ts - 375 + 374 @@ -5992,7 +6020,7 @@ ano apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 203 + 209 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -6004,7 +6032,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 385 + 384 @@ -6012,11 +6040,11 @@ anos apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 207 + 213 libs/ui/src/lib/assistant/assistant.component.ts - 409 + 408 @@ -6032,7 +6060,7 @@ Coleta de dados apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 587 + 594 apps/client/src/app/components/admin-overview/admin-overview.html @@ -6044,7 +6072,7 @@ geral apps/client/src/app/pages/faq/faq-page.component.ts - 49 + 41 @@ -6052,7 +6080,7 @@ Nuvem apps/client/src/app/pages/faq/faq-page.component.ts - 54 + 46 libs/common/src/lib/routes/routes.ts @@ -6064,7 +6092,7 @@ Auto-hospedagem apps/client/src/app/pages/faq/faq-page.component.ts - 60 + 52 libs/common/src/lib/routes/routes.ts @@ -6105,7 +6133,7 @@ Ativo apps/client/src/app/components/home-holdings/home-holdings.component.ts - 64 + 63 @@ -6113,7 +6141,7 @@ Fechado apps/client/src/app/components/home-holdings/home-holdings.component.ts - 65 + 64 @@ -6145,7 +6173,7 @@ Executar trabalho apps/client/src/app/components/admin-jobs/admin-jobs.html - 220 + 229 @@ -6153,7 +6181,7 @@ Prioridade apps/client/src/app/components/admin-jobs/admin-jobs.html - 96 + 105 @@ -6209,7 +6237,7 @@ Você realmente deseja encerrar sua conta Ghostfolio? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 208 + 205 @@ -6257,7 +6285,7 @@ Include in apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 374 + 377 @@ -6265,7 +6293,7 @@ Ops! Ocorreu um erro ao configurar a autenticação biométrica. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 336 + 333 @@ -6281,7 +6309,7 @@ Referências apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 126 + 125 @@ -6329,7 +6357,7 @@ Você gostaria de refinar seu estratégia de investimento pessoal? apps/client/src/app/pages/public/public-page.html - 234 + 233 @@ -6661,7 +6689,7 @@ Erro apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 697 + 713 @@ -6713,7 +6741,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 592 + 599 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6745,7 +6773,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 345 + 341 apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html @@ -6753,7 +6781,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 46 + 47 libs/ui/src/lib/i18n.ts @@ -6765,7 +6793,7 @@ Fechar apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 594 + 601 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6791,13 +6819,17 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 68 + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 127 + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html 107 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 347 + 343 libs/ui/src/lib/i18n.ts @@ -6809,7 +6841,7 @@ Role apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 14 + 33 @@ -6833,7 +6865,7 @@ Visão geral do portfólio apps/client/src/app/components/admin-jobs/admin-jobs.html - 56 + 65 @@ -6900,6 +6932,14 @@ 42 + + has been copied to the clipboard + has been copied to the clipboard + + libs/ui/src/lib/value/value.component.ts + 180 + + From the beginning Desde o início @@ -7065,7 +7105,7 @@ Definir chave de API apps/client/src/app/components/admin-settings/admin-settings.component.html - 171 + 188 @@ -7101,7 +7141,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 45 + 44 libs/common/src/lib/routes/routes.ts @@ -7117,7 +7157,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 34 + 33 libs/common/src/lib/routes/routes.ts @@ -7171,7 +7211,7 @@ de apps/client/src/app/components/admin-settings/admin-settings.component.html - 135 + 152 @@ -7179,7 +7219,7 @@ solicitações diárias apps/client/src/app/components/admin-settings/admin-settings.component.html - 137 + 154 @@ -7187,7 +7227,7 @@ Remover chave de API apps/client/src/app/components/admin-settings/admin-settings.component.html - 161 + 178 @@ -7195,7 +7235,7 @@ Você realmente deseja excluir a chave de API? apps/client/src/app/components/admin-settings/admin-settings.component.ts - 127 + 133 @@ -7215,7 +7255,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 98 + 117 @@ -7287,7 +7327,7 @@ Guardar apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 603 + 610 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7323,11 +7363,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 356 + 352 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 48 + 49 @@ -7339,7 +7379,7 @@ apps/client/src/app/components/user-account-access/user-account-access.component.ts - 260 + 257 @@ -7363,7 +7403,7 @@ Please enter your Ghostfolio API key. apps/client/src/app/components/admin-settings/admin-settings.component.ts - 146 + 152 @@ -7379,7 +7419,7 @@ AI prompt has been copied to the clipboard apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 201 + 199 @@ -7395,7 +7435,7 @@ Lazy apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 225 + 231 @@ -7403,7 +7443,7 @@ Instant apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 229 + 235 @@ -7411,7 +7451,7 @@ Preço de mercado padrão apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 481 + 484 @@ -7419,7 +7459,7 @@ Mode apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 518 + 521 @@ -7427,7 +7467,7 @@ Selector apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 534 + 537 @@ -7435,7 +7475,7 @@ HTTP Request Headers apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 494 + 497 @@ -7443,7 +7483,7 @@ end of day apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 225 + 231 @@ -7451,7 +7491,7 @@ real-time apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 229 + 235 @@ -7459,7 +7499,7 @@ Open Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 202 + 200 @@ -7479,7 +7519,7 @@ libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 377 @@ -7491,7 +7531,7 @@ apps/client/src/app/components/home-overview/home-overview.component.ts - 55 + 54 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -7499,11 +7539,11 @@ libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 377 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 381 + 390 @@ -7607,11 +7647,11 @@ Security token apps/client/src/app/components/admin-users/admin-users.component.ts - 236 + 235 apps/client/src/app/components/user-account-access/user-account-access.component.ts - 170 + 167 @@ -7619,7 +7659,7 @@ Do you really want to generate a new security token for this user? apps/client/src/app/components/admin-users/admin-users.component.ts - 241 + 240 @@ -7627,7 +7667,7 @@ Find account, holding or page... libs/ui/src/lib/assistant/assistant.component.ts - 151 + 115 @@ -7692,7 +7732,7 @@ () is already in use. apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 633 + 649 @@ -7700,7 +7740,7 @@ An error occurred while updating to (). apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 641 + 657 @@ -7764,7 +7804,7 @@ someone apps/client/src/app/pages/public/public-page.component.ts - 59 + 61 @@ -7796,7 +7836,7 @@ Do you really want to delete this item? libs/ui/src/lib/benchmark/benchmark.component.ts - 144 + 139 @@ -7837,7 +7877,7 @@ Demo user account has been synced. apps/client/src/app/components/admin-overview/admin-overview.component.ts - 274 + 277 @@ -7872,7 +7912,7 @@ 150 - + Fee Ratio Fee Ratio @@ -7880,17 +7920,17 @@ 152 - - The fees do exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - The fees do exceed ${thresholdMax}% of your initial investment (${feeRatio}%) + + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 154 - - The fees do not exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - The fees do not exceed ${thresholdMax}% of your initial investment (${feeRatio}%) + + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 158 @@ -8051,7 +8091,7 @@ Current month apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 195 + 201 @@ -8059,11 +8099,11 @@ new apps/client/src/app/components/admin-settings/admin-settings.component.html - 67 + 79 apps/client/src/app/pages/admin/admin-page.component.ts - 56 + 53 @@ -8220,7 +8260,7 @@ Do you really want to generate a new security token? apps/client/src/app/components/user-account-access/user-account-access.component.ts - 175 + 172 @@ -8244,7 +8284,7 @@ Stocks apps/client/src/app/components/markets/markets.component.ts - 52 + 51 apps/client/src/app/pages/features/features-page.html @@ -8256,7 +8296,7 @@ Criptomoedas apps/client/src/app/components/markets/markets.component.ts - 53 + 52 apps/client/src/app/pages/features/features-page.html @@ -8276,7 +8316,7 @@ Gerenciar perfil de ativos apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 466 + 471 @@ -8696,7 +8736,7 @@ Registration Date apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 26 + 45 diff --git a/apps/client/src/locales/messages.tr.xlf b/apps/client/src/locales/messages.tr.xlf index 421ef3855..e4547a2de 100644 --- a/apps/client/src/locales/messages.tr.xlf +++ b/apps/client/src/locales/messages.tr.xlf @@ -223,7 +223,7 @@ Tip apps/client/src/app/components/admin-jobs/admin-jobs.html - 48 + 57 apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html @@ -311,7 +311,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 309 + 310 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -323,7 +323,7 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 46 + 58 apps/client/src/app/components/admin-tag/admin-tag.component.html @@ -339,7 +339,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 139 + 135 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -383,7 +383,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 316 + 317 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -395,7 +395,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 145 + 141 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -415,15 +415,15 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 205 + 201 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 208 + 204 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 211 + 207 libs/ui/src/lib/account-balances/account-balances.component.html @@ -471,11 +471,11 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 74 + 78 apps/client/src/app/components/admin-tag/admin-tag.component.html - 67 + 71 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -503,11 +503,15 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 85 + 89 apps/client/src/app/components/admin-tag/admin-tag.component.html - 78 + 82 + + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 22 libs/ui/src/lib/account-balances/account-balances.component.html @@ -531,7 +535,7 @@ Bu hesabı silmeyi gerçekten istiyor musunuz? libs/ui/src/lib/accounts-table/accounts-table.component.ts - 150 + 148 @@ -539,7 +543,7 @@ Veri Kaynağı apps/client/src/app/components/admin-jobs/admin-jobs.html - 82 + 91 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -551,7 +555,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 155 + 151 libs/ui/src/lib/i18n.ts @@ -563,7 +567,7 @@ Deneme apps/client/src/app/components/admin-jobs/admin-jobs.html - 120 + 129 @@ -571,7 +575,7 @@ Oluşturuldu apps/client/src/app/components/admin-jobs/admin-jobs.html - 134 + 143 @@ -579,7 +583,7 @@ Tamamlandı apps/client/src/app/components/admin-jobs/admin-jobs.html - 143 + 152 @@ -587,11 +591,11 @@ Durum apps/client/src/app/components/admin-jobs/admin-jobs.html - 152 + 161 apps/client/src/app/components/admin-settings/admin-settings.component.html - 92 + 104 @@ -607,7 +611,7 @@ İşleri Sil apps/client/src/app/components/admin-jobs/admin-jobs.html - 193 + 202 @@ -615,7 +619,7 @@ Varlık Profili apps/client/src/app/components/admin-settings/admin-settings.component.html - 106 + 123 libs/ui/src/lib/assistant/assistant.html @@ -627,11 +631,11 @@ Tarihsel Piyasa Verisi apps/client/src/app/components/admin-jobs/admin-jobs.html - 54 + 63 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 448 + 451 @@ -639,7 +643,7 @@ Veri Gör apps/client/src/app/components/admin-jobs/admin-jobs.html - 208 + 217 @@ -647,7 +651,7 @@ Hata İzini Görüntüle apps/client/src/app/components/admin-jobs/admin-jobs.html - 216 + 225 @@ -655,7 +659,7 @@ İşleri Sil apps/client/src/app/components/admin-jobs/admin-jobs.html - 224 + 233 @@ -671,7 +675,7 @@ Tarih apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 161 + 157 libs/ui/src/lib/account-balances/account-balances.component.html @@ -707,11 +711,11 @@ Para Birimleri apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 131 + 130 apps/client/src/app/pages/public/public-page.html - 96 + 95 @@ -719,7 +723,7 @@ Ülkesi Olmayan ETF’ler apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 136 + 135 @@ -727,7 +731,7 @@ Sektörü Olmayan ETF’ler apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 141 + 140 @@ -735,7 +739,7 @@ Filtrele... apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 385 + 383 @@ -775,7 +779,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 44 + 40 @@ -843,7 +847,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 53 + 72 @@ -855,7 +859,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 396 + 399 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -863,7 +867,7 @@ apps/client/src/app/pages/public/public-page.html - 114 + 113 @@ -875,7 +879,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 407 + 410 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -887,7 +891,7 @@ Sembol Eşleştirme apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 384 + 387 @@ -903,7 +907,7 @@ Veri Toplayıcı Yapılandırması apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 471 + 474 @@ -911,7 +915,7 @@ Not apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 432 + 435 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -919,7 +923,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 275 + 271 @@ -947,7 +951,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 124 + 120 @@ -955,7 +959,7 @@ Bu kuponu gerçekten silmek istiyor musunuz? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 193 + 196 @@ -963,7 +967,7 @@ Önbelleği temizlemeyi gerçekten istiyor musunuz? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 230 + 233 @@ -971,7 +975,7 @@ Lütfen sistem mesajınızı belirleyin: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 250 + 253 @@ -1011,7 +1015,7 @@ Etiketler apps/client/src/app/components/admin-settings/admin-settings.component.html - 201 + 218 libs/ui/src/lib/tags-selector/tags-selector.component.html @@ -1103,11 +1107,11 @@ Url apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 419 + 422 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 550 + 553 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -1123,7 +1127,7 @@ Asset profile has been saved apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 578 + 594 @@ -1131,7 +1135,15 @@ Bu platformu silmeyi gerçekten istiyor musunuz? apps/client/src/app/components/admin-platform/admin-platform.component.ts - 106 + 111 + + + + Explore + Explore + + apps/client/src/app/pages/resources/overview/resources-overview.component.html + 11 @@ -1155,7 +1167,7 @@ Current year apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 199 + 205 @@ -1171,7 +1183,7 @@ Platformlar apps/client/src/app/components/admin-settings/admin-settings.component.html - 195 + 212 @@ -1215,7 +1227,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 89 + 108 @@ -1247,11 +1259,11 @@ Could not validate form apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 554 + 570 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 557 + 573 @@ -1299,7 +1311,7 @@ Karşılaştırma Ölçütü apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 376 + 379 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -1335,7 +1347,7 @@ apps/client/src/app/components/header/header.component.ts - 297 + 298 apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html @@ -1355,15 +1367,15 @@ Hay Allah! Güvenlik anahtarı yanlış. apps/client/src/app/components/header/header.component.ts - 312 + 313 apps/client/src/app/components/user-account-access/user-account-access.component.ts - 154 + 152 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 193 + 191 @@ -1371,7 +1383,7 @@ İşlemleri Yönet apps/client/src/app/components/home-holdings/home-holdings.html - 67 + 64 @@ -1379,11 +1391,11 @@ Korku apps/client/src/app/components/home-market/home-market.component.ts - 42 + 41 apps/client/src/app/components/markets/markets.component.ts - 47 + 46 libs/ui/src/lib/i18n.ts @@ -1395,11 +1407,11 @@ Açgözlülük apps/client/src/app/components/home-market/home-market.component.ts - 43 + 42 apps/client/src/app/components/markets/markets.component.ts - 48 + 47 libs/ui/src/lib/i18n.ts @@ -1503,7 +1515,7 @@ Current week apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 191 + 197 @@ -1523,7 +1535,7 @@ Toplam Tutar apps/client/src/app/components/investment-chart/investment-chart.component.ts - 143 + 146 @@ -1635,7 +1647,7 @@ Toplam Brüt Performans apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 73 + 77 @@ -1643,7 +1655,7 @@ Toplam Net Performans apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 107 + 111 apps/client/src/app/pages/portfolio/analysis/analysis-page.html @@ -1655,7 +1667,7 @@ Net Performans apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 123 + 127 apps/client/src/app/pages/portfolio/analysis/analysis-page.html @@ -1667,7 +1679,7 @@ Toplam Varlıklar apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 149 + 153 @@ -1675,7 +1687,7 @@ Varlıklar apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 233 @@ -1683,7 +1695,7 @@ Alım Limiti apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 241 + 248 @@ -1691,7 +1703,7 @@ Analize Dahil Edilmemiştir. apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 267 + 274 @@ -1699,7 +1711,7 @@ Yükümlülükler apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 295 + 302 apps/client/src/app/pages/features/features-page.html @@ -1711,7 +1723,7 @@ Toplam Varlık apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 317 + 324 @@ -1719,7 +1731,7 @@ Yıllıklandırılmış Performans apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 331 + 338 @@ -1755,7 +1767,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 189 + 185 libs/ui/src/lib/activities-table/activities-table.component.html @@ -1775,7 +1787,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 88 + 92 @@ -1783,7 +1795,7 @@ Rapor Veri Sorunu apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 451 + 456 @@ -1963,7 +1975,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 363 + 362 @@ -1971,11 +1983,11 @@ YTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 199 + 205 libs/ui/src/lib/assistant/assistant.component.ts - 375 + 374 @@ -1983,11 +1995,11 @@ 1Y apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 203 + 209 libs/ui/src/lib/assistant/assistant.component.ts - 385 + 384 @@ -1995,11 +2007,11 @@ 5Y apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 207 + 213 libs/ui/src/lib/assistant/assistant.component.ts - 409 + 408 @@ -2015,11 +2027,11 @@ Maks. apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 211 + 217 libs/ui/src/lib/assistant/assistant.component.ts - 415 + 414 @@ -2043,7 +2055,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 195 + 194 @@ -2055,7 +2067,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 193 + 192 @@ -2071,7 +2083,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 196 + 195 @@ -2199,11 +2211,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 375 + 381 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 66 + 85 apps/client/src/app/pages/accounts/accounts-page.html @@ -2263,7 +2275,7 @@ Piyasa Verileri apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 398 + 403 libs/common/src/lib/routes/routes.ts @@ -2297,6 +2309,10 @@ Overview Özet + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 7 + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 114 @@ -2315,11 +2331,11 @@ apps/client/src/app/pages/admin/admin-page.component.ts - 48 + 45 apps/client/src/app/pages/resources/resources-page.component.ts - 30 + 29 libs/common/src/lib/routes/routes.ts @@ -2443,11 +2459,11 @@ Could not parse scraper configuration apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 509 + 525 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 512 + 528 @@ -2463,7 +2479,7 @@ Oturum açmış olduğunuz için demo hesabına erişemezsiniz. apps/client/src/app/pages/demo/demo-page.component.ts - 35 + 32 @@ -2647,7 +2663,7 @@ apps/client/src/app/pages/public/public-page.html - 242 + 241 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -2699,7 +2715,7 @@ Piyasalar apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 378 + 381 apps/client/src/app/components/footer/footer.component.html @@ -2723,7 +2739,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 40 + 39 libs/common/src/lib/routes/routes.ts @@ -3087,7 +3103,7 @@ Job ID apps/client/src/app/components/admin-jobs/admin-jobs.html - 34 + 43 @@ -3115,7 +3131,7 @@ apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 115 + 113 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -3135,11 +3151,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 342 + 348 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 75 + 94 apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -3159,7 +3175,7 @@ Tüm işlemlerinizi silmeyi gerçekten istiyor musunuz? libs/ui/src/lib/activities-table/activities-table.component.ts - 278 + 282 @@ -3203,7 +3219,7 @@ Nakit Bakiyesini Güncelle apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 112 + 108 @@ -3211,7 +3227,7 @@ Birim Fiyat apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 214 + 210 libs/ui/src/lib/activities-table/activities-table.component.html @@ -3239,7 +3255,7 @@ Temettüleri İçe Aktar apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 137 + 136 libs/ui/src/lib/activities-table/activities-table.component.html @@ -3255,7 +3271,7 @@ Veri içe aktarılıyor... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 175 + 174 @@ -3263,7 +3279,7 @@ İçe aktarma tamamlandı apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 185 + 184 @@ -3279,7 +3295,7 @@ Veri doğrulanıyor... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 299 + 293 @@ -3367,7 +3383,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 71 + 67 @@ -3459,7 +3475,7 @@ apps/client/src/app/pages/public/public-page.html - 151 + 150 @@ -3483,7 +3499,7 @@ apps/client/src/app/pages/public/public-page.html - 168 + 167 @@ -3491,7 +3507,7 @@ Latest activities apps/client/src/app/pages/public/public-page.html - 211 + 210 @@ -3503,7 +3519,7 @@ apps/client/src/app/pages/public/public-page.html - 177 + 176 @@ -3515,7 +3531,7 @@ apps/client/src/app/pages/public/public-page.html - 186 + 185 @@ -3575,7 +3591,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 365 + 372 apps/client/src/app/pages/features/features-page.html @@ -3583,11 +3599,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 202 + 198 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 76 + 75 libs/ui/src/lib/i18n.ts @@ -3607,7 +3623,7 @@ Para Yatırma libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 377 + 404 @@ -3615,7 +3631,7 @@ Aylık apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 91 + 90 @@ -3623,7 +3639,7 @@ Yıllık apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 92 + 91 @@ -3903,11 +3919,11 @@ Could not save asset profile apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 588 + 604 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 591 + 607 @@ -3931,7 +3947,7 @@ Kıtalar apps/client/src/app/pages/public/public-page.html - 132 + 131 @@ -3947,7 +3963,7 @@ Ghostfolio, varlıklarınızı takip etmenizi sağlar. apps/client/src/app/pages/public/public-page.html - 238 + 237 @@ -3997,6 +4013,10 @@ apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html 88 + + libs/ui/src/lib/value/value.component.html + 18 + Personal Finance Tools @@ -4336,7 +4356,7 @@ Otomatik apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 70 + 69 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -4380,7 +4400,7 @@ Bu giriş yöntemini kaldırmayı gerçekten istiyor musunuz? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 282 + 279 @@ -4388,7 +4408,7 @@ Geçerli tarih apps/client/src/app/components/admin-settings/admin-settings.component.html - 74 + 86 libs/ui/src/lib/membership-card/membership-card.component.html @@ -4468,7 +4488,7 @@ Yerel Ayarlar apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 512 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -4568,7 +4588,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 11 + 30 @@ -4664,7 +4684,7 @@ TBu işlemi silmeyi gerçekten istiyor musunuz? libs/ui/src/lib/activities-table/activities-table.component.ts - 288 + 292 @@ -4740,11 +4760,11 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 352 + 359 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 387 + 414 libs/ui/src/lib/i18n.ts @@ -4756,7 +4776,7 @@ Tasarruflar libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 397 + 424 @@ -4784,7 +4804,7 @@ Tümünü göster libs/ui/src/lib/holdings-table/holdings-table.component.html - 216 + 212 @@ -4828,7 +4848,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 326 + 327 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -4836,7 +4856,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 290 + 286 libs/ui/src/lib/i18n.ts @@ -4860,7 +4880,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 342 + 343 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -4868,7 +4888,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 309 + 305 libs/ui/src/lib/i18n.ts @@ -4912,7 +4932,7 @@ Acil Durum Fonu apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 164 + 168 apps/client/src/app/pages/features/features-page.html @@ -4988,7 +5008,7 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 437 + 451 @@ -4999,6 +5019,14 @@ 27 + + No Activities + No Activities + + apps/client/src/app/components/admin-market-data/admin-market-data.component.ts + 145 + + Retirement Provision Yaşlılık Provizyonu @@ -5028,7 +5056,7 @@ Sembol apps/client/src/app/components/admin-jobs/admin-jobs.html - 68 + 77 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -5044,7 +5072,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 315 + 318 libs/ui/src/lib/i18n.ts @@ -5144,7 +5172,7 @@ Nakit apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 212 + 219 libs/ui/src/lib/i18n.ts @@ -5192,7 +5220,7 @@ Authentication apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 35 + 54 @@ -5324,7 +5352,7 @@ apps/client/src/app/pages/public/public-page.html - 196 + 195 libs/ui/src/lib/benchmark/benchmark.component.html @@ -5332,11 +5360,11 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 439 + 453 libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 452 + 467 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -5440,7 +5468,7 @@ Ücret apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 262 + 258 libs/ui/src/lib/activities-table/activities-table.component.html @@ -5464,7 +5492,7 @@ Bu etiketi silmeyi gerçekten istiyor musunuz? apps/client/src/app/components/admin-tag/admin-tag.component.ts - 103 + 108 @@ -5532,7 +5560,7 @@ Üyelik apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 48 + 67 libs/common/src/lib/routes/routes.ts @@ -5564,7 +5592,7 @@ Varlık Profili apps/client/src/app/components/admin-jobs/admin-jobs.html - 52 + 61 @@ -5688,7 +5716,7 @@ Hay Allah! Geçmiş veriler ayrıştırılamadı. libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.ts - 262 + 284 @@ -5696,7 +5724,7 @@ Bu sistem mesajını silmeyi gerçekten istiyor musunuz? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 206 + 209 @@ -5720,7 +5748,7 @@ Nakit Bakiyeleri apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 148 + 146 @@ -5740,7 +5768,7 @@ Bu nakit bakiyesini silmeyi gerçekten istiyor musunuz? libs/ui/src/lib/account-balances/account-balances.component.ts - 120 + 113 @@ -5756,7 +5784,7 @@ Şu anki piyasa fiyatı apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 706 + 722 @@ -5764,7 +5792,7 @@ Test apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 568 + 571 @@ -5852,11 +5880,11 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 81 + 80 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 97 + 96 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -5876,7 +5904,7 @@ Close Holding apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 442 + 447 @@ -5916,7 +5944,7 @@ Hafta içi libs/ui/src/lib/assistant/assistant.component.ts - 367 + 366 @@ -5924,11 +5952,11 @@ WTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 191 + 197 libs/ui/src/lib/assistant/assistant.component.ts - 367 + 366 @@ -5936,7 +5964,7 @@ Ay içi libs/ui/src/lib/assistant/assistant.component.ts - 371 + 370 @@ -5944,11 +5972,11 @@ MTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 195 + 201 libs/ui/src/lib/assistant/assistant.component.ts - 371 + 370 @@ -5956,7 +5984,7 @@ Yıl içi libs/ui/src/lib/assistant/assistant.component.ts - 375 + 374 @@ -5992,7 +6020,7 @@ Yıl apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 203 + 209 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -6004,7 +6032,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 385 + 384 @@ -6012,11 +6040,11 @@ Yıllar apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 207 + 213 libs/ui/src/lib/assistant/assistant.component.ts - 409 + 408 @@ -6032,7 +6060,7 @@ Veri Toplama apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 587 + 594 apps/client/src/app/components/admin-overview/admin-overview.html @@ -6044,7 +6072,7 @@ Genel apps/client/src/app/pages/faq/faq-page.component.ts - 49 + 41 @@ -6052,7 +6080,7 @@ Bulut apps/client/src/app/pages/faq/faq-page.component.ts - 54 + 46 libs/common/src/lib/routes/routes.ts @@ -6064,7 +6092,7 @@ Kendini Barındırma apps/client/src/app/pages/faq/faq-page.component.ts - 60 + 52 libs/common/src/lib/routes/routes.ts @@ -6105,7 +6133,7 @@ Aktif apps/client/src/app/components/home-holdings/home-holdings.component.ts - 64 + 63 @@ -6113,7 +6141,7 @@ Kapalı apps/client/src/app/components/home-holdings/home-holdings.component.ts - 65 + 64 @@ -6145,7 +6173,7 @@ İşlemi Yürüt apps/client/src/app/components/admin-jobs/admin-jobs.html - 220 + 229 @@ -6153,7 +6181,7 @@ Öncelik apps/client/src/app/components/admin-jobs/admin-jobs.html - 96 + 105 @@ -6209,7 +6237,7 @@ Ghostfolio hesabınızı kapatmak istediğinize emin misiniz? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 208 + 205 @@ -6257,7 +6285,7 @@ Include in apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 374 + 377 @@ -6265,7 +6293,7 @@ Oops! Biyometrik kimlik doğrulama ayarlanırken bir hata oluştu. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 336 + 333 @@ -6281,7 +6309,7 @@ Kıyaslamalar apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 126 + 125 @@ -6329,7 +6357,7 @@ Senin özel yatırım stratejinizi iyileştirmek ister misin? apps/client/src/app/pages/public/public-page.html - 234 + 233 @@ -6661,7 +6689,7 @@ Hata apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 697 + 713 @@ -6713,7 +6741,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 592 + 599 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6745,7 +6773,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 345 + 341 apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html @@ -6753,7 +6781,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 46 + 47 libs/ui/src/lib/i18n.ts @@ -6765,7 +6793,7 @@ Kapat apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 594 + 601 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6791,13 +6819,17 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 68 + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 127 + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html 107 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 347 + 343 libs/ui/src/lib/i18n.ts @@ -6809,7 +6841,7 @@ Role apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 14 + 33 @@ -6833,7 +6865,7 @@ Portföy Anlık Görüntüsü apps/client/src/app/components/admin-jobs/admin-jobs.html - 56 + 65 @@ -6900,6 +6932,14 @@ 42 + + has been copied to the clipboard + has been copied to the clipboard + + libs/ui/src/lib/value/value.component.ts + 180 + + From the beginning Başlangıçtan beri @@ -7065,7 +7105,7 @@ API anahtarını ayarla apps/client/src/app/components/admin-settings/admin-settings.component.html - 171 + 188 @@ -7101,7 +7141,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 45 + 44 libs/common/src/lib/routes/routes.ts @@ -7117,7 +7157,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 34 + 33 libs/common/src/lib/routes/routes.ts @@ -7171,7 +7211,7 @@ ın apps/client/src/app/components/admin-settings/admin-settings.component.html - 135 + 152 @@ -7179,7 +7219,7 @@ günlük istekler apps/client/src/app/components/admin-settings/admin-settings.component.html - 137 + 154 @@ -7187,7 +7227,7 @@ API anahtarını kaldır apps/client/src/app/components/admin-settings/admin-settings.component.html - 161 + 178 @@ -7195,7 +7235,7 @@ API anahtarını silmek istediğinize emin misiniz? apps/client/src/app/components/admin-settings/admin-settings.component.ts - 127 + 133 @@ -7215,7 +7255,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 98 + 117 @@ -7287,7 +7327,7 @@ Kaydet apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 603 + 610 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7323,11 +7363,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 356 + 352 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 48 + 49 @@ -7339,7 +7379,7 @@ apps/client/src/app/components/user-account-access/user-account-access.component.ts - 260 + 257 @@ -7363,7 +7403,7 @@ Lütfen Ghostfolio API anahtarınızı girin. apps/client/src/app/components/admin-settings/admin-settings.component.ts - 146 + 152 @@ -7379,7 +7419,7 @@ Yapay zeka istemi panoya kopyalandı apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 201 + 199 @@ -7395,7 +7435,7 @@ Tembel apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 225 + 231 @@ -7403,7 +7443,7 @@ Anında apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 229 + 235 @@ -7411,7 +7451,7 @@ Varsayılan Piyasa Fiyatı apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 481 + 484 @@ -7419,7 +7459,7 @@ Mod apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 518 + 521 @@ -7427,7 +7467,7 @@ Seçici apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 534 + 537 @@ -7435,7 +7475,7 @@ HTTP İstek Başlıkları apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 494 + 497 @@ -7443,7 +7483,7 @@ gün sonu apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 225 + 231 @@ -7451,7 +7491,7 @@ gerçek zamanlı apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 229 + 235 @@ -7459,7 +7499,7 @@ Duck.ai’yi aç apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 202 + 200 @@ -7479,7 +7519,7 @@ libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 377 @@ -7491,7 +7531,7 @@ apps/client/src/app/components/home-overview/home-overview.component.ts - 55 + 54 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -7499,11 +7539,11 @@ libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 377 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 381 + 390 @@ -7607,11 +7647,11 @@ Güvenlik belirteci apps/client/src/app/components/admin-users/admin-users.component.ts - 236 + 235 apps/client/src/app/components/user-account-access/user-account-access.component.ts - 170 + 167 @@ -7619,7 +7659,7 @@ Bu kullanıcı için yeni bir güvenlik belirteci oluşturmak istediğinize emin misiniz? apps/client/src/app/components/admin-users/admin-users.component.ts - 241 + 240 @@ -7627,7 +7667,7 @@ Find account, holding or page... libs/ui/src/lib/assistant/assistant.component.ts - 151 + 115 @@ -7692,7 +7732,7 @@ () is already in use. apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 633 + 649 @@ -7700,7 +7740,7 @@ Güncelleştirilirken bir hata oluştu (). apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 641 + 657 @@ -7764,7 +7804,7 @@ birisi apps/client/src/app/pages/public/public-page.component.ts - 59 + 61 @@ -7796,7 +7836,7 @@ Bu öğeyi silmek istediğinize emin misiniz? libs/ui/src/lib/benchmark/benchmark.component.ts - 144 + 139 @@ -7837,7 +7877,7 @@ Demo kullanıcı hesabı senkronize edildi. apps/client/src/app/components/admin-overview/admin-overview.component.ts - 274 + 277 @@ -7872,25 +7912,25 @@ 150 - + Fee Ratio - Ücret Oranı + Fee Ratio apps/client/src/app/pages/i18n/i18n-page.html 152 - - The fees do exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - Ücretler, ilk yatırımınızın %${thresholdMax} kadarını aşıyor (${feeRatio}%) + + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 154 - - The fees do not exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - Ücretler, ilk yatırımınızın %${thresholdMax}’ını (${feeRatio}%) aşmaz + + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 158 @@ -8051,7 +8091,7 @@ Current month apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 195 + 201 @@ -8059,11 +8099,11 @@ yeni apps/client/src/app/components/admin-settings/admin-settings.component.html - 67 + 79 apps/client/src/app/pages/admin/admin-page.component.ts - 56 + 53 @@ -8220,7 +8260,7 @@ Do you really want to generate a new security token? apps/client/src/app/components/user-account-access/user-account-access.component.ts - 175 + 172 @@ -8244,7 +8284,7 @@ Stocks apps/client/src/app/components/markets/markets.component.ts - 52 + 51 apps/client/src/app/pages/features/features-page.html @@ -8256,7 +8296,7 @@ Cryptocurrencies apps/client/src/app/components/markets/markets.component.ts - 53 + 52 apps/client/src/app/pages/features/features-page.html @@ -8276,7 +8316,7 @@ Manage Asset Profile apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 466 + 471 @@ -8696,7 +8736,7 @@ Registration Date apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 26 + 45 diff --git a/apps/client/src/locales/messages.uk.xlf b/apps/client/src/locales/messages.uk.xlf index 2fc389030..12b5c2bc3 100644 --- a/apps/client/src/locales/messages.uk.xlf +++ b/apps/client/src/locales/messages.uk.xlf @@ -38,7 +38,7 @@ apps/client/src/app/components/header/header.component.ts - 297 + 298 apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html @@ -419,7 +419,7 @@ Баланс готівки apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 148 + 146 @@ -443,7 +443,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 309 + 310 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -455,7 +455,7 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 46 + 58 apps/client/src/app/components/admin-tag/admin-tag.component.html @@ -471,7 +471,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 139 + 135 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -515,7 +515,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 316 + 317 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -527,7 +527,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 145 + 141 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -547,15 +547,15 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 205 + 201 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 208 + 204 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 211 + 207 libs/ui/src/lib/account-balances/account-balances.component.html @@ -603,11 +603,11 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 74 + 78 apps/client/src/app/components/admin-tag/admin-tag.component.html - 67 + 71 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -635,11 +635,15 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 85 + 89 apps/client/src/app/components/admin-tag/admin-tag.component.html - 78 + 82 + + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 22 libs/ui/src/lib/account-balances/account-balances.component.html @@ -663,7 +667,7 @@ Ви дійсно хочете видалити цей обліковий запис? libs/ui/src/lib/accounts-table/accounts-table.component.ts - 150 + 148 @@ -671,7 +675,7 @@ Тип apps/client/src/app/components/admin-jobs/admin-jobs.html - 48 + 57 apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html @@ -691,7 +695,7 @@ Профіль активу apps/client/src/app/components/admin-jobs/admin-jobs.html - 52 + 61 @@ -699,11 +703,11 @@ Історичні ринкові дані apps/client/src/app/components/admin-jobs/admin-jobs.html - 54 + 63 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 448 + 451 @@ -711,7 +715,7 @@ Знімок портфеля apps/client/src/app/components/admin-jobs/admin-jobs.html - 56 + 65 @@ -719,7 +723,7 @@ Джерело даних apps/client/src/app/components/admin-jobs/admin-jobs.html - 82 + 91 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -731,7 +735,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 155 + 151 libs/ui/src/lib/i18n.ts @@ -743,7 +747,7 @@ Пріоритет apps/client/src/app/components/admin-jobs/admin-jobs.html - 96 + 105 @@ -751,7 +755,7 @@ Спроби apps/client/src/app/components/admin-jobs/admin-jobs.html - 120 + 129 @@ -759,7 +763,7 @@ Створено apps/client/src/app/components/admin-jobs/admin-jobs.html - 134 + 143 @@ -767,7 +771,7 @@ Завершено apps/client/src/app/components/admin-jobs/admin-jobs.html - 143 + 152 @@ -775,11 +779,11 @@ Статус apps/client/src/app/components/admin-jobs/admin-jobs.html - 152 + 161 apps/client/src/app/components/admin-settings/admin-settings.component.html - 92 + 104 @@ -795,7 +799,7 @@ Видалити завдання apps/client/src/app/components/admin-jobs/admin-jobs.html - 193 + 202 @@ -803,7 +807,7 @@ Переглянути дані apps/client/src/app/components/admin-jobs/admin-jobs.html - 208 + 217 @@ -811,7 +815,7 @@ Переглянути трасування apps/client/src/app/components/admin-jobs/admin-jobs.html - 216 + 225 @@ -819,7 +823,7 @@ Виконати завдання apps/client/src/app/components/admin-jobs/admin-jobs.html - 220 + 229 @@ -827,7 +831,7 @@ Видалити завдання apps/client/src/app/components/admin-jobs/admin-jobs.html - 224 + 233 @@ -835,7 +839,7 @@ Порівняльні показники apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 126 + 125 @@ -843,11 +847,11 @@ Валюти apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 131 + 130 apps/client/src/app/pages/public/public-page.html - 96 + 95 @@ -855,7 +859,7 @@ ETF без країн apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 136 + 135 @@ -863,7 +867,7 @@ ETF без секторів apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 141 + 140 @@ -871,7 +875,7 @@ Фільтрувати за... apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 385 + 383 @@ -927,7 +931,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 44 + 40 @@ -995,7 +999,7 @@ Помилка apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 697 + 713 @@ -1003,7 +1007,7 @@ Поточна ринкова ціна apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 706 + 722 @@ -1043,7 +1047,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 53 + 72 @@ -1055,7 +1059,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 396 + 399 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -1063,7 +1067,7 @@ apps/client/src/app/pages/public/public-page.html - 114 + 113 @@ -1075,7 +1079,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 407 + 410 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -1087,7 +1091,7 @@ Зіставлення символів apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 384 + 387 @@ -1103,7 +1107,7 @@ Конфігурація скребка apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 471 + 474 @@ -1111,7 +1115,7 @@ Тест apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 568 + 571 @@ -1119,11 +1123,11 @@ URL apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 419 + 422 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 550 + 553 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -1139,7 +1143,7 @@ Asset profile has been saved apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 578 + 594 @@ -1147,7 +1151,7 @@ Примітка apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 432 + 435 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1155,7 +1159,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 275 + 271 @@ -1207,7 +1211,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 124 + 120 @@ -1223,7 +1227,7 @@ Ви дійсно хочете видалити цей купон? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 193 + 196 @@ -1231,7 +1235,7 @@ Ви дійсно хочете видалити це системне повідомлення? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 206 + 209 @@ -1239,7 +1243,7 @@ Ви дійсно хочете очистити кеш? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 230 + 233 @@ -1247,7 +1251,7 @@ Будь ласка, встановіть ваше системне повідомлення: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 250 + 253 @@ -1303,7 +1307,7 @@ Збір даних apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 587 + 594 apps/client/src/app/components/admin-overview/admin-overview.html @@ -1375,7 +1379,15 @@ Ви дійсно хочете видалити цю платформу? apps/client/src/app/components/admin-platform/admin-platform.component.ts - 106 + 111 + + + + Explore + Explore + + apps/client/src/app/pages/resources/overview/resources-overview.component.html + 11 @@ -1399,7 +1411,7 @@ Current year apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 199 + 205 @@ -1423,7 +1435,7 @@ Дійсне до apps/client/src/app/components/admin-settings/admin-settings.component.html - 74 + 86 libs/ui/src/lib/membership-card/membership-card.component.html @@ -1435,7 +1447,7 @@ з apps/client/src/app/components/admin-settings/admin-settings.component.html - 135 + 152 @@ -1443,7 +1455,7 @@ щоденних запитів apps/client/src/app/components/admin-settings/admin-settings.component.html - 137 + 154 @@ -1451,7 +1463,7 @@ Вилучити ключ API apps/client/src/app/components/admin-settings/admin-settings.component.html - 161 + 178 @@ -1459,7 +1471,7 @@ Встановити ключ API apps/client/src/app/components/admin-settings/admin-settings.component.html - 171 + 188 @@ -1467,7 +1479,7 @@ Платформи apps/client/src/app/components/admin-settings/admin-settings.component.html - 195 + 212 @@ -1475,7 +1487,7 @@ Теги apps/client/src/app/components/admin-settings/admin-settings.component.html - 201 + 218 libs/ui/src/lib/tags-selector/tags-selector.component.html @@ -1491,7 +1503,7 @@ Ви дійсно хочете видалити ключ API? apps/client/src/app/components/admin-settings/admin-settings.component.ts - 127 + 133 @@ -1499,7 +1511,7 @@ Будь ласка, введіть ваш ключ API Ghostfolio. apps/client/src/app/components/admin-settings/admin-settings.component.ts - 146 + 152 @@ -1583,7 +1595,7 @@ Ви дійсно хочете видалити цей тег? apps/client/src/app/components/admin-tag/admin-tag.component.ts - 103 + 108 @@ -1619,7 +1631,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 89 + 108 @@ -1631,7 +1643,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 98 + 117 @@ -1663,11 +1675,11 @@ Could not validate form apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 554 + 570 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 557 + 573 @@ -1715,7 +1727,7 @@ Порівняльний показник apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 376 + 379 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -1791,15 +1803,15 @@ Упс! Неправильний Секретний Токен. apps/client/src/app/components/header/header.component.ts - 312 + 313 apps/client/src/app/components/user-account-access/user-account-access.component.ts - 154 + 152 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 193 + 191 @@ -1851,7 +1863,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 189 + 185 libs/ui/src/lib/activities-table/activities-table.component.html @@ -1879,7 +1891,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 88 + 92 @@ -1903,7 +1915,7 @@ Повідомити про збій даних apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 451 + 456 @@ -1911,7 +1923,7 @@ Активний apps/client/src/app/components/home-holdings/home-holdings.component.ts - 64 + 63 @@ -1919,7 +1931,7 @@ Закритий apps/client/src/app/components/home-holdings/home-holdings.component.ts - 65 + 64 @@ -1943,7 +1955,7 @@ Керування діяльністю apps/client/src/app/components/home-holdings/home-holdings.html - 67 + 64 @@ -1951,11 +1963,11 @@ Страх apps/client/src/app/components/home-market/home-market.component.ts - 42 + 41 apps/client/src/app/components/markets/markets.component.ts - 47 + 46 libs/ui/src/lib/i18n.ts @@ -1967,11 +1979,11 @@ Жадібність apps/client/src/app/components/home-market/home-market.component.ts - 43 + 42 apps/client/src/app/components/markets/markets.component.ts - 48 + 47 libs/ui/src/lib/i18n.ts @@ -2075,7 +2087,7 @@ Current week apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 191 + 197 @@ -2095,7 +2107,7 @@ Загальна сума apps/client/src/app/components/investment-chart/investment-chart.component.ts - 143 + 146 @@ -2187,7 +2199,7 @@ Абсолютний валовий дохід apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 73 + 77 @@ -2195,7 +2207,7 @@ Абсолютний чистий прибуток apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 107 + 111 apps/client/src/app/pages/portfolio/analysis/analysis-page.html @@ -2207,7 +2219,7 @@ Чистий прибуток apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 123 + 127 apps/client/src/app/pages/portfolio/analysis/analysis-page.html @@ -2219,7 +2231,7 @@ Загальні активи apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 149 + 153 @@ -2227,7 +2239,7 @@ Активи apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 233 @@ -2235,7 +2247,7 @@ Купівельна спроможність apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 241 + 248 @@ -2243,7 +2255,7 @@ Виключено з аналізу apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 267 + 274 @@ -2251,7 +2263,7 @@ Зобов’язання apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 295 + 302 apps/client/src/app/pages/features/features-page.html @@ -2263,7 +2275,7 @@ Чиста вартість apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 317 + 324 @@ -2271,7 +2283,7 @@ Річна доходність apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 331 + 338 @@ -2279,7 +2291,7 @@ Зберегти apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 603 + 610 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -2315,11 +2327,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 356 + 352 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 48 + 49 @@ -2551,7 +2563,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 363 + 362 @@ -2559,11 +2571,11 @@ З початку року apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 199 + 205 libs/ui/src/lib/assistant/assistant.component.ts - 375 + 374 @@ -2571,11 +2583,11 @@ 1 рік apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 203 + 209 libs/ui/src/lib/assistant/assistant.component.ts - 385 + 384 @@ -2583,11 +2595,11 @@ 5 років apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 207 + 213 libs/ui/src/lib/assistant/assistant.component.ts - 409 + 408 @@ -2603,11 +2615,11 @@ Максимум apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 211 + 217 libs/ui/src/lib/assistant/assistant.component.ts - 415 + 414 @@ -2663,7 +2675,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 11 + 30 @@ -2675,7 +2687,7 @@ apps/client/src/app/components/user-account-access/user-account-access.component.ts - 260 + 257 @@ -2723,7 +2735,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 196 + 195 @@ -2823,7 +2835,7 @@ Автоматичний apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 70 + 69 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -2835,7 +2847,7 @@ Ви дійсно хочете закрити ваш обліковий запис Ghostfolio? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 208 + 205 @@ -2843,7 +2855,7 @@ Ви дійсно хочете вилучити цей спосіб входу? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 282 + 279 @@ -2851,7 +2863,7 @@ Include in apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 374 + 377 @@ -2859,7 +2871,7 @@ Упс! Виникла помилка під час налаштування біометричної автентифікації. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 336 + 333 @@ -2907,7 +2919,7 @@ Локалізація apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 512 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -3051,7 +3063,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 195 + 194 @@ -3071,7 +3083,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 193 + 192 @@ -3207,11 +3219,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 375 + 381 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 66 + 85 apps/client/src/app/pages/accounts/accounts-page.html @@ -3311,7 +3323,7 @@ Ринкові дані apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 398 + 403 libs/common/src/lib/routes/routes.ts @@ -3345,6 +3357,10 @@ Overview Огляд + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 7 + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 114 @@ -3363,11 +3379,11 @@ apps/client/src/app/pages/admin/admin-page.component.ts - 48 + 45 apps/client/src/app/pages/resources/resources-page.component.ts - 30 + 29 libs/common/src/lib/routes/routes.ts @@ -3499,11 +3515,11 @@ Could not parse scraper configuration apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 509 + 525 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 512 + 528 @@ -3519,7 +3535,7 @@ Оскільки ви вже ввійшли, ви не можете отримати доступ до демонстраційного обліковий запис. apps/client/src/app/pages/demo/demo-page.component.ts - 35 + 32 @@ -3547,7 +3563,7 @@ Загальні apps/client/src/app/pages/faq/faq-page.component.ts - 49 + 41 @@ -3555,7 +3571,7 @@ Хмара apps/client/src/app/pages/faq/faq-page.component.ts - 54 + 46 libs/common/src/lib/routes/routes.ts @@ -3567,7 +3583,7 @@ Самохостинг apps/client/src/app/pages/faq/faq-page.component.ts - 60 + 52 libs/common/src/lib/routes/routes.ts @@ -3716,7 +3732,7 @@ apps/client/src/app/pages/public/public-page.html - 242 + 241 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -3768,7 +3784,7 @@ Ринки apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 378 + 381 apps/client/src/app/components/footer/footer.component.html @@ -3792,7 +3808,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 40 + 39 libs/common/src/lib/routes/routes.ts @@ -4240,7 +4256,7 @@ Job ID apps/client/src/app/components/admin-jobs/admin-jobs.html - 34 + 43 @@ -4276,7 +4292,7 @@ apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 115 + 113 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -4296,11 +4312,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 342 + 348 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 75 + 94 apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -4380,7 +4396,7 @@ Оновити баланс готівки apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 112 + 108 @@ -4388,7 +4404,7 @@ Дата apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 161 + 157 libs/ui/src/lib/account-balances/account-balances.component.html @@ -4408,7 +4424,7 @@ Ціна за одиницю apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 214 + 210 libs/ui/src/lib/activities-table/activities-table.component.html @@ -4436,7 +4452,7 @@ Імпорт дивідендів apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 137 + 136 libs/ui/src/lib/activities-table/activities-table.component.html @@ -4452,7 +4468,7 @@ Імпортуються дані... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 175 + 174 @@ -4460,7 +4476,7 @@ Імпорт завершено apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 185 + 184 @@ -4476,7 +4492,7 @@ Перевірка даних... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 299 + 293 @@ -4572,7 +4588,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 71 + 67 @@ -4664,7 +4680,7 @@ apps/client/src/app/pages/public/public-page.html - 151 + 150 @@ -4688,7 +4704,7 @@ apps/client/src/app/pages/public/public-page.html - 168 + 167 @@ -4696,7 +4712,7 @@ Latest activities apps/client/src/app/pages/public/public-page.html - 211 + 210 @@ -4708,7 +4724,7 @@ apps/client/src/app/pages/public/public-page.html - 177 + 176 @@ -4720,7 +4736,7 @@ apps/client/src/app/pages/public/public-page.html - 186 + 185 @@ -4796,7 +4812,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 365 + 372 apps/client/src/app/pages/features/features-page.html @@ -4804,11 +4820,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 202 + 198 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 76 + 75 libs/ui/src/lib/i18n.ts @@ -4828,11 +4844,11 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 81 + 80 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 97 + 96 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -4852,7 +4868,7 @@ Щомісячно apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 91 + 90 @@ -4860,7 +4876,7 @@ Щорічно apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 92 + 91 @@ -4868,7 +4884,7 @@ Close Holding apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 442 + 447 @@ -5204,11 +5220,11 @@ Could not save asset profile apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 588 + 604 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 591 + 607 @@ -5235,6 +5251,14 @@ 42 + + has been copied to the clipboard + has been copied to the clipboard + + libs/ui/src/lib/value/value.component.ts + 180 + + From the beginning З початку @@ -5248,7 +5272,7 @@ Континенти apps/client/src/app/pages/public/public-page.html - 132 + 131 @@ -5256,7 +5280,7 @@ Чи хотіли б ви удосконалити вашу особисту інвестиційну стратегію? apps/client/src/app/pages/public/public-page.html - 234 + 233 @@ -5272,7 +5296,7 @@ Ghostfolio надає можливість вам стежити за вашим багатством. apps/client/src/app/pages/public/public-page.html - 238 + 237 @@ -5302,6 +5326,10 @@ apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html 88 + + libs/ui/src/lib/value/value.component.html + 18 + Glossary @@ -5312,7 +5340,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 45 + 44 libs/common/src/lib/routes/routes.ts @@ -5328,7 +5356,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 34 + 33 libs/common/src/lib/routes/routes.ts @@ -6003,7 +6031,7 @@ Членство apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 48 + 67 libs/common/src/lib/routes/routes.ts @@ -6071,7 +6099,7 @@ Ви дійсно хочете видалити цей рахунок? libs/ui/src/lib/account-balances/account-balances.component.ts - 120 + 113 @@ -6135,7 +6163,7 @@ Ви дійсно хочете видалити ці дії? libs/ui/src/lib/activities-table/activities-table.component.ts - 278 + 282 @@ -6143,7 +6171,7 @@ Ви дійсно хочете видалити цю активність? libs/ui/src/lib/activities-table/activities-table.component.ts - 288 + 292 @@ -6151,7 +6179,7 @@ Тиждень до дати libs/ui/src/lib/assistant/assistant.component.ts - 367 + 366 @@ -6159,11 +6187,11 @@ WTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 191 + 197 libs/ui/src/lib/assistant/assistant.component.ts - 367 + 366 @@ -6171,7 +6199,7 @@ Місяць до дати libs/ui/src/lib/assistant/assistant.component.ts - 371 + 370 @@ -6179,11 +6207,11 @@ MTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 195 + 201 libs/ui/src/lib/assistant/assistant.component.ts - 371 + 370 @@ -6191,7 +6219,7 @@ Рік до дати libs/ui/src/lib/assistant/assistant.component.ts - 375 + 374 @@ -6199,7 +6227,7 @@ рік apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 203 + 209 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -6211,7 +6239,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 385 + 384 @@ -6219,11 +6247,11 @@ роки apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 207 + 213 libs/ui/src/lib/assistant/assistant.component.ts - 409 + 408 @@ -6231,7 +6259,7 @@ Профілі активів apps/client/src/app/components/admin-settings/admin-settings.component.html - 106 + 123 libs/ui/src/lib/assistant/assistant.html @@ -6371,7 +6399,7 @@ Депозит libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 377 + 404 @@ -6383,11 +6411,11 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 352 + 359 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 387 + 414 libs/ui/src/lib/i18n.ts @@ -6399,7 +6427,7 @@ Заощадження libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 397 + 424 @@ -6415,7 +6443,7 @@ Упс! Не вдалося отримати історичні дані. libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.ts - 262 + 284 @@ -6443,7 +6471,7 @@ Показати все libs/ui/src/lib/holdings-table/holdings-table.component.html - 216 + 212 @@ -6487,7 +6515,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 326 + 327 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -6495,7 +6523,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 290 + 286 libs/ui/src/lib/i18n.ts @@ -6519,7 +6547,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 342 + 343 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -6527,7 +6555,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 309 + 305 libs/ui/src/lib/i18n.ts @@ -6551,7 +6579,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 592 + 599 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6583,7 +6611,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 345 + 341 apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html @@ -6591,7 +6619,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 46 + 47 libs/ui/src/lib/i18n.ts @@ -6611,7 +6639,7 @@ Закрити apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 594 + 601 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6637,13 +6665,17 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 68 + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 127 + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html 107 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 347 + 343 libs/ui/src/lib/i18n.ts @@ -6679,7 +6711,7 @@ Резервний фонд apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 164 + 168 apps/client/src/app/pages/features/features-page.html @@ -6747,7 +6779,7 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 437 + 451 @@ -6766,6 +6798,14 @@ 27 + + No Activities + No Activities + + apps/client/src/app/components/admin-market-data/admin-market-data.component.ts + 145 + + Retirement Provision Пенсійне накопичення @@ -6795,7 +6835,7 @@ Символ apps/client/src/app/components/admin-jobs/admin-jobs.html - 68 + 77 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -6811,7 +6851,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 315 + 318 libs/ui/src/lib/i18n.ts @@ -6863,7 +6903,7 @@ Role apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 14 + 33 @@ -6899,7 +6939,7 @@ Комісія apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 262 + 258 libs/ui/src/lib/activities-table/activities-table.component.html @@ -6943,7 +6983,7 @@ Готівка apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 212 + 219 libs/ui/src/lib/i18n.ts @@ -6999,7 +7039,7 @@ Authentication apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 35 + 54 @@ -7339,7 +7379,7 @@ apps/client/src/app/pages/public/public-page.html - 196 + 195 libs/ui/src/lib/benchmark/benchmark.component.html @@ -7347,11 +7387,11 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 439 + 453 libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 452 + 467 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -7387,7 +7427,7 @@ Запит AI скопійовано в буфер обміну apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 201 + 199 @@ -7395,7 +7435,7 @@ Lazy apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 225 + 231 @@ -7403,7 +7443,7 @@ Instant apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 229 + 235 @@ -7411,7 +7451,7 @@ Default Market Price apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 481 + 484 @@ -7419,7 +7459,7 @@ Mode apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 518 + 521 @@ -7427,7 +7467,7 @@ Selector apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 534 + 537 @@ -7435,7 +7475,7 @@ HTTP Request Headers apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 494 + 497 @@ -7443,7 +7483,7 @@ end of day apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 225 + 231 @@ -7451,7 +7491,7 @@ real-time apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 229 + 235 @@ -7459,7 +7499,7 @@ Open Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 202 + 200 @@ -7479,7 +7519,7 @@ libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 377 @@ -7491,7 +7531,7 @@ apps/client/src/app/components/home-overview/home-overview.component.ts - 55 + 54 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -7499,11 +7539,11 @@ libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 377 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 381 + 390 @@ -7607,11 +7647,11 @@ Security token apps/client/src/app/components/admin-users/admin-users.component.ts - 236 + 235 apps/client/src/app/components/user-account-access/user-account-access.component.ts - 170 + 167 @@ -7619,7 +7659,7 @@ Do you really want to generate a new security token for this user? apps/client/src/app/components/admin-users/admin-users.component.ts - 241 + 240 @@ -7627,7 +7667,7 @@ Find account, holding or page... libs/ui/src/lib/assistant/assistant.component.ts - 151 + 115 @@ -7692,7 +7732,7 @@ () is already in use. apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 633 + 649 @@ -7700,7 +7740,7 @@ An error occurred while updating to (). apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 641 + 657 @@ -7764,7 +7804,7 @@ someone apps/client/src/app/pages/public/public-page.component.ts - 59 + 61 @@ -7796,7 +7836,7 @@ Do you really want to delete this item? libs/ui/src/lib/benchmark/benchmark.component.ts - 144 + 139 @@ -7837,7 +7877,7 @@ Demo user account has been synced. apps/client/src/app/components/admin-overview/admin-overview.component.ts - 274 + 277 @@ -7872,7 +7912,7 @@ 150 - + Fee Ratio Fee Ratio @@ -7880,17 +7920,17 @@ 152 - - The fees do exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - The fees do exceed ${thresholdMax}% of your initial investment (${feeRatio}%) + + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 154 - - The fees do not exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - The fees do not exceed ${thresholdMax}% of your initial investment (${feeRatio}%) + + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 158 @@ -8051,7 +8091,7 @@ Current month apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 195 + 201 @@ -8059,11 +8099,11 @@ new apps/client/src/app/components/admin-settings/admin-settings.component.html - 67 + 79 apps/client/src/app/pages/admin/admin-page.component.ts - 56 + 53 @@ -8220,7 +8260,7 @@ Do you really want to generate a new security token? apps/client/src/app/components/user-account-access/user-account-access.component.ts - 175 + 172 @@ -8244,7 +8284,7 @@ Stocks apps/client/src/app/components/markets/markets.component.ts - 52 + 51 apps/client/src/app/pages/features/features-page.html @@ -8256,7 +8296,7 @@ Cryptocurrencies apps/client/src/app/components/markets/markets.component.ts - 53 + 52 apps/client/src/app/pages/features/features-page.html @@ -8276,7 +8316,7 @@ Manage Asset Profile apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 466 + 471 @@ -8696,7 +8736,7 @@ Registration Date apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 26 + 45 diff --git a/apps/client/src/locales/messages.xlf b/apps/client/src/locales/messages.xlf index a6907698d..fa9e6b874 100644 --- a/apps/client/src/locales/messages.xlf +++ b/apps/client/src/locales/messages.xlf @@ -235,7 +235,7 @@ Type apps/client/src/app/components/admin-jobs/admin-jobs.html - 48 + 57 apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html @@ -312,7 +312,7 @@ Cash Balances apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 148 + 146 @@ -334,7 +334,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 309 + 310 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -346,7 +346,7 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 46 + 58 apps/client/src/app/components/admin-tag/admin-tag.component.html @@ -362,7 +362,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 139 + 135 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -404,7 +404,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 316 + 317 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -416,7 +416,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 145 + 141 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -435,15 +435,15 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 205 + 201 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 208 + 204 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 211 + 207 libs/ui/src/lib/account-balances/account-balances.component.html @@ -490,11 +490,11 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 74 + 78 apps/client/src/app/components/admin-tag/admin-tag.component.html - 67 + 71 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -521,11 +521,15 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 85 + 89 apps/client/src/app/components/admin-tag/admin-tag.component.html - 78 + 82 + + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 22 libs/ui/src/lib/account-balances/account-balances.component.html @@ -548,32 +552,32 @@ Do you really want to delete this account? libs/ui/src/lib/accounts-table/accounts-table.component.ts - 150 + 148 Asset Profile apps/client/src/app/components/admin-jobs/admin-jobs.html - 52 + 61 Historical Market Data apps/client/src/app/components/admin-jobs/admin-jobs.html - 54 + 63 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 448 + 451 Data Source apps/client/src/app/components/admin-jobs/admin-jobs.html - 82 + 91 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -585,7 +589,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 155 + 151 libs/ui/src/lib/i18n.ts @@ -596,32 +600,32 @@ Attempts apps/client/src/app/components/admin-jobs/admin-jobs.html - 120 + 129 Created apps/client/src/app/components/admin-jobs/admin-jobs.html - 134 + 143 Finished apps/client/src/app/components/admin-jobs/admin-jobs.html - 143 + 152 Status apps/client/src/app/components/admin-jobs/admin-jobs.html - 152 + 161 apps/client/src/app/components/admin-settings/admin-settings.component.html - 92 + 104 @@ -635,28 +639,28 @@ Delete Jobs apps/client/src/app/components/admin-jobs/admin-jobs.html - 193 + 202 View Data apps/client/src/app/components/admin-jobs/admin-jobs.html - 208 + 217 View Stacktrace apps/client/src/app/components/admin-jobs/admin-jobs.html - 216 + 225 Delete Job apps/client/src/app/components/admin-jobs/admin-jobs.html - 224 + 233 @@ -670,7 +674,7 @@ Date apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 161 + 157 libs/ui/src/lib/account-balances/account-balances.component.html @@ -704,25 +708,25 @@ Currencies apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 131 + 130 apps/client/src/app/pages/public/public-page.html - 96 + 95 ETFs without Countries apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 136 + 135 ETFs without Sectors apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 141 + 140 @@ -736,7 +740,7 @@ Filter by... apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 385 + 383 @@ -773,7 +777,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 44 + 40 @@ -819,7 +823,7 @@ Oops! Could not parse historical data. libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.ts - 262 + 284 @@ -848,7 +852,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 71 + 67 @@ -878,7 +882,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 53 + 72 @@ -889,7 +893,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 396 + 399 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -897,7 +901,7 @@ apps/client/src/app/pages/public/public-page.html - 114 + 113 @@ -908,7 +912,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 407 + 410 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -919,7 +923,7 @@ Symbol Mapping apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 384 + 387 @@ -933,14 +937,14 @@ Scraper Configuration apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 471 + 474 Note apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 432 + 435 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -948,7 +952,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 275 + 271 @@ -988,35 +992,35 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 124 + 120 Do you really want to delete this coupon? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 193 + 196 Do you really want to delete this system message? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 206 + 209 Do you really want to flush the cache? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 230 + 233 Please set your system message: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 250 + 253 @@ -1125,11 +1129,11 @@ Url apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 419 + 422 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 550 + 553 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -1144,14 +1148,21 @@ Asset profile has been saved apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 578 + 594 Do you really want to delete this platform? apps/client/src/app/components/admin-platform/admin-platform.component.ts - 106 + 111 + + + + Explore + + apps/client/src/app/pages/resources/overview/resources-overview.component.html + 11 @@ -1172,7 +1183,7 @@ Current year apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 199 + 205 @@ -1186,14 +1197,14 @@ Platforms apps/client/src/app/components/admin-settings/admin-settings.component.html - 195 + 212 Tags apps/client/src/app/components/admin-settings/admin-settings.component.html - 201 + 218 libs/ui/src/lib/tags-selector/tags-selector.component.html @@ -1215,7 +1226,7 @@ Do you really want to delete this tag? apps/client/src/app/components/admin-tag/admin-tag.component.ts - 103 + 108 @@ -1269,7 +1280,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 89 + 108 @@ -1297,11 +1308,11 @@ Could not validate form apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 554 + 570 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 557 + 573 @@ -1345,7 +1356,7 @@ Benchmark apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 376 + 379 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -1378,7 +1389,7 @@ apps/client/src/app/components/header/header.component.ts - 297 + 298 apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html @@ -1397,33 +1408,33 @@ Oops! Incorrect Security Token. apps/client/src/app/components/header/header.component.ts - 312 + 313 apps/client/src/app/components/user-account-access/user-account-access.component.ts - 154 + 152 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 193 + 191 Manage Activities apps/client/src/app/components/home-holdings/home-holdings.html - 67 + 64 Fear apps/client/src/app/components/home-market/home-market.component.ts - 42 + 41 apps/client/src/app/components/markets/markets.component.ts - 47 + 46 libs/ui/src/lib/i18n.ts @@ -1434,11 +1445,11 @@ Greed apps/client/src/app/components/home-market/home-market.component.ts - 43 + 42 apps/client/src/app/components/markets/markets.component.ts - 48 + 47 libs/ui/src/lib/i18n.ts @@ -1530,7 +1541,7 @@ Current week apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 191 + 197 @@ -1548,7 +1559,7 @@ Total Amount apps/client/src/app/components/investment-chart/investment-chart.component.ts - 143 + 146 @@ -1653,7 +1664,7 @@ Absolute Gross Performance apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 73 + 77 @@ -1664,14 +1675,14 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 88 + 92 Absolute Net Performance apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 107 + 111 apps/client/src/app/pages/portfolio/analysis/analysis-page.html @@ -1682,7 +1693,7 @@ Net Performance apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 123 + 127 apps/client/src/app/pages/portfolio/analysis/analysis-page.html @@ -1693,35 +1704,35 @@ Total Assets apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 149 + 153 Assets apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 233 Buying Power apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 241 + 248 Excluded from Analysis apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 267 + 274 Liabilities apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 295 + 302 apps/client/src/app/pages/features/features-page.html @@ -1732,14 +1743,14 @@ Net Worth apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 317 + 324 Annualized Performance apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 331 + 338 @@ -1771,7 +1782,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 189 + 185 libs/ui/src/lib/activities-table/activities-table.component.html @@ -1786,7 +1797,7 @@ Report Data Glitch apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 451 + 456 @@ -1954,40 +1965,40 @@ libs/ui/src/lib/assistant/assistant.component.ts - 363 + 362 YTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 199 + 205 libs/ui/src/lib/assistant/assistant.component.ts - 375 + 374 1Y apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 203 + 209 libs/ui/src/lib/assistant/assistant.component.ts - 385 + 384 5Y apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 207 + 213 libs/ui/src/lib/assistant/assistant.component.ts - 409 + 408 @@ -2001,11 +2012,11 @@ Max apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 211 + 217 libs/ui/src/lib/assistant/assistant.component.ts - 415 + 414 @@ -2094,7 +2105,7 @@ Auto apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 70 + 69 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -2105,7 +2116,7 @@ Do you really want to remove this sign in method? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 282 + 279 @@ -2140,7 +2151,7 @@ Locale apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 512 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -2240,7 +2251,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 11 + 30 @@ -2269,7 +2280,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 195 + 194 @@ -2280,7 +2291,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 193 + 192 @@ -2295,7 +2306,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 196 + 195 @@ -2414,11 +2425,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 375 + 381 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 66 + 85 apps/client/src/app/pages/accounts/accounts-page.html @@ -2501,7 +2512,7 @@ Market Data apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 398 + 403 libs/common/src/lib/routes/routes.ts @@ -2532,6 +2543,10 @@ Overview + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 7 + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 114 @@ -2550,11 +2565,11 @@ apps/client/src/app/pages/admin/admin-page.component.ts - 48 + 45 apps/client/src/app/pages/resources/resources-page.component.ts - 30 + 29 libs/common/src/lib/routes/routes.ts @@ -2676,11 +2691,11 @@ Could not parse scraper configuration apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 509 + 525 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 512 + 528 @@ -2694,7 +2709,7 @@ As you are already logged in, you cannot access the demo account. apps/client/src/app/pages/demo/demo-page.component.ts - 35 + 32 @@ -2850,7 +2865,7 @@ apps/client/src/app/pages/public/public-page.html - 242 + 241 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -2899,7 +2914,7 @@ Markets apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 378 + 381 apps/client/src/app/components/footer/footer.component.html @@ -2923,7 +2938,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 40 + 39 libs/common/src/lib/routes/routes.ts @@ -3312,7 +3327,7 @@ Job ID apps/client/src/app/components/admin-jobs/admin-jobs.html - 34 + 43 @@ -3344,7 +3359,7 @@ apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 115 + 113 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -3364,11 +3379,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 342 + 348 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 75 + 94 apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -3387,7 +3402,7 @@ Do you really want to delete these activities? libs/ui/src/lib/activities-table/activities-table.component.ts - 278 + 282 @@ -3447,14 +3462,14 @@ Update Cash Balance apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 112 + 108 Unit Price apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 214 + 210 libs/ui/src/lib/activities-table/activities-table.component.html @@ -3480,7 +3495,7 @@ Import Dividends apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 137 + 136 libs/ui/src/lib/activities-table/activities-table.component.html @@ -3495,14 +3510,14 @@ Importing data... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 175 + 174 Import has been completed apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 185 + 184 @@ -3516,7 +3531,7 @@ Validating data... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 299 + 293 @@ -3669,7 +3684,7 @@ apps/client/src/app/pages/public/public-page.html - 151 + 150 @@ -3691,14 +3706,14 @@ apps/client/src/app/pages/public/public-page.html - 168 + 167 Latest activities apps/client/src/app/pages/public/public-page.html - 211 + 210 @@ -3709,7 +3724,7 @@ apps/client/src/app/pages/public/public-page.html - 177 + 176 @@ -3720,7 +3735,7 @@ apps/client/src/app/pages/public/public-page.html - 186 + 185 @@ -3774,7 +3789,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 365 + 372 apps/client/src/app/pages/features/features-page.html @@ -3782,11 +3797,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 202 + 198 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 76 + 75 libs/ui/src/lib/i18n.ts @@ -3804,21 +3819,21 @@ Deposit libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 377 + 404 Monthly apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 91 + 90 Yearly apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 92 + 91 @@ -4070,11 +4085,11 @@ Could not save asset profile apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 588 + 604 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 591 + 607 @@ -4095,7 +4110,7 @@ Continents apps/client/src/app/pages/public/public-page.html - 132 + 131 @@ -4109,7 +4124,7 @@ Ghostfolio empowers you to keep track of your wealth. apps/client/src/app/pages/public/public-page.html - 238 + 237 @@ -4136,6 +4151,10 @@ apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html 88 + + libs/ui/src/lib/value/value.component.html + 18 + Personal Finance Tools @@ -4448,7 +4467,7 @@ Membership apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 48 + 67 libs/common/src/lib/routes/routes.ts @@ -4509,7 +4528,7 @@ Do you really want to delete this account balance? libs/ui/src/lib/account-balances/account-balances.component.ts - 120 + 113 @@ -4559,14 +4578,14 @@ Do you really want to delete this activity? libs/ui/src/lib/activities-table/activities-table.component.ts - 288 + 292 Asset Profiles apps/client/src/app/components/admin-settings/admin-settings.component.html - 106 + 123 libs/ui/src/lib/assistant/assistant.html @@ -4665,11 +4684,11 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 352 + 359 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 387 + 414 libs/ui/src/lib/i18n.ts @@ -4680,7 +4699,7 @@ Savings libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 397 + 424 @@ -4706,7 +4725,7 @@ Show all libs/ui/src/lib/holdings-table/holdings-table.component.html - 216 + 212 @@ -4747,7 +4766,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 326 + 327 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -4755,7 +4774,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 290 + 286 libs/ui/src/lib/i18n.ts @@ -4778,7 +4797,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 342 + 343 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -4786,7 +4805,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 309 + 305 libs/ui/src/lib/i18n.ts @@ -4825,7 +4844,7 @@ Emergency Fund apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 164 + 168 apps/client/src/app/pages/features/features-page.html @@ -4893,7 +4912,7 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 437 + 451 @@ -4903,6 +4922,13 @@ 27 + + No Activities + + apps/client/src/app/components/admin-market-data/admin-market-data.component.ts + 145 + + Retirement Provision @@ -4921,7 +4947,7 @@ Symbol apps/client/src/app/components/admin-jobs/admin-jobs.html - 68 + 77 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -4937,7 +4963,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 315 + 318 libs/ui/src/lib/i18n.ts @@ -5002,7 +5028,7 @@ Fee apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 262 + 258 libs/ui/src/lib/activities-table/activities-table.component.html @@ -5042,7 +5068,7 @@ Cash apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 212 + 219 libs/ui/src/lib/i18n.ts @@ -5085,7 +5111,7 @@ Authentication apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 35 + 54 @@ -5211,7 +5237,7 @@ Valid until apps/client/src/app/components/admin-settings/admin-settings.component.html - 74 + 86 libs/ui/src/lib/membership-card/membership-card.component.html @@ -5233,7 +5259,7 @@ apps/client/src/app/pages/public/public-page.html - 196 + 195 libs/ui/src/lib/benchmark/benchmark.component.html @@ -5241,11 +5267,11 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 439 + 453 libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 452 + 467 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -5270,14 +5296,14 @@ The current market price is apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 706 + 722 Test apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 568 + 571 @@ -5348,7 +5374,7 @@ Close Holding apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 442 + 447 @@ -5370,11 +5396,11 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 81 + 80 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 97 + 96 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -5406,43 +5432,43 @@ Year to date libs/ui/src/lib/assistant/assistant.component.ts - 375 + 374 Week to date libs/ui/src/lib/assistant/assistant.component.ts - 367 + 366 Month to date libs/ui/src/lib/assistant/assistant.component.ts - 371 + 370 MTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 195 + 201 libs/ui/src/lib/assistant/assistant.component.ts - 371 + 370 WTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 191 + 197 libs/ui/src/lib/assistant/assistant.component.ts - 367 + 366 @@ -5474,7 +5500,7 @@ year apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 203 + 209 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -5486,18 +5512,18 @@ libs/ui/src/lib/assistant/assistant.component.ts - 385 + 384 years apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 207 + 213 libs/ui/src/lib/assistant/assistant.component.ts - 409 + 408 @@ -5523,7 +5549,7 @@ Self-Hosting apps/client/src/app/pages/faq/faq-page.component.ts - 60 + 52 libs/common/src/lib/routes/routes.ts @@ -5534,7 +5560,7 @@ Data Gathering apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 587 + 594 apps/client/src/app/components/admin-overview/admin-overview.html @@ -5545,14 +5571,14 @@ General apps/client/src/app/pages/faq/faq-page.component.ts - 49 + 41 Cloud apps/client/src/app/pages/faq/faq-page.component.ts - 54 + 46 libs/common/src/lib/routes/routes.ts @@ -5577,14 +5603,14 @@ Closed apps/client/src/app/components/home-holdings/home-holdings.component.ts - 65 + 64 Active apps/client/src/app/components/home-holdings/home-holdings.component.ts - 64 + 63 @@ -5612,7 +5638,7 @@ Execute Job apps/client/src/app/components/admin-jobs/admin-jobs.html - 220 + 229 @@ -5626,7 +5652,7 @@ Priority apps/client/src/app/components/admin-jobs/admin-jobs.html - 96 + 105 @@ -5675,7 +5701,7 @@ Do you really want to close your Ghostfolio account? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 208 + 205 @@ -5710,14 +5736,14 @@ Include in apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 374 + 377 Oops! There was an error setting up biometric authentication. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 336 + 333 @@ -5752,7 +5778,7 @@ Benchmarks apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 126 + 125 @@ -5773,7 +5799,7 @@ Would you like to refine your personal investment strategy? apps/client/src/app/pages/public/public-page.html - 234 + 233 @@ -6071,7 +6097,7 @@ Error apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 697 + 713 @@ -6082,7 +6108,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 592 + 599 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6114,7 +6140,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 345 + 341 apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html @@ -6122,7 +6148,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 46 + 47 libs/ui/src/lib/i18n.ts @@ -6133,7 +6159,7 @@ Role apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 14 + 33 @@ -6161,7 +6187,7 @@ Close apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 594 + 601 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6187,13 +6213,17 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 68 + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 127 + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html 107 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 347 + 343 libs/ui/src/lib/i18n.ts @@ -6246,7 +6276,7 @@ Portfolio Snapshot apps/client/src/app/components/admin-jobs/admin-jobs.html - 56 + 65 @@ -6298,6 +6328,13 @@ 42 + + has been copied to the clipboard + + libs/ui/src/lib/value/value.component.ts + 180 + + offers a free plan @@ -6439,7 +6476,7 @@ Set API key apps/client/src/app/components/admin-settings/admin-settings.component.html - 171 + 188 @@ -6471,7 +6508,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 45 + 44 libs/common/src/lib/routes/routes.ts @@ -6498,7 +6535,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 34 + 33 libs/common/src/lib/routes/routes.ts @@ -6542,28 +6579,28 @@ of apps/client/src/app/components/admin-settings/admin-settings.component.html - 135 + 152 Do you really want to delete the API key? apps/client/src/app/components/admin-settings/admin-settings.component.ts - 127 + 133 Remove API key apps/client/src/app/components/admin-settings/admin-settings.component.html - 161 + 178 daily requests apps/client/src/app/components/admin-settings/admin-settings.component.html - 137 + 154 @@ -6588,7 +6625,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 98 + 117 @@ -6637,7 +6674,7 @@ Save apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 603 + 610 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6673,11 +6710,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 356 + 352 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 48 + 49 @@ -6702,14 +6739,14 @@ apps/client/src/app/components/user-account-access/user-account-access.component.ts - 260 + 257 Please enter your Ghostfolio API key. apps/client/src/app/components/admin-settings/admin-settings.component.ts - 146 + 152 @@ -6723,7 +6760,7 @@ AI prompt has been copied to the clipboard apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 201 + 199 @@ -6737,63 +6774,63 @@ Mode apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 518 + 521 Default Market Price apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 481 + 484 Selector apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 534 + 537 Instant apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 229 + 235 Lazy apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 225 + 231 HTTP Request Headers apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 494 + 497 real-time apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 229 + 235 end of day apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 225 + 231 Open Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 202 + 200 @@ -6811,7 +6848,7 @@ libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 377 @@ -6822,7 +6859,7 @@ apps/client/src/app/components/home-overview/home-overview.component.ts - 55 + 54 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -6830,11 +6867,11 @@ libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 377 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 381 + 390 @@ -6925,25 +6962,25 @@ Do you really want to generate a new security token for this user? apps/client/src/app/components/admin-users/admin-users.component.ts - 241 + 240 Find account, holding or page... libs/ui/src/lib/assistant/assistant.component.ts - 151 + 115 Security token apps/client/src/app/components/admin-users/admin-users.component.ts - 236 + 235 apps/client/src/app/components/user-account-access/user-account-access.component.ts - 170 + 167 @@ -7001,14 +7038,14 @@ () is already in use. apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 633 + 649 An error occurred while updating to (). apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 641 + 657 @@ -7043,7 +7080,7 @@ someone apps/client/src/app/pages/public/public-page.component.ts - 59 + 61 @@ -7072,7 +7109,7 @@ Do you really want to delete this item? libs/ui/src/lib/benchmark/benchmark.component.ts - 144 + 139 @@ -7116,7 +7153,7 @@ Demo user account has been synced. apps/client/src/app/components/admin-overview/admin-overview.component.ts - 274 + 277 @@ -7140,22 +7177,22 @@ 150 - + Fee Ratio apps/client/src/app/pages/i18n/i18n-page.html 152 - - The fees do exceed ${thresholdMax}% of your initial investment (${feeRatio}%) + + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 154 - - The fees do not exceed ${thresholdMax}% of your initial investment (${feeRatio}%) + + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 158 @@ -7300,18 +7337,18 @@ Current month apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 195 + 201 new apps/client/src/app/components/admin-settings/admin-settings.component.html - 67 + 79 apps/client/src/app/pages/admin/admin-page.component.ts - 56 + 53 @@ -7463,14 +7500,14 @@ Do you really want to generate a new security token? apps/client/src/app/components/user-account-access/user-account-access.component.ts - 175 + 172 Cryptocurrencies apps/client/src/app/components/markets/markets.component.ts - 53 + 52 apps/client/src/app/pages/features/features-page.html @@ -7481,7 +7518,7 @@ Stocks apps/client/src/app/components/markets/markets.component.ts - 52 + 51 apps/client/src/app/pages/features/features-page.html @@ -7499,7 +7536,7 @@ Manage Asset Profile apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 466 + 471 @@ -7868,7 +7905,7 @@ Registration Date apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 26 + 45 diff --git a/apps/client/src/locales/messages.zh.xlf b/apps/client/src/locales/messages.zh.xlf index 7ec9d85a0..78c9b717d 100644 --- a/apps/client/src/locales/messages.zh.xlf +++ b/apps/client/src/locales/messages.zh.xlf @@ -252,7 +252,7 @@ 类型 apps/client/src/app/components/admin-jobs/admin-jobs.html - 48 + 57 apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html @@ -336,7 +336,7 @@ 现金余额 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 148 + 146 @@ -360,7 +360,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 309 + 310 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -372,7 +372,7 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 46 + 58 apps/client/src/app/components/admin-tag/admin-tag.component.html @@ -388,7 +388,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 139 + 135 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -432,7 +432,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 316 + 317 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -444,7 +444,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 145 + 141 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -464,15 +464,15 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 205 + 201 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 208 + 204 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 211 + 207 libs/ui/src/lib/account-balances/account-balances.component.html @@ -520,11 +520,11 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 74 + 78 apps/client/src/app/components/admin-tag/admin-tag.component.html - 67 + 71 libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -552,11 +552,15 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 85 + 89 apps/client/src/app/components/admin-tag/admin-tag.component.html - 78 + 82 + + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 22 libs/ui/src/lib/account-balances/account-balances.component.html @@ -580,7 +584,7 @@ 您确定要删除此账户吗? libs/ui/src/lib/accounts-table/accounts-table.component.ts - 150 + 148 @@ -588,7 +592,7 @@ 资产概况 apps/client/src/app/components/admin-jobs/admin-jobs.html - 52 + 61 @@ -596,11 +600,11 @@ 历史市场数据 apps/client/src/app/components/admin-jobs/admin-jobs.html - 54 + 63 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 448 + 451 @@ -608,7 +612,7 @@ 数据源 apps/client/src/app/components/admin-jobs/admin-jobs.html - 82 + 91 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -620,7 +624,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 155 + 151 libs/ui/src/lib/i18n.ts @@ -632,7 +636,7 @@ 尝试次数 apps/client/src/app/components/admin-jobs/admin-jobs.html - 120 + 129 @@ -640,7 +644,7 @@ 创建 apps/client/src/app/components/admin-jobs/admin-jobs.html - 134 + 143 @@ -648,7 +652,7 @@ 完成 apps/client/src/app/components/admin-jobs/admin-jobs.html - 143 + 152 @@ -656,11 +660,11 @@ 状态 apps/client/src/app/components/admin-jobs/admin-jobs.html - 152 + 161 apps/client/src/app/components/admin-settings/admin-settings.component.html - 92 + 104 @@ -676,7 +680,7 @@ 删除任务 apps/client/src/app/components/admin-jobs/admin-jobs.html - 193 + 202 @@ -684,7 +688,7 @@ 查看数据 apps/client/src/app/components/admin-jobs/admin-jobs.html - 208 + 217 @@ -692,7 +696,7 @@ 查看堆栈跟踪 apps/client/src/app/components/admin-jobs/admin-jobs.html - 216 + 225 @@ -700,7 +704,7 @@ 删除任务 apps/client/src/app/components/admin-jobs/admin-jobs.html - 224 + 233 @@ -716,7 +720,7 @@ 日期 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 161 + 157 libs/ui/src/lib/account-balances/account-balances.component.html @@ -752,11 +756,11 @@ 货币 apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 131 + 130 apps/client/src/app/pages/public/public-page.html - 96 + 95 @@ -764,7 +768,7 @@ 没有国家的 ETF apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 136 + 135 @@ -772,7 +776,7 @@ 无行业类别的 ETF apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 141 + 140 @@ -788,7 +792,7 @@ 过滤... apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 385 + 383 @@ -828,7 +832,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 44 + 40 @@ -864,7 +868,7 @@ 哎呀!无法解析历史数据。 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.ts - 262 + 284 @@ -888,7 +892,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 71 + 67 @@ -920,7 +924,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 53 + 72 @@ -932,7 +936,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 396 + 399 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -940,7 +944,7 @@ apps/client/src/app/pages/public/public-page.html - 114 + 113 @@ -952,7 +956,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 407 + 410 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -964,7 +968,7 @@ 代码映射 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 384 + 387 @@ -980,7 +984,7 @@ 刮削配置 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 471 + 474 @@ -988,7 +992,7 @@ 笔记 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 432 + 435 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -996,7 +1000,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 275 + 271 @@ -1040,7 +1044,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 124 + 120 @@ -1048,7 +1052,7 @@ 您确实要删除此优惠券吗? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 193 + 196 @@ -1056,7 +1060,7 @@ 您真的要删除这条系统消息吗? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 206 + 209 @@ -1064,7 +1068,7 @@ 您真的要刷新缓存吗? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 230 + 233 @@ -1072,7 +1076,7 @@ 请设置您的系统消息: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 250 + 253 @@ -1196,11 +1200,11 @@ 网址 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 419 + 422 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 550 + 553 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -1216,7 +1220,7 @@ 资产概况已保存 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 578 + 594 @@ -1224,7 +1228,15 @@ 您真的要删除这个平台吗? apps/client/src/app/components/admin-platform/admin-platform.component.ts - 106 + 111 + + + + Explore + Explore + + apps/client/src/app/pages/resources/overview/resources-overview.component.html + 11 @@ -1248,7 +1260,7 @@ 当前年份 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 199 + 205 @@ -1264,7 +1276,7 @@ 平台 apps/client/src/app/components/admin-settings/admin-settings.component.html - 195 + 212 @@ -1272,7 +1284,7 @@ 标签 apps/client/src/app/components/admin-settings/admin-settings.component.html - 201 + 218 libs/ui/src/lib/tags-selector/tags-selector.component.html @@ -1296,7 +1308,7 @@ 您真的要删除此标签吗? apps/client/src/app/components/admin-tag/admin-tag.component.ts - 103 + 108 @@ -1356,7 +1368,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 89 + 108 @@ -1388,11 +1400,11 @@ 无法验证表单 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 554 + 570 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 557 + 573 @@ -1440,7 +1452,7 @@ 基准 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 376 + 379 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -1476,7 +1488,7 @@ apps/client/src/app/components/header/header.component.ts - 297 + 298 apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html @@ -1496,15 +1508,15 @@ 哎呀!安全令牌不正确。 apps/client/src/app/components/header/header.component.ts - 312 + 313 apps/client/src/app/components/user-account-access/user-account-access.component.ts - 154 + 152 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 193 + 191 @@ -1512,7 +1524,7 @@ 管理活动 apps/client/src/app/components/home-holdings/home-holdings.html - 67 + 64 @@ -1520,11 +1532,11 @@ 恐惧 apps/client/src/app/components/home-market/home-market.component.ts - 42 + 41 apps/client/src/app/components/markets/markets.component.ts - 47 + 46 libs/ui/src/lib/i18n.ts @@ -1536,11 +1548,11 @@ 贪婪 apps/client/src/app/components/home-market/home-market.component.ts - 43 + 42 apps/client/src/app/components/markets/markets.component.ts - 48 + 47 libs/ui/src/lib/i18n.ts @@ -1644,7 +1656,7 @@ 当前周 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 191 + 197 @@ -1664,7 +1676,7 @@ 总金额 apps/client/src/app/components/investment-chart/investment-chart.component.ts - 143 + 146 @@ -1776,7 +1788,7 @@ 绝对总业绩 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 73 + 77 @@ -1788,7 +1800,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 88 + 92 @@ -1796,7 +1808,7 @@ 绝对净绩效 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 107 + 111 apps/client/src/app/pages/portfolio/analysis/analysis-page.html @@ -1808,7 +1820,7 @@ 净绩效 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 123 + 127 apps/client/src/app/pages/portfolio/analysis/analysis-page.html @@ -1820,7 +1832,7 @@ 总资产 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 149 + 153 @@ -1828,7 +1840,7 @@ 资产 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 233 @@ -1836,7 +1848,7 @@ 购买力 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 241 + 248 @@ -1844,7 +1856,7 @@ 从分析中排除 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 267 + 274 @@ -1852,7 +1864,7 @@ 负债 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 295 + 302 apps/client/src/app/pages/features/features-page.html @@ -1864,7 +1876,7 @@ 净值 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 317 + 324 @@ -1872,7 +1884,7 @@ 年化业绩 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 331 + 338 @@ -1908,7 +1920,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 189 + 185 libs/ui/src/lib/activities-table/activities-table.component.html @@ -1924,7 +1936,7 @@ 报告数据故障 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 451 + 456 @@ -2104,7 +2116,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 363 + 362 @@ -2112,11 +2124,11 @@ 年初至今 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 199 + 205 libs/ui/src/lib/assistant/assistant.component.ts - 375 + 374 @@ -2124,11 +2136,11 @@ 1年 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 203 + 209 libs/ui/src/lib/assistant/assistant.component.ts - 385 + 384 @@ -2136,11 +2148,11 @@ 5年 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 207 + 213 libs/ui/src/lib/assistant/assistant.component.ts - 409 + 408 @@ -2156,11 +2168,11 @@ 最大限度 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 211 + 217 libs/ui/src/lib/assistant/assistant.component.ts - 415 + 414 @@ -2260,7 +2272,7 @@ 自动 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 70 + 69 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -2272,7 +2284,7 @@ 您确实要删除此登录方法吗? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 282 + 279 @@ -2312,7 +2324,7 @@ 语言环境 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 512 apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -2424,7 +2436,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 11 + 30 @@ -2456,7 +2468,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 195 + 194 @@ -2468,7 +2480,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 193 + 192 @@ -2484,7 +2496,7 @@ apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 196 + 195 @@ -2612,11 +2624,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 375 + 381 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 66 + 85 apps/client/src/app/pages/accounts/accounts-page.html @@ -2708,7 +2720,7 @@ 市场数据 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 398 + 403 libs/common/src/lib/routes/routes.ts @@ -2742,6 +2754,10 @@ Overview 概述 + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 7 + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html 114 @@ -2760,11 +2776,11 @@ apps/client/src/app/pages/admin/admin-page.component.ts - 48 + 45 apps/client/src/app/pages/resources/resources-page.component.ts - 30 + 29 libs/common/src/lib/routes/routes.ts @@ -2888,11 +2904,11 @@ 无法解析抓取器配置 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 509 + 525 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 512 + 528 @@ -2908,7 +2924,7 @@ 由于您已经登录,因此无法访问模拟帐户。 apps/client/src/app/pages/demo/demo-page.component.ts - 35 + 32 @@ -3080,7 +3096,7 @@ apps/client/src/app/pages/public/public-page.html - 242 + 241 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -3132,7 +3148,7 @@ 市场 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 378 + 381 apps/client/src/app/components/footer/footer.component.html @@ -3156,7 +3172,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 40 + 39 libs/common/src/lib/routes/routes.ts @@ -3596,7 +3612,7 @@ 作业 ID apps/client/src/app/components/admin-jobs/admin-jobs.html - 34 + 43 @@ -3632,7 +3648,7 @@ apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 115 + 113 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -3652,11 +3668,11 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 342 + 348 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 75 + 94 apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -3676,7 +3692,7 @@ 您确定要删除这些活动吗? libs/ui/src/lib/activities-table/activities-table.component.ts - 278 + 282 @@ -3744,7 +3760,7 @@ 更新现金余额 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 112 + 108 @@ -3752,7 +3768,7 @@ 单价 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 214 + 210 libs/ui/src/lib/activities-table/activities-table.component.html @@ -3780,7 +3796,7 @@ 导入股息 apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 137 + 136 libs/ui/src/lib/activities-table/activities-table.component.html @@ -3796,7 +3812,7 @@ 正在导入数据... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 175 + 174 @@ -3804,7 +3820,7 @@ 导入已完成 apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 185 + 184 @@ -3820,7 +3836,7 @@ 验证数据... apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts - 299 + 293 @@ -3992,7 +4008,7 @@ apps/client/src/app/pages/public/public-page.html - 151 + 150 @@ -4016,7 +4032,7 @@ apps/client/src/app/pages/public/public-page.html - 168 + 167 @@ -4024,7 +4040,7 @@ 最新活动 apps/client/src/app/pages/public/public-page.html - 211 + 210 @@ -4036,7 +4052,7 @@ apps/client/src/app/pages/public/public-page.html - 177 + 176 @@ -4048,7 +4064,7 @@ apps/client/src/app/pages/public/public-page.html - 186 + 185 @@ -4108,7 +4124,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 365 + 372 apps/client/src/app/pages/features/features-page.html @@ -4116,11 +4132,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 202 + 198 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 76 + 75 libs/ui/src/lib/i18n.ts @@ -4140,7 +4156,7 @@ 存款 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 377 + 404 @@ -4148,7 +4164,7 @@ 每月 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 91 + 90 @@ -4156,7 +4172,7 @@ 每年 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 92 + 91 @@ -4436,11 +4452,11 @@ 无法保存资产概况 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 588 + 604 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 591 + 607 @@ -4464,7 +4480,7 @@ 大陆 apps/client/src/app/pages/public/public-page.html - 132 + 131 @@ -4480,7 +4496,7 @@ Ghostfolio 使您能够跟踪您的财富。 apps/client/src/app/pages/public/public-page.html - 238 + 237 @@ -4510,6 +4526,10 @@ apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html 88 + + libs/ui/src/lib/value/value.component.html + 18 + Personal Finance Tools @@ -4853,7 +4873,7 @@ 会员资格 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 48 + 67 libs/common/src/lib/routes/routes.ts @@ -4921,7 +4941,7 @@ 您确实要删除该帐户余额吗? libs/ui/src/lib/account-balances/account-balances.component.ts - 120 + 113 @@ -4977,7 +4997,7 @@ 您确实要删除此活动吗? libs/ui/src/lib/activities-table/activities-table.component.ts - 288 + 292 @@ -4985,7 +5005,7 @@ 资产概况 apps/client/src/app/components/admin-settings/admin-settings.component.html - 106 + 123 libs/ui/src/lib/assistant/assistant.html @@ -5097,11 +5117,11 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 352 + 359 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 387 + 414 libs/ui/src/lib/i18n.ts @@ -5113,7 +5133,7 @@ 储蓄 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 397 + 424 @@ -5141,7 +5161,7 @@ 显示所有 libs/ui/src/lib/holdings-table/holdings-table.component.html - 216 + 212 @@ -5185,7 +5205,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 326 + 327 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -5193,7 +5213,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 290 + 286 libs/ui/src/lib/i18n.ts @@ -5217,7 +5237,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 342 + 343 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -5225,7 +5245,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 309 + 305 libs/ui/src/lib/i18n.ts @@ -5269,7 +5289,7 @@ 应急基金 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 164 + 168 apps/client/src/app/pages/features/features-page.html @@ -5345,7 +5365,7 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 437 + 451 @@ -5356,6 +5376,14 @@ 27 + + No Activities + No Activities + + apps/client/src/app/components/admin-market-data/admin-market-data.component.ts + 145 + + Retirement Provision 退休金 @@ -5377,7 +5405,7 @@ 代码 apps/client/src/app/components/admin-jobs/admin-jobs.html - 68 + 77 apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -5393,7 +5421,7 @@ apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 315 + 318 libs/ui/src/lib/i18n.ts @@ -5465,7 +5493,7 @@ 费用 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 262 + 258 libs/ui/src/lib/activities-table/activities-table.component.html @@ -5509,7 +5537,7 @@ 现金 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 212 + 219 libs/ui/src/lib/i18n.ts @@ -5557,7 +5585,7 @@ 认证 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 35 + 54 @@ -5701,7 +5729,7 @@ 有效期至 apps/client/src/app/components/admin-settings/admin-settings.component.html - 74 + 86 libs/ui/src/lib/membership-card/membership-card.component.html @@ -5725,7 +5753,7 @@ apps/client/src/app/pages/public/public-page.html - 196 + 195 libs/ui/src/lib/benchmark/benchmark.component.html @@ -5733,11 +5761,11 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 439 + 453 libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 452 + 467 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -5765,7 +5793,7 @@ 当前市场价格为 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 706 + 722 @@ -5773,7 +5801,7 @@ 测试 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 568 + 571 @@ -5853,7 +5881,7 @@ 关闭持仓 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 442 + 447 @@ -5877,11 +5905,11 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 81 + 80 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 97 + 96 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -5917,7 +5945,7 @@ 今年迄今为止 libs/ui/src/lib/assistant/assistant.component.ts - 375 + 374 @@ -5925,7 +5953,7 @@ 本周至今 libs/ui/src/lib/assistant/assistant.component.ts - 367 + 366 @@ -5933,7 +5961,7 @@ 本月至今 libs/ui/src/lib/assistant/assistant.component.ts - 371 + 370 @@ -5941,11 +5969,11 @@ 本月至今 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 195 + 201 libs/ui/src/lib/assistant/assistant.component.ts - 371 + 370 @@ -5953,11 +5981,11 @@ 本周至今 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 191 + 197 libs/ui/src/lib/assistant/assistant.component.ts - 367 + 366 @@ -5993,7 +6021,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 203 + 209 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -6005,7 +6033,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 385 + 384 @@ -6013,11 +6041,11 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 207 + 213 libs/ui/src/lib/assistant/assistant.component.ts - 409 + 408 @@ -6046,7 +6074,7 @@ 自托管 apps/client/src/app/pages/faq/faq-page.component.ts - 60 + 52 libs/common/src/lib/routes/routes.ts @@ -6058,7 +6086,7 @@ 数据收集 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 587 + 594 apps/client/src/app/components/admin-overview/admin-overview.html @@ -6070,7 +6098,7 @@ 一般的 apps/client/src/app/pages/faq/faq-page.component.ts - 49 + 41 @@ -6078,7 +6106,7 @@ apps/client/src/app/pages/faq/faq-page.component.ts - 54 + 46 libs/common/src/lib/routes/routes.ts @@ -6106,7 +6134,7 @@ 已关闭 apps/client/src/app/components/home-holdings/home-holdings.component.ts - 65 + 64 @@ -6114,7 +6142,7 @@ 活跃 apps/client/src/app/components/home-holdings/home-holdings.component.ts - 64 + 63 @@ -6146,7 +6174,7 @@ 执行作业 apps/client/src/app/components/admin-jobs/admin-jobs.html - 220 + 229 @@ -6154,7 +6182,7 @@ 优先级 apps/client/src/app/components/admin-jobs/admin-jobs.html - 96 + 105 @@ -6210,7 +6238,7 @@ 您确定要关闭您的 Ghostfolio 账户吗? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 208 + 205 @@ -6258,7 +6286,7 @@ 包含在 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 374 + 377 @@ -6266,7 +6294,7 @@ 哎呀!设置生物识别认证时发生错误。 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 336 + 333 @@ -6282,7 +6310,7 @@ 基准 apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 126 + 125 @@ -6330,7 +6358,7 @@ 您想 优化 您的 个人投资策略吗? apps/client/src/app/pages/public/public-page.html - 234 + 233 @@ -6662,7 +6690,7 @@ 错误 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 697 + 713 @@ -6714,7 +6742,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 592 + 599 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6746,7 +6774,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 345 + 341 apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html @@ -6754,7 +6782,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 46 + 47 libs/ui/src/lib/i18n.ts @@ -6766,7 +6794,7 @@ 关闭 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 594 + 601 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6792,13 +6820,17 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 68 + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 127 + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html 107 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 347 + 343 libs/ui/src/lib/i18n.ts @@ -6810,7 +6842,7 @@ 角色 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 14 + 33 @@ -6834,7 +6866,7 @@ 投资组合快照 apps/client/src/app/components/admin-jobs/admin-jobs.html - 56 + 65 @@ -6901,6 +6933,14 @@ 42 + + has been copied to the clipboard + has been copied to the clipboard + + libs/ui/src/lib/value/value.component.ts + 180 + + From the beginning 从头开始 @@ -7066,7 +7106,7 @@ 设置 API 密钥 apps/client/src/app/components/admin-settings/admin-settings.component.html - 171 + 188 @@ -7102,7 +7142,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 45 + 44 libs/common/src/lib/routes/routes.ts @@ -7118,7 +7158,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 34 + 33 libs/common/src/lib/routes/routes.ts @@ -7172,7 +7212,7 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 135 + 152 @@ -7180,7 +7220,7 @@ 每日请求 apps/client/src/app/components/admin-settings/admin-settings.component.html - 137 + 154 @@ -7188,7 +7228,7 @@ 移除 API 密钥 apps/client/src/app/components/admin-settings/admin-settings.component.html - 161 + 178 @@ -7196,7 +7236,7 @@ 您确定要删除此 API 密钥吗? apps/client/src/app/components/admin-settings/admin-settings.component.ts - 127 + 133 @@ -7216,7 +7256,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 98 + 117 @@ -7288,7 +7328,7 @@ 保存 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 603 + 610 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7324,11 +7364,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 356 + 352 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 48 + 49 @@ -7340,7 +7380,7 @@ apps/client/src/app/components/user-account-access/user-account-access.component.ts - 260 + 257 @@ -7364,7 +7404,7 @@ 请输入您的 Ghostfolio API 密钥。 apps/client/src/app/components/admin-settings/admin-settings.component.ts - 146 + 152 @@ -7380,7 +7420,7 @@ AI 提示已复制到剪贴板 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 201 + 199 @@ -7396,7 +7436,7 @@ 延迟 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 225 + 231 @@ -7404,7 +7444,7 @@ 即时 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 229 + 235 @@ -7412,7 +7452,7 @@ 默认市场价格 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 481 + 484 @@ -7420,7 +7460,7 @@ 模式 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 518 + 521 @@ -7428,7 +7468,7 @@ 选择器 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 534 + 537 @@ -7436,7 +7476,7 @@ HTTP 请求标头 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 494 + 497 @@ -7444,7 +7484,7 @@ 收盘 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 225 + 231 @@ -7452,7 +7492,7 @@ 实时 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 229 + 235 @@ -7460,7 +7500,7 @@ 打开 Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 202 + 200 @@ -7480,7 +7520,7 @@ libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 377 @@ -7492,7 +7532,7 @@ apps/client/src/app/components/home-overview/home-overview.component.ts - 55 + 54 libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -7500,11 +7540,11 @@ libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 377 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 381 + 390 @@ -7608,11 +7648,11 @@ 安全令牌 apps/client/src/app/components/admin-users/admin-users.component.ts - 236 + 235 apps/client/src/app/components/user-account-access/user-account-access.component.ts - 170 + 167 @@ -7620,7 +7660,7 @@ 您确定要为此用户生成新的安全令牌吗? apps/client/src/app/components/admin-users/admin-users.component.ts - 241 + 240 @@ -7628,7 +7668,7 @@ 查找账户、持仓或页面... libs/ui/src/lib/assistant/assistant.component.ts - 151 + 115 @@ -7693,7 +7733,7 @@ () 已在使用中。 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 633 + 649 @@ -7701,7 +7741,7 @@ 在更新到 () 时发生错误。 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 641 + 657 @@ -7765,7 +7805,7 @@ 某人 apps/client/src/app/pages/public/public-page.component.ts - 59 + 61 @@ -7797,7 +7837,7 @@ 您确定要删除此项目吗? libs/ui/src/lib/benchmark/benchmark.component.ts - 144 + 139 @@ -7838,7 +7878,7 @@ 演示用户账户已同步。 apps/client/src/app/components/admin-overview/admin-overview.component.ts - 274 + 277 @@ -7873,7 +7913,7 @@ 150 - + Fee Ratio 费率 @@ -7881,17 +7921,17 @@ 152 - - The fees do exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - 费用超过了您初始投资的 ${thresholdMax}% (${feeRatio}%) + + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + 费用已超过您总投资金额的 ${thresholdMax}%(${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 154 - - The fees do not exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - 费用未超过您初始投资的 ${thresholdMax}% (${feeRatio}%) + + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + 费用未超过您总投资金额的 ${thresholdMax}%(${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 158 @@ -8052,7 +8092,7 @@ 当前月份 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 195 + 201 @@ -8060,11 +8100,11 @@ 新增 apps/client/src/app/components/admin-settings/admin-settings.component.html - 67 + 79 apps/client/src/app/pages/admin/admin-page.component.ts - 56 + 53 @@ -8221,7 +8261,7 @@ 您真的想要生成一个新的安全令牌吗? apps/client/src/app/components/user-account-access/user-account-access.component.ts - 175 + 172 @@ -8245,7 +8285,7 @@ 股票 apps/client/src/app/components/markets/markets.component.ts - 52 + 51 apps/client/src/app/pages/features/features-page.html @@ -8257,7 +8297,7 @@ 加密货币 apps/client/src/app/components/markets/markets.component.ts - 53 + 52 apps/client/src/app/pages/features/features-page.html @@ -8277,7 +8317,7 @@ 管理资产概况 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 466 + 471 @@ -8697,7 +8737,7 @@ 注册日期 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 26 + 45 diff --git a/apps/client/src/styles.scss b/apps/client/src/styles.scss index b7a031bfa..f5a4e9c80 100644 --- a/apps/client/src/styles.scss +++ b/apps/client/src/styles.scss @@ -2,7 +2,7 @@ @import './styles/table'; @import './styles/variables'; -@import 'svgmap/dist/svgMap'; +@import 'svgmap/style.min'; :root { --dark-background: rgb(25, 25, 25); @@ -546,6 +546,10 @@ ngx-skeleton-loader { padding: 9px 24px !important; } +.no-height { + height: unset !important; +} + .no-min-width { min-width: unset !important; } diff --git a/libs/common/src/lib/calculation-helper.ts b/libs/common/src/lib/calculation-helper.ts index 76b38f9b2..2097fa52a 100644 --- a/libs/common/src/lib/calculation-helper.ts +++ b/libs/common/src/lib/calculation-helper.ts @@ -36,14 +36,16 @@ export function getAnnualizedPerformancePercent({ return new Big(0); } -export function getIntervalFromDateRange( - aDateRange: DateRange, - portfolioStart = new Date(0) -) { - let endDate = endOfDay(new Date()); - let startDate = portfolioStart; +export function getIntervalFromDateRange(params: { + dateRange: DateRange; + endDate?: Date; + startDate?: Date; +}) { + const { dateRange } = params; + let endDate = params.endDate ?? endOfDay(new Date()); + let startDate = params.startDate ?? new Date(0); - switch (aDateRange) { + switch (dateRange) { case '1d': startDate = max([startDate, subDays(resetHours(new Date()), 1)]); break; @@ -75,8 +77,8 @@ export function getIntervalFromDateRange( break; default: // '2024', '2023', '2022', etc. - endDate = endOfYear(new Date(aDateRange)); - startDate = max([startDate, new Date(aDateRange)]); + endDate = endOfYear(new Date(dateRange)); + startDate = max([startDate, new Date(dateRange)]); } return { endDate, startDate }; diff --git a/libs/common/src/lib/config.ts b/libs/common/src/lib/config.ts index b558ccc42..08fa2f030 100644 --- a/libs/common/src/lib/config.ts +++ b/libs/common/src/lib/config.ts @@ -51,6 +51,14 @@ export const ASSET_CLASS_MAPPING = new Map([ [AssetClass.REAL_ESTATE, []] ]); +export const BULL_BOARD_COOKIE_NAME = 'bull_board_token'; + +/** + * WARNING: This route is mirrored in `apps/client/proxy.conf.json`. + * If you update this value, you must also update the proxy configuration. + */ +export const BULL_BOARD_ROUTE = '/admin/queues'; + export const CACHE_TTL_NO_CACHE = 1; export const CACHE_TTL_INFINITE = 0; @@ -80,6 +88,11 @@ export const DEFAULT_PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_TIMEOUT = 30000; export const DEFAULT_REDACTED_PATHS = [ 'accounts[*].balance', + 'accounts[*].balanceInBaseCurrency', + 'accounts[*].comment', + 'accounts[*].dividendInBaseCurrency', + 'accounts[*].interestInBaseCurrency', + 'accounts[*].value', 'accounts[*].valueInBaseCurrency', 'activities[*].account.balance', 'activities[*].account.comment', @@ -199,6 +212,7 @@ export const PROPERTY_BETTER_UPTIME_MONITOR_ID = 'BETTER_UPTIME_MONITOR_ID'; export const PROPERTY_COUNTRIES_OF_SUBSCRIBERS = 'COUNTRIES_OF_SUBSCRIBERS'; export const PROPERTY_COUPONS = 'COUPONS'; export const PROPERTY_CURRENCIES = 'CURRENCIES'; +export const PROPERTY_CUSTOM_CRYPTOCURRENCIES = 'CUSTOM_CRYPTOCURRENCIES'; export const PROPERTY_DATA_SOURCE_MAPPING = 'DATA_SOURCE_MAPPING'; export const PROPERTY_DATA_SOURCES_GHOSTFOLIO_DATA_PROVIDER_MAX_REQUESTS = 'DATA_SOURCES_GHOSTFOLIO_DATA_PROVIDER_MAX_REQUESTS'; diff --git a/libs/common/src/lib/dtos/create-asset-profile.dto.ts b/libs/common/src/lib/dtos/create-asset-profile.dto.ts index 80d45ba42..85ad73cc0 100644 --- a/libs/common/src/lib/dtos/create-asset-profile.dto.ts +++ b/libs/common/src/lib/dtos/create-asset-profile.dto.ts @@ -5,7 +5,6 @@ import { IsArray, IsBoolean, IsEnum, - IsObject, IsOptional, IsString, IsUrl @@ -66,10 +65,6 @@ export class CreateAssetProfileDto { @IsString() name?: string; - @IsObject() - @IsOptional() - scraperConfiguration?: Prisma.InputJsonObject; - @IsArray() @IsOptional() sectors?: Prisma.InputJsonArray; @@ -77,12 +72,6 @@ export class CreateAssetProfileDto { @IsString() symbol: string; - @IsObject() - @IsOptional() - symbolMapping?: { - [dataProvider: string]: string; - }; - @IsOptional() @IsUrl({ protocols: ['https'], diff --git a/libs/common/src/lib/helper.spec.ts b/libs/common/src/lib/helper.spec.ts index 25779cf39..a339c6dab 100644 --- a/libs/common/src/lib/helper.spec.ts +++ b/libs/common/src/lib/helper.spec.ts @@ -25,7 +25,7 @@ describe('Helper', () => { it('Get decimal number with group (dot notation)', () => { expect( - extractNumberFromString({ locale: 'de-CH', value: '99’999.99' }) + extractNumberFromString({ locale: 'de-CH', value: `99'999.99` }) ).toEqual(99999.99); }); @@ -54,12 +54,12 @@ describe('Helper', () => { }); it('Get de-CH number format group', () => { - expect(getNumberFormatGroup('de-CH')).toEqual('’'); + expect(getNumberFormatGroup('de-CH')).toEqual(`'`); }); it('Get de-CH number format group when it is default', () => { languageGetter.mockReturnValue('de-CH'); - expect(getNumberFormatGroup()).toEqual('’'); + expect(getNumberFormatGroup()).toEqual(`'`); }); it('Get de-DE number format group', () => { diff --git a/libs/common/src/lib/interfaces/lookup-item.interface.ts b/libs/common/src/lib/interfaces/lookup-item.interface.ts index fa91ed690..6cedeca09 100644 --- a/libs/common/src/lib/interfaces/lookup-item.interface.ts +++ b/libs/common/src/lib/interfaces/lookup-item.interface.ts @@ -7,7 +7,7 @@ export interface LookupItem { assetSubClass: AssetSubClass; currency: string; dataProviderInfo: DataProviderInfo; - dataSource: DataSource; + dataSource: DataSource | null; name: string; symbol: string; } diff --git a/libs/common/src/lib/interfaces/portfolio-performance.interface.ts b/libs/common/src/lib/interfaces/portfolio-performance.interface.ts index c0c3802d8..0698004d5 100644 --- a/libs/common/src/lib/interfaces/portfolio-performance.interface.ts +++ b/libs/common/src/lib/interfaces/portfolio-performance.interface.ts @@ -7,4 +7,5 @@ export interface PortfolioPerformance { netPerformancePercentageWithCurrencyEffect: number; netPerformanceWithCurrencyEffect: number; totalInvestment: number; + totalInvestmentValueWithCurrencyEffect: number; } diff --git a/libs/common/src/lib/interfaces/portfolio-position.interface.ts b/libs/common/src/lib/interfaces/portfolio-position.interface.ts index 620cc00e9..c4ef2e3dc 100644 --- a/libs/common/src/lib/interfaces/portfolio-position.interface.ts +++ b/libs/common/src/lib/interfaces/portfolio-position.interface.ts @@ -3,19 +3,52 @@ import { Market, MarketAdvanced } from '@ghostfolio/common/types'; import { AssetClass, AssetSubClass, DataSource, Tag } from '@prisma/client'; import { Country } from './country.interface'; +import { EnhancedSymbolProfile } from './enhanced-symbol-profile.interface'; import { Holding } from './holding.interface'; import { Sector } from './sector.interface'; export interface PortfolioPosition { activitiesCount: number; allocationInPercentage: number; + + /** @deprecated */ assetClass?: AssetClass; + + /** @deprecated */ assetClassLabel?: string; + + assetProfile: Pick< + EnhancedSymbolProfile, + | 'assetClass' + | 'assetSubClass' + | 'countries' + | 'currency' + | 'dataSource' + | 'holdings' + | 'name' + | 'sectors' + | 'symbol' + | 'url' + > & { + assetClassLabel?: string; + assetSubClassLabel?: string; + }; + + /** @deprecated */ assetSubClass?: AssetSubClass; + + /** @deprecated */ assetSubClassLabel?: string; + + /** @deprecated */ countries: Country[]; + + /** @deprecated */ currency: string; + + /** @deprecated */ dataSource: DataSource; + dateOfFirstActivity: Date; dividend: number; exchange?: string; @@ -23,24 +56,38 @@ export interface PortfolioPosition { grossPerformancePercent: number; grossPerformancePercentWithCurrencyEffect: number; grossPerformanceWithCurrencyEffect: number; + + /** @deprecated */ holdings: Holding[]; + investment: number; marketChange?: number; marketChangePercent?: number; marketPrice: number; markets?: { [key in Market]: number }; marketsAdvanced?: { [key in MarketAdvanced]: number }; + + /** @deprecated */ name: string; + netPerformance: number; netPerformancePercent: number; netPerformancePercentWithCurrencyEffect: number; netPerformanceWithCurrencyEffect: number; quantity: number; + + /** @deprecated */ sectors: Sector[]; + + /** @deprecated */ symbol: string; + tags?: Tag[]; type?: string; + + /** @deprecated */ url?: string; + valueInBaseCurrency?: number; valueInPercentage?: number; } diff --git a/libs/common/src/lib/interfaces/portfolio-summary.interface.ts b/libs/common/src/lib/interfaces/portfolio-summary.interface.ts index ccf94dcf7..8db6b39bb 100644 --- a/libs/common/src/lib/interfaces/portfolio-summary.interface.ts +++ b/libs/common/src/lib/interfaces/portfolio-summary.interface.ts @@ -6,7 +6,6 @@ export interface PortfolioSummary extends PortfolioPerformance { annualizedPerformancePercent: number; annualizedPerformancePercentWithCurrencyEffect: number; cash: number; - committedFunds: number; dateOfFirstActivity: Date; dividendInBaseCurrency: number; emergencyFund: { diff --git a/libs/common/src/lib/interfaces/responses/export-response.interface.ts b/libs/common/src/lib/interfaces/responses/export-response.interface.ts index 8b1697ca4..fa592faf2 100644 --- a/libs/common/src/lib/interfaces/responses/export-response.interface.ts +++ b/libs/common/src/lib/interfaces/responses/export-response.interface.ts @@ -27,7 +27,12 @@ export interface ExportResponse { > & { dataSource: DataSource; date: string; symbol: string })[]; assetProfiles: (Omit< SymbolProfile, - 'createdAt' | 'id' | 'updatedAt' | 'userId' + | 'createdAt' + | 'id' + | 'scraperConfiguration' + | 'symbolMapping' + | 'updatedAt' + | 'userId' > & { marketData: MarketData[]; })[]; diff --git a/libs/common/src/lib/interfaces/responses/public-portfolio-response.interface.ts b/libs/common/src/lib/interfaces/responses/public-portfolio-response.interface.ts index 4a087ad16..eae14cec6 100644 --- a/libs/common/src/lib/interfaces/responses/public-portfolio-response.interface.ts +++ b/libs/common/src/lib/interfaces/responses/public-portfolio-response.interface.ts @@ -14,16 +14,31 @@ export interface PublicPortfolioResponse extends PublicPortfolioResponseV1 { [symbol: string]: Pick< PortfolioPosition, | 'allocationInPercentage' + + /** @deprecated */ | 'assetClass' + | 'assetProfile' + + /** @deprecated */ | 'countries' | 'currency' + + /** @deprecated */ | 'dataSource' | 'dateOfFirstActivity' | 'markets' + + /** @deprecated */ | 'name' | 'netPerformancePercentWithCurrencyEffect' + + /** @deprecated */ | 'sectors' + + /** @deprecated */ | 'symbol' + + /** @deprecated */ | 'url' | 'valueInBaseCurrency' | 'valueInPercentage' diff --git a/libs/common/src/lib/interfaces/x-ray-rules-settings.interface.ts b/libs/common/src/lib/interfaces/x-ray-rules-settings.interface.ts index bdef3e169..60a76d468 100644 --- a/libs/common/src/lib/interfaces/x-ray-rules-settings.interface.ts +++ b/libs/common/src/lib/interfaces/x-ray-rules-settings.interface.ts @@ -9,7 +9,7 @@ export interface XRayRulesSettings { EconomicMarketClusterRiskDevelopedMarkets?: RuleSettings; EconomicMarketClusterRiskEmergingMarkets?: RuleSettings; EmergencyFundSetup?: RuleSettings; - FeeRatioInitialInvestment?: RuleSettings; + FeeRatioTotalInvestmentVolume?: RuleSettings; RegionalMarketClusterRiskAsiaPacific?: RuleSettings; RegionalMarketClusterRiskEmergingMarkets?: RuleSettings; RegionalMarketClusterRiskEurope?: RuleSettings; diff --git a/libs/common/src/lib/permissions.ts b/libs/common/src/lib/permissions.ts index cb4eb175b..f9cb19562 100644 --- a/libs/common/src/lib/permissions.ts +++ b/libs/common/src/lib/permissions.ts @@ -4,15 +4,16 @@ import { Role } from '@prisma/client'; export const permissions = { accessAdminControl: 'accessAdminControl', + accessAdminControlBullBoard: 'accessAdminControlBullBoard', accessAssistant: 'accessAssistant', accessHoldingsChart: 'accessHoldingsChart', createAccess: 'createAccess', createAccount: 'createAccount', createAccountBalance: 'createAccountBalance', + createActivity: 'createActivity', createApiKey: 'createApiKey', createMarketData: 'createMarketData', createMarketDataOfOwnAssetProfile: 'createMarketDataOfOwnAssetProfile', - createOrder: 'createOrder', createOwnTag: 'createOwnTag', createPlatform: 'createPlatform', createTag: 'createTag', @@ -21,8 +22,8 @@ export const permissions = { deleteAccess: 'deleteAccess', deleteAccount: 'deleteAccount', deleteAccountBalance: 'deleteAccountBalance', + deleteActivity: 'deleteActivity', deleteAuthDevice: 'deleteAuthDevice', - deleteOrder: 'deleteOrder', deleteOwnUser: 'deleteOwnUser', deletePlatform: 'deletePlatform', deleteTag: 'deleteTag', @@ -53,10 +54,10 @@ export const permissions = { toggleReadOnlyMode: 'toggleReadOnlyMode', updateAccount: 'updateAccount', updateAccess: 'updateAccess', + updateActivity: 'updateActivity', updateAuthDevice: 'updateAuthDevice', updateMarketData: 'updateMarketData', updateMarketDataOfOwnAssetProfile: 'updateMarketDataOfOwnAssetProfile', - updateOrder: 'updateOrder', updateOwnAccessToken: 'updateOwnAccessToken', updatePlatform: 'updatePlatform', updateTag: 'updateTag', @@ -74,19 +75,19 @@ export function getPermissions(aRole: Role): string[] { permissions.createAccess, permissions.createAccount, permissions.createAccountBalance, + permissions.createActivity, permissions.createWatchlistItem, permissions.deleteAccountBalance, permissions.deleteWatchlistItem, permissions.createMarketData, permissions.createMarketDataOfOwnAssetProfile, - permissions.createOrder, permissions.createOwnTag, permissions.createPlatform, permissions.createTag, permissions.deleteAccess, permissions.deleteAccount, + permissions.deleteActivity, permissions.deleteAuthDevice, - permissions.deleteOrder, permissions.deletePlatform, permissions.deleteTag, permissions.deleteUser, @@ -99,10 +100,10 @@ export function getPermissions(aRole: Role): string[] { permissions.readWatchlist, permissions.updateAccount, permissions.updateAccess, + permissions.updateActivity, permissions.updateAuthDevice, permissions.updateMarketData, permissions.updateMarketDataOfOwnAssetProfile, - permissions.updateOrder, permissions.updatePlatform, permissions.updateTag, permissions.updateUserSettings, @@ -125,15 +126,15 @@ export function getPermissions(aRole: Role): string[] { permissions.createAccess, permissions.createAccount, permissions.createAccountBalance, + permissions.createActivity, permissions.createMarketDataOfOwnAssetProfile, - permissions.createOrder, permissions.createOwnTag, permissions.createWatchlistItem, permissions.deleteAccess, permissions.deleteAccount, permissions.deleteAccountBalance, + permissions.deleteActivity, permissions.deleteAuthDevice, - permissions.deleteOrder, permissions.deleteWatchlistItem, permissions.readAiPrompt, permissions.readMarketDataOfOwnAssetProfile, @@ -141,9 +142,9 @@ export function getPermissions(aRole: Role): string[] { permissions.readWatchlist, permissions.updateAccount, permissions.updateAccess, + permissions.updateActivity, permissions.updateAuthDevice, permissions.updateMarketDataOfOwnAssetProfile, - permissions.updateOrder, permissions.updateUserSettings, permissions.updateViewMode ]; @@ -194,7 +195,7 @@ export function hasReadRestrictedAccessPermission({ return false; } - const access = user.accessesGet?.find(({ id }) => { + const access = user?.accessesGet?.find(({ id }) => { return id === impersonationId; }); diff --git a/libs/common/src/lib/personal-finance-tools.ts b/libs/common/src/lib/personal-finance-tools.ts index 6d0a85fb2..063b4254c 100644 --- a/libs/common/src/lib/personal-finance-tools.ts +++ b/libs/common/src/lib/personal-finance-tools.ts @@ -33,6 +33,15 @@ export const personalFinanceTools: Product[] = [ origin: 'Switzerland', slogan: 'Simplicity for Complex Wealth' }, + { + founded: 2018, + hasFreePlan: false, + hasSelfHostingAbility: false, + key: 'altruist', + name: 'Altruist', + origin: 'United States', + slogan: 'The wealth platform built for independent advisors' + }, { founded: 2023, hasFreePlan: false, @@ -116,6 +125,17 @@ export const personalFinanceTools: Product[] = [ origin: 'Switzerland', slogan: 'Schweizer Budget App für einfache & smarte Budgetplanung' }, + { + founded: 2015, + hasFreePlan: true, + hasSelfHostingAbility: false, + key: 'boldin', + name: 'Boldin', + note: 'Originally named as NewRetirement', + origin: 'United States', + pricingPerYear: '$144', + slogan: 'Take control with retirement planning tools that begin with you' + }, { key: 'budgetpulse', name: 'BudgetPulse', @@ -841,6 +861,16 @@ export const personalFinanceTools: Product[] = [ pricingPerYear: '$108', slogan: 'Build Financial Plans You Love.' }, + { + founded: 2022, + hasFreePlan: false, + hasSelfHostingAbility: false, + key: 'prostocktracker', + name: 'Pro Stock Tracker', + origin: 'United Kingdom', + pricingPerYear: '$60', + slogan: 'The stock portfolio tracker built for long-term investors' + }, { founded: 2015, hasSelfHostingAbility: false, @@ -1014,6 +1044,16 @@ export const personalFinanceTools: Product[] = [ regions: ['Austria', 'Germany', 'Switzerland'], slogan: 'Dein Vermögen immer im Blick' }, + { + founded: 2025, + hasFreePlan: false, + hasSelfHostingAbility: false, + key: 'turbobulls', + name: 'Turbobulls', + origin: 'Romania', + pricingPerYear: '€39.99', + slogan: 'Your complete financial dashboard. Actually private.' + }, { hasFreePlan: true, hasSelfHostingAbility: false, diff --git a/libs/common/src/lib/types/market-data-preset.type.ts b/libs/common/src/lib/types/market-data-preset.type.ts index 0dbf914fa..2622feac3 100644 --- a/libs/common/src/lib/types/market-data-preset.type.ts +++ b/libs/common/src/lib/types/market-data-preset.type.ts @@ -2,4 +2,5 @@ export type MarketDataPreset = | 'BENCHMARKS' | 'CURRENCIES' | 'ETF_WITHOUT_COUNTRIES' - | 'ETF_WITHOUT_SECTORS'; + | 'ETF_WITHOUT_SECTORS' + | 'NO_ACTIVITIES'; diff --git a/libs/ui/src/lib/account-balances/account-balances.component.html b/libs/ui/src/lib/account-balances/account-balances.component.html index caef922ed..29037a985 100644 --- a/libs/ui/src/lib/account-balances/account-balances.component.html +++ b/libs/ui/src/lib/account-balances/account-balances.component.html @@ -12,7 +12,7 @@ Date
  • + Name @@ -102,7 +114,12 @@ - + Asset Profiles @@ -193,13 +210,13 @@

    Platforms

    - +

    Tags

    - +
    diff --git a/apps/client/src/app/components/admin-settings/admin-settings.component.ts b/apps/client/src/app/components/admin-settings/admin-settings.component.ts index 446221058..d030abb82 100644 --- a/apps/client/src/app/components/admin-settings/admin-settings.component.ts +++ b/apps/client/src/app/components/admin-settings/admin-settings.component.ts @@ -22,20 +22,24 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, - OnDestroy, - OnInit + DestroyRef, + OnInit, + ViewChild } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; import { MatMenuModule } from '@angular/material/menu'; import { MatProgressBarModule } from '@angular/material/progress-bar'; +import { MatSort, MatSortModule } from '@angular/material/sort'; import { MatTableDataSource, MatTableModule } from '@angular/material/table'; import { RouterModule } from '@angular/router'; import { IonIcon } from '@ionic/angular/standalone'; import { addIcons } from 'ionicons'; import { ellipsisHorizontal, trashOutline } from 'ionicons/icons'; +import { get } from 'lodash'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; -import { catchError, filter, of, Subject, takeUntil } from 'rxjs'; +import { catchError, filter, of } from 'rxjs'; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, @@ -52,6 +56,7 @@ import { catchError, filter, of, Subject, takeUntil } from 'rxjs'; MatCardModule, MatMenuModule, MatProgressBarModule, + MatSortModule, MatTableModule, NgxSkeletonLoaderModule, RouterModule @@ -60,7 +65,9 @@ import { catchError, filter, of, Subject, takeUntil } from 'rxjs'; styleUrls: ['./admin-settings.component.scss'], templateUrl: './admin-settings.component.html' }) -export class GfAdminSettingsComponent implements OnDestroy, OnInit { +export class GfAdminSettingsComponent implements OnInit { + @ViewChild(MatSort) sort: MatSort; + public dataSource = new MatTableDataSource(); public defaultDateFormat: string; public displayedColumns = [ @@ -74,14 +81,13 @@ export class GfAdminSettingsComponent implements OnDestroy, OnInit { public isGhostfolioApiKeyValid: boolean; public isLoading = false; public pricingUrl: string; - - private unsubscribeSubject = new Subject(); - private user: User; + public user: User; public constructor( private adminService: AdminService, private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private notificationService: NotificationService, private userService: UserService ) { @@ -90,7 +96,7 @@ export class GfAdminSettingsComponent implements OnDestroy, OnInit { public ngOnInit() { this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -147,11 +153,6 @@ export class GfAdminSettingsComponent implements OnDestroy, OnInit { }); } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private initialize() { this.isLoading = true; @@ -159,13 +160,15 @@ export class GfAdminSettingsComponent implements OnDestroy, OnInit { this.adminService .fetchAdminData() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ dataProviders, settings }) => { const filteredProviders = dataProviders.filter(({ dataSource }) => { return dataSource !== 'MANUAL'; }); this.dataSource = new MatTableDataSource(filteredProviders); + this.dataSource.sort = this.sort; + this.dataSource.sortingDataAccessor = get; const ghostfolioApiKey = settings[ PROPERTY_API_KEY_GHOSTFOLIO @@ -185,7 +188,7 @@ export class GfAdminSettingsComponent implements OnDestroy, OnInit { filter((status) => { return status !== null; }), - takeUntil(this.unsubscribeSubject) + takeUntilDestroyed(this.destroyRef) ) .subscribe((status) => { this.ghostfolioApiStatus = status; diff --git a/apps/client/src/app/components/admin-tag/admin-tag.component.html b/apps/client/src/app/components/admin-tag/admin-tag.component.html index 98919abd8..463a817ff 100644 --- a/apps/client/src/app/components/admin-tag/admin-tag.component.html +++ b/apps/client/src/app/components/admin-tag/admin-tag.component.html @@ -45,7 +45,11 @@ Activities
    - {{ element.activityCount }} + - + @@ -37,7 +37,7 @@
    @@ -48,7 +48,7 @@
    - {{ accountCurrency }} + {{ accountCurrency() }}
    @@ -58,7 +58,7 @@
    - @if (showActions) { + @if (showActions()) {
    diff --git a/libs/ui/src/lib/account-balances/account-balances.component.ts b/libs/ui/src/lib/account-balances/account-balances.component.ts index 608ee1c75..7b26263b0 100644 --- a/libs/ui/src/lib/account-balances/account-balances.component.ts +++ b/libs/ui/src/lib/account-balances/account-balances.component.ts @@ -10,12 +10,12 @@ import { ChangeDetectionStrategy, Component, EventEmitter, - Input, OnChanges, - OnDestroy, OnInit, Output, - ViewChild + inject, + input, + viewChild } from '@angular/core'; import { FormGroup, @@ -39,8 +39,7 @@ import { ellipsisHorizontal, trashOutline } from 'ionicons/icons'; -import { get } from 'lodash'; -import { Subject } from 'rxjs'; +import { get, isNil } from 'lodash'; import { GfValueComponent } from '../value'; @@ -63,50 +62,44 @@ import { GfValueComponent } from '../value'; styleUrls: ['./account-balances.component.scss'], templateUrl: './account-balances.component.html' }) -export class GfAccountBalancesComponent - implements OnChanges, OnDestroy, OnInit -{ - @Input() accountBalances: AccountBalancesResponse['balances']; - @Input() accountCurrency: string; - @Input() accountId: string; - @Input() locale = getLocale(); - @Input() showActions = true; - +export class GfAccountBalancesComponent implements OnChanges, OnInit { @Output() accountBalanceCreated = new EventEmitter(); @Output() accountBalanceDeleted = new EventEmitter(); - @ViewChild(MatSort) sort: MatSort; + public readonly accountBalances = + input.required(); + public readonly accountCurrency = input.required(); + public readonly accountId = input.required(); + public readonly displayedColumns: string[] = ['date', 'value', 'actions']; + public readonly locale = input(getLocale()); + public readonly showActions = input(true); + public readonly sort = viewChild(MatSort); public accountBalanceForm = new FormGroup({ - balance: new FormControl(0, Validators.required), - date: new FormControl(new Date(), Validators.required) + balance: new FormControl(0, (control) => Validators.required(control)), + date: new FormControl(new Date(), (control) => Validators.required(control)) }); public dataSource = new MatTableDataSource< AccountBalancesResponse['balances'][0] >(); - public displayedColumns: string[] = ['date', 'value', 'actions']; - public Validators = Validators; - - private unsubscribeSubject = new Subject(); + private dateAdapter = inject>(DateAdapter); + private notificationService = inject(NotificationService); - public constructor( - private dateAdapter: DateAdapter, - private notificationService: NotificationService - ) { + public constructor() { addIcons({ calendarClearOutline, ellipsisHorizontal, trashOutline }); } public ngOnInit() { - this.dateAdapter.setLocale(this.locale); + this.dateAdapter.setLocale(this.locale()); } public ngOnChanges() { - if (this.accountBalances) { - this.dataSource = new MatTableDataSource(this.accountBalances); + if (this.accountBalances()) { + this.dataSource = new MatTableDataSource(this.accountBalances()); - this.dataSource.sort = this.sort; + this.dataSource.sort = this.sort(); this.dataSource.sortingDataAccessor = get; } } @@ -122,10 +115,16 @@ export class GfAccountBalancesComponent } public async onSubmitAccountBalance() { + const { balance, date } = this.accountBalanceForm.value; + + if (isNil(balance) || !date) { + return; + } + const accountBalance: CreateAccountBalanceDto = { - accountId: this.accountId, - balance: this.accountBalanceForm.get('balance').value, - date: format(this.accountBalanceForm.get('date').value, DATE_FORMAT) + balance, + accountId: this.accountId(), + date: format(date, DATE_FORMAT) }; try { @@ -141,9 +140,4 @@ export class GfAccountBalancesComponent this.accountBalanceCreated.emit(accountBalance); } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/libs/ui/src/lib/accounts-table/accounts-table.component.ts b/libs/ui/src/lib/accounts-table/accounts-table.component.ts index d486b775f..99e68c679 100644 --- a/libs/ui/src/lib/accounts-table/accounts-table.component.ts +++ b/libs/ui/src/lib/accounts-table/accounts-table.component.ts @@ -53,7 +53,7 @@ import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; templateUrl: './accounts-table.component.html' }) export class GfAccountsTableComponent { - public readonly accounts = input.required(); + public readonly accounts = input.required(); public readonly activitiesCount = input(); public readonly baseCurrency = input(); public readonly hasPermissionToOpenDetails = input(true); diff --git a/libs/ui/src/lib/activities-filter/activities-filter.component.html b/libs/ui/src/lib/activities-filter/activities-filter.component.html index fd22ed351..d87ce16ce 100644 --- a/libs/ui/src/lib/activities-filter/activities-filter.component.html +++ b/libs/ui/src/lib/activities-filter/activities-filter.component.html @@ -10,7 +10,7 @@ [removable]="true" (removed)="onRemoveFilter(filter)" > - {{ filter.label | gfSymbol }} + {{ filter.label ?? '' | gfSymbol }} @@ -23,7 +23,7 @@ [matAutocomplete]="autocomplete" [matChipInputFor]="chipList" [matChipInputSeparatorKeyCodes]="separatorKeysCodes" - [placeholder]="placeholder" + [placeholder]="placeholder()" (matChipInputTokenEnd)="onAddFilter($event)" /> @@ -35,7 +35,7 @@ @for (filter of filterGroup.filters; track filter) { - {{ filter.label | gfSymbol }} + {{ filter.label ?? '' | gfSymbol }} } @@ -46,7 +46,7 @@ disabled mat-icon-button matSuffix - [ngClass]="{ 'd-none': !isLoading }" + [ngClass]="{ 'd-none': !isLoading() }" > diff --git a/libs/ui/src/lib/activities-filter/activities-filter.component.ts b/libs/ui/src/lib/activities-filter/activities-filter.component.ts index 34f883c67..6b58e6aec 100644 --- a/libs/ui/src/lib/activities-filter/activities-filter.component.ts +++ b/libs/ui/src/lib/activities-filter/activities-filter.component.ts @@ -7,15 +7,16 @@ import { CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, Component, + DestroyRef, ElementRef, - EventEmitter, Input, OnChanges, - OnDestroy, - Output, SimpleChanges, - ViewChild + ViewChild, + input, + output } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { MatAutocomplete, @@ -30,8 +31,7 @@ import { IonIcon } from '@ionic/angular/standalone'; import { addIcons } from 'ionicons'; import { closeOutline, searchOutline } from 'ionicons/icons'; import { groupBy } from 'lodash'; -import { BehaviorSubject, Observable, Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; +import { BehaviorSubject } from 'rxjs'; import { translate } from '../i18n'; @@ -53,28 +53,26 @@ import { translate } from '../i18n'; styleUrls: ['./activities-filter.component.scss'], templateUrl: './activities-filter.component.html' }) -export class GfActivitiesFilterComponent implements OnChanges, OnDestroy { +export class GfActivitiesFilterComponent implements OnChanges { @Input() allFilters: Filter[]; - @Input() isLoading: boolean; - @Input() placeholder: string; - @Output() valueChanged = new EventEmitter(); + @ViewChild('autocomplete') protected matAutocomplete: MatAutocomplete; + @ViewChild('searchInput') protected searchInput: ElementRef; - @ViewChild('autocomplete') matAutocomplete: MatAutocomplete; - @ViewChild('searchInput') searchInput: ElementRef; + public readonly isLoading = input.required(); + public readonly placeholder = input.required(); + public readonly valueChanged = output(); - public filterGroups$: Subject = new BehaviorSubject([]); - public filters$: Subject = new BehaviorSubject([]); - public filters: Observable = this.filters$.asObservable(); - public searchControl = new FormControl(undefined); - public selectedFilters: Filter[] = []; - public separatorKeysCodes: number[] = [ENTER, COMMA]; + protected readonly filterGroups$ = new BehaviorSubject([]); + protected readonly searchControl = new FormControl( + null + ); + protected selectedFilters: Filter[] = []; + protected readonly separatorKeysCodes: number[] = [ENTER, COMMA]; - private unsubscribeSubject = new Subject(); - - public constructor() { + public constructor(private destroyRef: DestroyRef) { this.searchControl.valueChanges - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((filterOrSearchTerm) => { if (filterOrSearchTerm) { const searchTerm = @@ -97,41 +95,39 @@ export class GfActivitiesFilterComponent implements OnChanges, OnDestroy { } } - public onAddFilter({ input, value }: MatChipInputEvent) { + public onAddFilter({ chipInput, value }: MatChipInputEvent) { if (value?.trim()) { this.updateFilters(); } // Reset the input value - if (input) { - input.value = ''; + if (chipInput.inputElement) { + chipInput.inputElement.value = ''; } - this.searchControl.setValue(undefined); + this.searchControl.setValue(null); } public onRemoveFilter(aFilter: Filter) { - this.selectedFilters = this.selectedFilters.filter((filter) => { - return filter.id !== aFilter.id; + this.selectedFilters = this.selectedFilters.filter(({ id }) => { + return id !== aFilter.id; }); this.updateFilters(); } public onSelectFilter(event: MatAutocompleteSelectedEvent) { - this.selectedFilters.push( - this.allFilters.find((filter) => { - return filter.id === event.option.value; - }) - ); + const filter = this.allFilters.find(({ id }) => { + return id === event.option.value; + }); + + if (filter) { + this.selectedFilters.push(filter); + } + this.updateFilters(); this.searchInput.nativeElement.value = ''; - this.searchControl.setValue(undefined); - } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); + this.searchControl.setValue(null); } private getGroupedFilters(searchTerm?: string) { @@ -139,23 +135,23 @@ export class GfActivitiesFilterComponent implements OnChanges, OnDestroy { this.allFilters .filter((filter) => { // Filter selected filters - return !this.selectedFilters.some((selectedFilter) => { - return selectedFilter.id === filter.id; + return !this.selectedFilters.some(({ id }) => { + return id === filter.id; }); }) .filter((filter) => { if (searchTerm) { // Filter by search term return filter.label - .toLowerCase() + ?.toLowerCase() .includes(searchTerm.toLowerCase()); } return filter; }) - .sort((a, b) => a.label?.localeCompare(b.label)), - (filter) => { - return filter.type; + .sort((a, b) => (a.label ?? '').localeCompare(b.label ?? '')), + ({ type }) => { + return type; } ); diff --git a/libs/ui/src/lib/assistant/assistant-list-item/assistant-list-item.component.ts b/libs/ui/src/lib/assistant/assistant-list-item/assistant-list-item.component.ts index c2ad2462e..05750cea4 100644 --- a/libs/ui/src/lib/assistant/assistant-list-item/assistant-list-item.component.ts +++ b/libs/ui/src/lib/assistant/assistant-list-item/assistant-list-item.component.ts @@ -7,12 +7,12 @@ import { ChangeDetectorRef, Component, ElementRef, - EventEmitter, HostBinding, Input, OnChanges, - Output, - ViewChild + ViewChild, + inject, + output } from '@angular/core'; import { Params, RouterModule } from '@angular/router'; @@ -33,21 +33,23 @@ export class GfAssistantListItemComponent implements FocusableOption, OnChanges { @HostBinding('attr.tabindex') tabindex = -1; - @HostBinding('class.has-focus') get getHasFocus() { - return this.hasFocus; - } @Input() item: SearchResultItem; - @Output() clicked = new EventEmitter(); - - @ViewChild('link') public linkElement: ElementRef; + @ViewChild('link') public linkElement: ElementRef; public hasFocus = false; public queryParams: Params; public routerLink: string[]; - public constructor(private changeDetectorRef: ChangeDetectorRef) {} + protected readonly clicked = output(); + + private readonly changeDetectorRef = inject(ChangeDetectorRef); + + @HostBinding('class.has-focus') + public get getHasFocus() { + return this.hasFocus; + } public ngOnChanges() { if (this.item?.mode === SearchMode.ACCOUNT) { @@ -65,7 +67,7 @@ export class GfAssistantListItemComponent }; this.routerLink = - internalRoutes.adminControl.subRoutes.marketData.routerLink; + internalRoutes.adminControl.subRoutes?.marketData.routerLink ?? []; } else if (this.item?.mode === SearchMode.HOLDING) { this.queryParams = { dataSource: this.item.dataSource, diff --git a/libs/ui/src/lib/assistant/assistant-list-item/assistant-list-item.html b/libs/ui/src/lib/assistant/assistant-list-item/assistant-list-item.html index fd2c4011d..36179b719 100644 --- a/libs/ui/src/lib/assistant/assistant-list-item/assistant-list-item.html +++ b/libs/ui/src/lib/assistant/assistant-list-item/assistant-list-item.html @@ -8,7 +8,7 @@ @if (item && isAsset(item)) {
    {{ item?.symbol | gfSymbol }} · {{ item?.currency }} + >{{ item?.symbol ?? '' | gfSymbol }} · {{ item?.currency }} @if (item?.assetSubClassString) { · {{ item.assetSubClassString }} } diff --git a/libs/ui/src/lib/assistant/assistant.component.ts b/libs/ui/src/lib/assistant/assistant.component.ts index 2b0216613..1c67e4fa2 100644 --- a/libs/ui/src/lib/assistant/assistant.component.ts +++ b/libs/ui/src/lib/assistant/assistant.component.ts @@ -12,16 +12,15 @@ import { ChangeDetectorRef, Component, ElementRef, - EventEmitter, HostListener, Input, OnChanges, OnDestroy, OnInit, - Output, QueryList, ViewChild, - ViewChildren + ViewChildren, + output } from '@angular/core'; import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; @@ -86,37 +85,7 @@ import { templateUrl: './assistant.html' }) export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit { - @HostListener('document:keydown', ['$event']) onKeydown( - event: KeyboardEvent - ) { - if (!this.isOpen) { - return; - } - - if (event.key === 'ArrowDown' || event.key === 'ArrowUp') { - for (const item of this.assistantListItems) { - item.removeFocus(); - } - - this.keyManager.onKeydown(event); - - const currentAssistantListItem = this.getCurrentAssistantListItem(); - - if (currentAssistantListItem?.linkElement) { - currentAssistantListItem.linkElement.nativeElement?.scrollIntoView({ - behavior: 'smooth', - block: 'center' - }); - } - } else if (event.key === 'Enter') { - const currentAssistantListItem = this.getCurrentAssistantListItem(); - - if (currentAssistantListItem?.linkElement) { - currentAssistantListItem.linkElement.nativeElement?.click(); - event.stopPropagation(); - } - } - } + public static readonly SEARCH_RESULTS_DEFAULT_LIMIT = 5; @Input() deviceType: string; @Input() hasPermissionToAccessAdminControl: boolean; @@ -124,21 +93,16 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit { @Input() hasPermissionToChangeFilters: boolean; @Input() user: User; - @Output() closed = new EventEmitter(); - @Output() dateRangeChanged = new EventEmitter(); - @Output() filtersChanged = new EventEmitter(); - @ViewChild('menuTrigger') menuTriggerElement: MatMenuTrigger; - @ViewChild('search', { static: true }) searchElement: ElementRef; + @ViewChild('search', { static: true }) + searchElement: ElementRef; @ViewChildren(GfAssistantListItemComponent) assistantListItems: QueryList; - public static readonly SEARCH_RESULTS_DEFAULT_LIMIT = 5; - public accounts: AccountWithPlatform[] = []; public assetClasses: Filter[] = []; - public dateRangeFormControl = new FormControl(undefined); + public dateRangeFormControl = new FormControl(null); public dateRangeOptions: DateRangeOption[] = []; public holdings: PortfolioPosition[] = []; public isLoading = { @@ -166,6 +130,10 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit { }; public tags: Filter[] = []; + protected readonly closed = output(); + protected readonly dateRangeChanged = output(); + protected readonly filtersChanged = output(); + private readonly PRESELECTION_DELAY = 100; private filterTypes: Filter['type'][] = [ @@ -188,6 +156,37 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit { addIcons({ closeCircleOutline, closeOutline, searchOutline }); } + @HostListener('document:keydown', ['$event']) + public onKeydown(event: KeyboardEvent) { + if (!this.isOpen) { + return; + } + + if (event.key === 'ArrowDown' || event.key === 'ArrowUp') { + for (const item of this.assistantListItems) { + item.removeFocus(); + } + + this.keyManager.onKeydown(event); + + const currentAssistantListItem = this.getCurrentAssistantListItem(); + + if (currentAssistantListItem?.linkElement) { + currentAssistantListItem.linkElement.nativeElement?.scrollIntoView({ + behavior: 'smooth', + block: 'center' + }); + } + } else if (event.key === 'Enter') { + const currentAssistantListItem = this.getCurrentAssistantListItem(); + + if (currentAssistantListItem?.linkElement) { + currentAssistantListItem.linkElement.nativeElement?.click(); + event.stopPropagation(); + } + } + } + public ngOnInit() { this.assetClasses = Object.keys(AssetClass).map((assetClass) => { return { @@ -482,7 +481,7 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit { .subscribe(({ holdings }) => { this.holdings = holdings .filter(({ assetSubClass }) => { - return !['CASH'].includes(assetSubClass); + return assetSubClass && !['CASH'].includes(assetSubClass); }) .sort((a, b) => { return a.name?.localeCompare(b.name); @@ -499,23 +498,23 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit { this.filtersChanged.emit([ { - id: filterValue?.account, + id: filterValue?.account ?? '', type: 'ACCOUNT' }, { - id: filterValue?.assetClass, + id: filterValue?.assetClass ?? '', type: 'ASSET_CLASS' }, { - id: filterValue?.holding?.dataSource, + id: filterValue?.holding?.dataSource ?? '', type: 'DATA_SOURCE' }, { - id: filterValue?.holding?.symbol, + id: filterValue?.holding?.symbol ?? '', type: 'SYMBOL' }, { - id: filterValue?.tag, + id: filterValue?.tag ?? '', type: 'TAG' } ]); @@ -541,7 +540,7 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit { this.filterTypes.map((type) => { return { type, - id: null + id: '' }; }) ); @@ -673,7 +672,7 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit { dataSource, name, symbol, - assetSubClassString: translate(assetSubClass), + assetSubClassString: translate(assetSubClass ?? ''), mode: SearchMode.ASSET_PROFILE as const }; } @@ -705,7 +704,7 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit { dataSource, name, symbol, - assetSubClassString: translate(assetSubClass), + assetSubClassString: translate(assetSubClass ?? ''), mode: SearchMode.HOLDING as const }; } @@ -755,6 +754,7 @@ export class GfAssistantComponent implements OnChanges, OnDestroy, OnInit { const symbol = this.user?.settings?.['filters.symbol']; const selectedHolding = this.holdings.find((holding) => { return ( + !!(dataSource && symbol) && getAssetProfileIdentifier({ dataSource: holding.dataSource, symbol: holding.symbol diff --git a/libs/ui/src/lib/assistant/assistant.html b/libs/ui/src/lib/assistant/assistant.html index 307269262..79e2f31a1 100644 --- a/libs/ui/src/lib/assistant/assistant.html +++ b/libs/ui/src/lib/assistant/assistant.html @@ -186,7 +186,7 @@
    @@ -210,7 +210,7 @@ type="button" [disabled]=" !portfolioFilterForm.filterForm.dirty || - portfolioFilterForm.disabled + portfolioFilterForm.disabled() " (click)="onApplyFilters()" > diff --git a/libs/ui/src/lib/benchmark/benchmark-detail-dialog/interfaces/interfaces.ts b/libs/ui/src/lib/benchmark/benchmark-detail-dialog/interfaces/interfaces.ts index 291f4c973..b01403284 100644 --- a/libs/ui/src/lib/benchmark/benchmark-detail-dialog/interfaces/interfaces.ts +++ b/libs/ui/src/lib/benchmark/benchmark-detail-dialog/interfaces/interfaces.ts @@ -3,7 +3,7 @@ import { ColorScheme } from '@ghostfolio/common/types'; import { DataSource } from '@prisma/client'; export interface BenchmarkDetailDialogParams { - colorScheme: ColorScheme; + colorScheme?: ColorScheme; dataSource: DataSource; deviceType: string; locale: string; diff --git a/libs/ui/src/lib/benchmark/benchmark.component.html b/libs/ui/src/lib/benchmark/benchmark.component.html index ab6db8887..8820f2ec1 100644 --- a/libs/ui/src/lib/benchmark/benchmark.component.html +++ b/libs/ui/src/lib/benchmark/benchmark.component.html @@ -15,7 +15,7 @@
    {{ element?.name }}
    - @if (showSymbol) { + @if (showSymbol()) {
    {{ element?.symbol }}
    @@ -98,7 +98,7 @@ @if (element?.performances?.allTimeHigh?.date) { } @@ -123,7 +123,7 @@ - @if (hasPermissionToDeleteItem) { + @if (hasPermissionToDeleteItem()) { + } + + @if (value || value === 0 || value === null) {
    } + @if (!hasLabel) { + + }
    } @@ -88,6 +110,9 @@ @if (size === 'large') {
    + @if (hasLabel) { + + } @if (subLabel) { {{ subLabel }} } @@ -95,6 +120,9 @@ } @else { + @if (hasLabel) { + + } }
    diff --git a/libs/ui/src/lib/value/value.component.stories.ts b/libs/ui/src/lib/value/value.component.stories.ts index a1f9d06a0..214331efc 100644 --- a/libs/ui/src/lib/value/value.component.stories.ts +++ b/libs/ui/src/lib/value/value.component.stories.ts @@ -1,3 +1,4 @@ +import '@angular/localize/init'; import { moduleMetadata } from '@storybook/angular'; import type { Meta, StoryObj } from '@storybook/angular'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; @@ -16,6 +17,13 @@ export default { deviceType: { control: 'select', options: ['desktop', 'mobile'] + }, + enableCopyToClipboardButton: { + control: 'boolean' + }, + size: { + control: 'select', + options: ['small', 'medium', 'large'] } } } as Meta; @@ -51,7 +59,11 @@ export const Label: Story = { args: { locale: 'en-US', value: 7.25 - } + }, + render: (args) => ({ + props: args, + template: `Label` + }) }; export const PerformancePositive: Story = { diff --git a/libs/ui/src/lib/value/value.component.ts b/libs/ui/src/lib/value/value.component.ts index 795e16491..9c3330466 100644 --- a/libs/ui/src/lib/value/value.component.ts +++ b/libs/ui/src/lib/value/value.component.ts @@ -1,30 +1,41 @@ import { getLocale } from '@ghostfolio/common/helper'; +import { Clipboard } from '@angular/cdk/clipboard'; import { CommonModule } from '@angular/common'; import { - CUSTOM_ELEMENTS_SCHEMA, + AfterViewInit, ChangeDetectionStrategy, + ChangeDetectorRef, Component, + computed, + CUSTOM_ELEMENTS_SCHEMA, + ElementRef, + input, Input, OnChanges, - computed, - input + ViewChild } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatSnackBar } from '@angular/material/snack-bar'; import { IonIcon } from '@ionic/angular/standalone'; +import { addIcons } from 'ionicons'; +import { copyOutline } from 'ionicons/icons'; import { isNumber } from 'lodash'; +import ms from 'ms'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, - imports: [CommonModule, IonIcon, NgxSkeletonLoaderModule], + imports: [CommonModule, IonIcon, MatButtonModule, NgxSkeletonLoaderModule], schemas: [CUSTOM_ELEMENTS_SCHEMA], selector: 'gf-value', styleUrls: ['./value.component.scss'], templateUrl: './value.component.html' }) -export class GfValueComponent implements OnChanges { +export class GfValueComponent implements AfterViewInit, OnChanges { @Input() colorizeSign = false; @Input() deviceType: string; + @Input() enableCopyToClipboardButton = false; @Input() icon = ''; @Input() isAbsolute = false; @Input() isCurrency = false; @@ -37,12 +48,26 @@ export class GfValueComponent implements OnChanges { @Input() unit = ''; @Input() value: number | string = ''; + @ViewChild('labelContent', { static: false }) + labelContent!: ElementRef; + public absoluteValue = 0; public formattedValue = ''; + public hasLabel = false; public isNumber = false; public isString = false; public useAbsoluteValue = false; + public constructor( + private changeDetectorRef: ChangeDetectorRef, + private clipboard: Clipboard, + private snackBar: MatSnackBar + ) { + addIcons({ + copyOutline + }); + } + public readonly precision = input(); private readonly formatOptions = computed(() => { @@ -59,6 +84,17 @@ export class GfValueComponent implements OnChanges { return precision !== undefined && precision >= 0; } + public ngAfterViewInit() { + if (this.labelContent) { + const element = this.labelContent.nativeElement; + + this.hasLabel = + element.children.length > 0 || element.textContent.trim().length > 0; + + this.changeDetectorRef.markForCheck(); + } + } + public ngOnChanges() { this.initializeVariables(); @@ -137,6 +173,18 @@ export class GfValueComponent implements OnChanges { } } + public onCopyValueToClipboard() { + this.clipboard.copy(String(this.value)); + + this.snackBar.open( + '✅ ' + $localize`${this.value} has been copied to the clipboard`, + undefined, + { + duration: ms('3 seconds') + } + ); + } + private initializeVariables() { this.absoluteValue = 0; this.formattedValue = ''; diff --git a/libs/ui/tsconfig.json b/libs/ui/tsconfig.json index 04f4630bc..51348a52a 100644 --- a/libs/ui/tsconfig.json +++ b/libs/ui/tsconfig.json @@ -19,6 +19,7 @@ "target": "es2020", // TODO: Remove once solved in tsconfig.base.json "strict": false, + "strictNullChecks": true, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true }, diff --git a/package-lock.json b/package-lock.json index 1731f1e7a..1f4295a6a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ghostfolio", - "version": "2.238.0", + "version": "2.251.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ghostfolio", - "version": "2.238.0", + "version": "2.251.0", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { @@ -21,26 +21,29 @@ "@angular/platform-browser-dynamic": "21.1.1", "@angular/router": "21.1.1", "@angular/service-worker": "21.1.1", + "@bull-board/api": "6.20.3", + "@bull-board/express": "6.20.3", + "@bull-board/nestjs": "6.20.3", "@codewithdan/observable-store": "2.2.15", "@date-fns/utc": "2.1.1", "@internationalized/number": "3.6.5", - "@ionic/angular": "8.7.8", + "@ionic/angular": "8.8.1", "@keyv/redis": "4.4.0", "@nestjs/bull": "11.0.4", - "@nestjs/cache-manager": "3.0.1", - "@nestjs/common": "11.1.8", - "@nestjs/config": "4.0.2", - "@nestjs/core": "11.1.8", + "@nestjs/cache-manager": "3.1.0", + "@nestjs/common": "11.1.14", + "@nestjs/config": "4.0.3", + "@nestjs/core": "11.1.14", "@nestjs/event-emitter": "3.0.1", - "@nestjs/jwt": "11.0.1", + "@nestjs/jwt": "11.0.2", "@nestjs/passport": "11.0.5", - "@nestjs/platform-express": "11.1.8", - "@nestjs/schedule": "6.0.1", + "@nestjs/platform-express": "11.1.14", + "@nestjs/schedule": "6.1.1", "@nestjs/serve-static": "5.0.4", "@openrouter/ai-sdk-provider": "0.7.2", "@prisma/client": "6.19.0", - "@simplewebauthn/browser": "13.1.0", - "@simplewebauthn/server": "13.1.1", + "@simplewebauthn/browser": "13.2.2", + "@simplewebauthn/server": "13.2.2", "ai": "4.3.16", "alphavantage": "2.2.0", "big.js": "7.0.1", @@ -51,12 +54,13 @@ "chartjs-chart-treemap": "3.1.0", "chartjs-plugin-annotation": "3.1.0", "chartjs-plugin-datalabels": "2.2.0", - "cheerio": "1.0.0", + "cheerio": "1.2.0", "class-transformer": "0.5.1", - "class-validator": "0.14.3", + "class-validator": "0.15.1", "color": "5.0.3", + "cookie-parser": "1.4.7", "countries-and-timezones": "3.8.0", - "countries-list": "3.2.2", + "countries-list": "3.3.0", "countup.js": "2.9.0", "date-fns": "4.1.0", "dotenv": "17.2.3", @@ -68,13 +72,13 @@ "helmet": "7.0.0", "http-status-codes": "2.3.0", "ionicons": "8.0.13", - "jsonpath": "1.1.1", + "jsonpath": "1.2.1", "lodash": "4.17.23", - "marked": "17.0.1", + "marked": "17.0.2", "ms": "3.0.0-canary.1", - "ng-extract-i18n-merge": "3.2.1", + "ng-extract-i18n-merge": "3.3.0", "ngx-device-detector": "11.0.0", - "ngx-markdown": "21.0.1", + "ngx-markdown": "21.1.0", "ngx-skeleton-loader": "12.0.0", "open-color": "1.9.1", "papaparse": "5.3.1", @@ -85,11 +89,11 @@ "passport-openidconnect": "0.1.2", "reflect-metadata": "0.2.2", "rxjs": "7.8.1", - "stripe": "20.3.0", - "svgmap": "2.14.0", + "stripe": "20.4.1", + "svgmap": "2.19.2", "tablemark": "4.1.0", "twitter-api-v2": "1.29.0", - "yahoo-finance2": "3.13.0", + "yahoo-finance2": "3.13.2", "zone.js": "0.16.0" }, "devDependencies": { @@ -107,22 +111,23 @@ "@eslint/eslintrc": "3.3.1", "@eslint/js": "9.35.0", "@nestjs/schematics": "11.0.9", - "@nestjs/testing": "11.1.8", - "@nx/angular": "22.4.5", - "@nx/eslint-plugin": "22.4.5", - "@nx/jest": "22.4.5", - "@nx/js": "22.4.5", - "@nx/module-federation": "22.4.5", - "@nx/nest": "22.4.5", - "@nx/node": "22.4.5", - "@nx/storybook": "22.4.5", - "@nx/web": "22.4.5", - "@nx/workspace": "22.4.5", + "@nestjs/testing": "11.1.14", + "@nx/angular": "22.5.3", + "@nx/eslint-plugin": "22.5.3", + "@nx/jest": "22.5.3", + "@nx/js": "22.5.3", + "@nx/module-federation": "22.5.3", + "@nx/nest": "22.5.3", + "@nx/node": "22.5.3", + "@nx/storybook": "22.5.3", + "@nx/web": "22.5.3", + "@nx/workspace": "22.5.3", "@schematics/angular": "21.1.1", "@storybook/addon-docs": "10.1.10", "@storybook/angular": "10.1.10", - "@trivago/prettier-plugin-sort-imports": "5.2.2", + "@trivago/prettier-plugin-sort-imports": "6.0.2", "@types/big.js": "6.2.2", + "@types/cookie-parser": "1.4.10", "@types/fast-redact": "3.0.4", "@types/google-spreadsheet": "3.1.5", "@types/jest": "30.0.0", @@ -130,7 +135,7 @@ "@types/lodash": "4.17.23", "@types/node": "22.15.17", "@types/papaparse": "5.3.7", - "@types/passport-google-oauth20": "2.0.16", + "@types/passport-google-oauth20": "2.0.17", "@types/passport-openidconnect": "0.1.3", "@typescript-eslint/eslint-plugin": "8.43.0", "@typescript-eslint/parser": "8.43.0", @@ -142,13 +147,13 @@ "jest": "30.2.0", "jest-environment-jsdom": "30.2.0", "jest-preset-angular": "16.0.0", - "nx": "22.4.5", + "nx": "22.5.3", "prettier": "3.8.1", "prettier-plugin-organize-attributes": "1.0.0", "prisma": "6.19.0", "react": "18.2.0", "react-dom": "18.2.0", - "replace-in-file": "8.3.0", + "replace-in-file": "8.4.0", "shx": "0.4.0", "storybook": "10.1.10", "ts-jest": "29.4.0", @@ -3617,6 +3622,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@borewit/text-codec": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@borewit/text-codec/-/text-codec-0.2.1.tgz", + "integrity": "sha512-k7vvKPbf7J2fZ5klGRD9AeKfUvojuZIQ3BT5u7Jfv+puwXkUBUT5PVyMDfJZpy30CBDXGMgw7fguK/lpOMBvgw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, "node_modules/@braintree/sanitize-url": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-7.1.1.tgz", @@ -3631,6 +3646,53 @@ "devOptional": true, "license": "(Apache-2.0 AND BSD-3-Clause)" }, + "node_modules/@bull-board/api": { + "version": "6.20.3", + "resolved": "https://registry.npmjs.org/@bull-board/api/-/api-6.20.3.tgz", + "integrity": "sha512-cDrsJJsmF4DbbY8/5oHxO4qFtyFjxexsWQKHowsud/8H4mtZN7MZg4fCmNzfaxc9Ov7V6r9Y9F5G2Mq6t7ZEJg==", + "license": "MIT", + "dependencies": { + "redis-info": "^3.1.0" + }, + "peerDependencies": { + "@bull-board/ui": "6.20.3" + } + }, + "node_modules/@bull-board/express": { + "version": "6.20.3", + "resolved": "https://registry.npmjs.org/@bull-board/express/-/express-6.20.3.tgz", + "integrity": "sha512-S6BGeSf/PLwjx5W1IrKxoV8G6iiMmLqT/pldZ6BiC1IDldedisTtAdL1z117swXPv1H7/3hy0vr03dUr8bUCPg==", + "license": "MIT", + "dependencies": { + "@bull-board/api": "6.20.3", + "@bull-board/ui": "6.20.3", + "ejs": "^3.1.10", + "express": "^5.2.1" + } + }, + "node_modules/@bull-board/nestjs": { + "version": "6.20.3", + "resolved": "https://registry.npmjs.org/@bull-board/nestjs/-/nestjs-6.20.3.tgz", + "integrity": "sha512-VFi96Z2M8k3G26H1ivzQnpjKszxh90vrUm78VtMZH/sh8wjm88mJFDXcOgFutOaddx7cc9VNXlKsTTcu6okPFQ==", + "license": "MIT", + "peerDependencies": { + "@bull-board/api": "^6.20.3", + "@nestjs/bull-shared": "^10.0.0 || ^11.0.0", + "@nestjs/common": "^9.0.0 || ^10.0.0 || ^11.0.0", + "@nestjs/core": "^9.0.0 || ^10.0.0 || ^11.0.0", + "reflect-metadata": "^0.1.13 || ^0.2.0", + "rxjs": "^7.8.1" + } + }, + "node_modules/@bull-board/ui": { + "version": "6.20.3", + "resolved": "https://registry.npmjs.org/@bull-board/ui/-/ui-6.20.3.tgz", + "integrity": "sha512-oANyYoW0X+xd0j/09DRyh3u7Q3wqBtXiLEWyZUJIi/Bjp/hINwiw20RwWuRcaFkqkFylEJL9l+pjmeSA9X5L2A==", + "license": "MIT", + "dependencies": { + "@bull-board/api": "6.20.3" + } + }, "node_modules/@chevrotain/cst-dts-gen": { "version": "11.0.3", "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.0.3.tgz", @@ -5008,12 +5070,12 @@ } }, "node_modules/@ionic/angular": { - "version": "8.7.8", - "resolved": "https://registry.npmjs.org/@ionic/angular/-/angular-8.7.8.tgz", - "integrity": "sha512-IBN5h3nIOwbuglLit48S7wNeg7NHtl/vaKAHDggICyzI92cSg5yYL07Fz59pszhkBlZQUB5SQnml990Zj2bZUg==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/@ionic/angular/-/angular-8.8.1.tgz", + "integrity": "sha512-Jp7LbouSHAnR00Dsa8qE1CSOZNqAfBCO0XKXScJNz8NKVoZe5fPGy/CboehGtAQ1xgzh2eDa15zMmyetXjAkYA==", "license": "MIT", "dependencies": { - "@ionic/core": "8.7.8", + "@ionic/core": "8.8.1", "ionicons": "^8.0.13", "jsonc-parser": "^3.0.0", "tslib": "^2.3.0" @@ -5027,14 +5089,17 @@ } }, "node_modules/@ionic/core": { - "version": "8.7.8", - "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.8.tgz", - "integrity": "sha512-GLWb/lz3kocpzTZTeQQ5xxoWz4CKHD6zpnbwJknTKsncebohAaw2KTe7uOw5toKQEDdohTseFuSGoDDBoRQ1Ug==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.1.tgz", + "integrity": "sha512-ksOUHyOEqoyUIVWcwCNSFZVGwNfP1DKrUVeN/Cdk/Xl9Rdd/5MLHGsrOQpWQfoCf3Csdnw+KHHPrXz/2fzMkMA==", "license": "MIT", "dependencies": { - "@stencil/core": "4.38.0", + "@stencil/core": "4.43.0", "ionicons": "^8.0.13", "tslib": "^2.1.0" + }, + "engines": { + "node": ">= 16" } }, "node_modules/@ioredis/commands": { @@ -6662,15 +6727,15 @@ } }, "node_modules/@module-federation/node": { - "version": "2.7.31", - "resolved": "https://registry.npmjs.org/@module-federation/node/-/node-2.7.31.tgz", - "integrity": "sha512-NSa0PFDKDLxmtfmCVHW9RhtfD9mcNOrp1d+cjVEoxb5x8dDI4jQTi1o3nsa9ettxs3bVtWhAUEQUNQBQ6ZA+Hw==", + "version": "2.7.32", + "resolved": "https://registry.npmjs.org/@module-federation/node/-/node-2.7.32.tgz", + "integrity": "sha512-hUj5v2GGwpNzl2gaJS4AyzCYRzJBhN8875A+ucKF9tq3jaQb5zpy3izYMISqqbN2q9a7jz3nEUgwAh3pjri+rQ==", "dev": true, "license": "MIT", "dependencies": { - "@module-federation/enhanced": "2.0.0", - "@module-federation/runtime": "2.0.0", - "@module-federation/sdk": "2.0.0", + "@module-federation/enhanced": "2.0.1", + "@module-federation/runtime": "2.0.1", + "@module-federation/sdk": "2.0.1", "btoa": "1.2.1", "encoding": "^0.1.13", "node-fetch": "2.7.0" @@ -6685,26 +6750,26 @@ } }, "node_modules/@module-federation/node/node_modules/@module-federation/bridge-react-webpack-plugin": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@module-federation/bridge-react-webpack-plugin/-/bridge-react-webpack-plugin-2.0.0.tgz", - "integrity": "sha512-AVT/rZK6RHva6ZTYfsyQ8oP4xYNTws3OzqKW/YxWaLXwQ3oG9ZbF7fKl4jIKoMKuuy2L9MGVXS4CYPZy0s8fXg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@module-federation/bridge-react-webpack-plugin/-/bridge-react-webpack-plugin-2.0.1.tgz", + "integrity": "sha512-D7LMW5EMAJShOMR1aZDAJ6s+MdsYDHaQyJADLQ3LaY0sne/BkVqkPikUwcO1IwOwKbXjYsDlQVOEvk9wZVRFhA==", "dev": true, "license": "MIT", "dependencies": { - "@module-federation/sdk": "2.0.0", + "@module-federation/sdk": "2.0.1", "@types/semver": "7.5.8", "semver": "7.6.3" } }, "node_modules/@module-federation/node/node_modules/@module-federation/cli": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@module-federation/cli/-/cli-2.0.0.tgz", - "integrity": "sha512-IWGWbdgoeNcuA5jzqPr6pLTN1hovMQh9A1lgJp5fAvKfICfFXKq7K8nwMAQrWD6iEKApIenI0madk1Dg2PU3pw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@module-federation/cli/-/cli-2.0.1.tgz", + "integrity": "sha512-2SL5Y8iODNX10y9T3CBLhHjSXo4afnA1BK82m4sNfZebuVO+o34bxewqwod9xfWq9xhTZmOSFZ+n+lgTKRv+CQ==", "dev": true, "license": "MIT", "dependencies": { - "@module-federation/dts-plugin": "2.0.0", - "@module-federation/sdk": "2.0.0", + "@module-federation/dts-plugin": "2.0.1", + "@module-federation/sdk": "2.0.1", "chalk": "3.0.0", "commander": "11.1.0", "jiti": "2.4.2" @@ -6717,14 +6782,14 @@ } }, "node_modules/@module-federation/node/node_modules/@module-federation/data-prefetch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@module-federation/data-prefetch/-/data-prefetch-2.0.0.tgz", - "integrity": "sha512-KPyZoqNrb5WgFY2owYnMaO2Mg2DYD6KXLVI7GPguj7Z/4pPKEC+SUjWU2FuSfTeyE6ZIi0iFGdwerxzlQ6nfmw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@module-federation/data-prefetch/-/data-prefetch-2.0.1.tgz", + "integrity": "sha512-Kq0P1OABGt6QAvs6TaE/zY9Ut9Y/oJFrzoSF3eWaCYbUAr2KD2SpTyMsPz4ssBzjeKXTgimugh6tHHd6mpCBIQ==", "dev": true, "license": "MIT", "dependencies": { - "@module-federation/runtime": "2.0.0", - "@module-federation/sdk": "2.0.0", + "@module-federation/runtime": "2.0.1", + "@module-federation/sdk": "2.0.1", "fs-extra": "9.1.0" }, "peerDependencies": { @@ -6741,16 +6806,16 @@ } }, "node_modules/@module-federation/node/node_modules/@module-federation/dts-plugin": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@module-federation/dts-plugin/-/dts-plugin-2.0.0.tgz", - "integrity": "sha512-YyYMgLNARKdf3FLihnIzzUTgafHrqzR9YnKPmrfuCm2Jit+USqFT4QO58hcb0F5KSEyjB2ARPz9RM4XAVZhzMg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@module-federation/dts-plugin/-/dts-plugin-2.0.1.tgz", + "integrity": "sha512-PLneTsf1fQS5/RTBedtLAAmCPRdMfIlhfJkOa8QH3WDJaQsqm8Wb3r2cTUBf2aNj/bP3aH/y6Hs9JFB/4x0l5g==", "dev": true, "license": "MIT", "dependencies": { - "@module-federation/error-codes": "2.0.0", - "@module-federation/managers": "2.0.0", - "@module-federation/sdk": "2.0.0", - "@module-federation/third-party-dts-extractor": "2.0.0", + "@module-federation/error-codes": "2.0.1", + "@module-federation/managers": "2.0.1", + "@module-federation/sdk": "2.0.1", + "@module-federation/third-party-dts-extractor": "2.0.1", "adm-zip": "^0.5.10", "ansi-colors": "^4.1.3", "axios": "^1.12.0", @@ -6775,23 +6840,23 @@ } }, "node_modules/@module-federation/node/node_modules/@module-federation/enhanced": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@module-federation/enhanced/-/enhanced-2.0.0.tgz", - "integrity": "sha512-xeVrGvypYMvN8gJulbro3j1t8+aS1f9xjj4quwAAqgJF0Nz8bt7sXUYJyjUHPmC2UZsShZ0GnPHJNtI8/2GYjA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@module-federation/bridge-react-webpack-plugin": "2.0.0", - "@module-federation/cli": "2.0.0", - "@module-federation/data-prefetch": "2.0.0", - "@module-federation/dts-plugin": "2.0.0", - "@module-federation/error-codes": "2.0.0", - "@module-federation/inject-external-runtime-core-plugin": "2.0.0", - "@module-federation/managers": "2.0.0", - "@module-federation/manifest": "2.0.0", - "@module-federation/rspack": "2.0.0", - "@module-federation/runtime-tools": "2.0.0", - "@module-federation/sdk": "2.0.0", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@module-federation/enhanced/-/enhanced-2.0.1.tgz", + "integrity": "sha512-EZIARQ/8ScoTP6PV8+E4SsmMYWK4ErrikZJ0G/FX8wvK8mCtdoKatFtvDN9++P6Nl78kN9zHYgAV4AHKdBVjfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@module-federation/bridge-react-webpack-plugin": "2.0.1", + "@module-federation/cli": "2.0.1", + "@module-federation/data-prefetch": "2.0.1", + "@module-federation/dts-plugin": "2.0.1", + "@module-federation/error-codes": "2.0.1", + "@module-federation/inject-external-runtime-core-plugin": "2.0.1", + "@module-federation/managers": "2.0.1", + "@module-federation/manifest": "2.0.1", + "@module-federation/rspack": "2.0.1", + "@module-federation/runtime-tools": "2.0.1", + "@module-federation/sdk": "2.0.1", "btoa": "^1.2.1", "schema-utils": "^4.3.0", "upath": "2.0.1" @@ -6817,62 +6882,62 @@ } }, "node_modules/@module-federation/node/node_modules/@module-federation/error-codes": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@module-federation/error-codes/-/error-codes-2.0.0.tgz", - "integrity": "sha512-9oE+hXuPv2zej7AxJ5hOgeRqlPs98meooV2FiutTfftLAyy2N6+Kwmmz5NR9d9t91weJj8N0cSHFoyenNHKTVg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@module-federation/error-codes/-/error-codes-2.0.1.tgz", + "integrity": "sha512-2bJF/ft+qL9L6Zvq2t/G9/f/0wFL73cM8/NJ04uyYz9BjIgvx28K5qu8/6+IwgEEKATG7vOhBBVj6wH3S+5ASA==", "dev": true, "license": "MIT" }, "node_modules/@module-federation/node/node_modules/@module-federation/inject-external-runtime-core-plugin": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@module-federation/inject-external-runtime-core-plugin/-/inject-external-runtime-core-plugin-2.0.0.tgz", - "integrity": "sha512-aZ6f4UU7KM5zBnHf3xsb2guqsfaEd6IlmuldbpED3JPk4ITwZk0DbvxRMr4prde7cfj8RH0nKMz2kmMncp+lIQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@module-federation/inject-external-runtime-core-plugin/-/inject-external-runtime-core-plugin-2.0.1.tgz", + "integrity": "sha512-oAA7G+4GCHM+WRYfscR/x4GwCyM9CEqfdD9/x2L6y8mtLWK9anRLKTocsI759AvzXsbT1m3EQ5ki1O6wlwDu3g==", "dev": true, "license": "MIT", "peerDependencies": { - "@module-federation/runtime-tools": "2.0.0" + "@module-federation/runtime-tools": "2.0.1" } }, "node_modules/@module-federation/node/node_modules/@module-federation/managers": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@module-federation/managers/-/managers-2.0.0.tgz", - "integrity": "sha512-ZmkRIujH+T3xvkmy04TNvviFH8xFOrNeKCLb4tlH4ifU/kLfjTu+PYO/KAEIsgtmrDnd52zTf22dg3ok85OAHA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@module-federation/managers/-/managers-2.0.1.tgz", + "integrity": "sha512-KR01lSlcYRQ9C6hW2a8CQQtAE0LvfTLgtV/6ZNUTagw8sRfeDln+ggrZsYilKu9zl0i8RPDgpv/kS60o4lcxCQ==", "dev": true, "license": "MIT", "dependencies": { - "@module-federation/sdk": "2.0.0", + "@module-federation/sdk": "2.0.1", "find-pkg": "2.0.0", "fs-extra": "9.1.0" } }, "node_modules/@module-federation/node/node_modules/@module-federation/manifest": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@module-federation/manifest/-/manifest-2.0.0.tgz", - "integrity": "sha512-AXwYyGiDJdfP9MteKyIdJrLwG5tp4qKaq0uOPiWHilYN3/21G0DM7f30HgJqgx3WSTFSh7hcq0a3V3EZHH/9TA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@module-federation/manifest/-/manifest-2.0.1.tgz", + "integrity": "sha512-p8nYGjHWp17MsYdW/Vv0ogBDiTTsI1PHWPQbvVIqLQXDqwiesaRSRR1zziECXQoEL8lV5Bs+uSkcaJGhea9P+A==", "dev": true, "license": "MIT", "dependencies": { - "@module-federation/dts-plugin": "2.0.0", - "@module-federation/managers": "2.0.0", - "@module-federation/sdk": "2.0.0", + "@module-federation/dts-plugin": "2.0.1", + "@module-federation/managers": "2.0.1", + "@module-federation/sdk": "2.0.1", "chalk": "3.0.0", "find-pkg": "2.0.0" } }, "node_modules/@module-federation/node/node_modules/@module-federation/rspack": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@module-federation/rspack/-/rspack-2.0.0.tgz", - "integrity": "sha512-1kziarKrPRM+rJax/AaMEZTwu7ORGed2xSxfdoP9GEbAFEGyNliadvw4kB6PqAfLad3PI4lQMX2vGMLI1KoyVQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@module-federation/rspack/-/rspack-2.0.1.tgz", + "integrity": "sha512-SAlNE8iclFmzrKtx3/C2GivXYx6nPzx4MgQV01QG/a4LpnLbwlxzdZu3rqQ2swp4NNWT/t/GT7Y+7gfhyVa7mg==", "dev": true, "license": "MIT", "dependencies": { - "@module-federation/bridge-react-webpack-plugin": "2.0.0", - "@module-federation/dts-plugin": "2.0.0", - "@module-federation/inject-external-runtime-core-plugin": "2.0.0", - "@module-federation/managers": "2.0.0", - "@module-federation/manifest": "2.0.0", - "@module-federation/runtime-tools": "2.0.0", - "@module-federation/sdk": "2.0.0", + "@module-federation/bridge-react-webpack-plugin": "2.0.1", + "@module-federation/dts-plugin": "2.0.1", + "@module-federation/inject-external-runtime-core-plugin": "2.0.1", + "@module-federation/managers": "2.0.1", + "@module-federation/manifest": "2.0.1", + "@module-federation/runtime-tools": "2.0.1", + "@module-federation/sdk": "2.0.1", "btoa": "1.2.1" }, "peerDependencies": { @@ -6890,50 +6955,50 @@ } }, "node_modules/@module-federation/node/node_modules/@module-federation/runtime": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@module-federation/runtime/-/runtime-2.0.0.tgz", - "integrity": "sha512-vPxQrmQNq3Z1T+1fkHEvFwTdJq9wuCLvdp/lpu9k2Oy7QP/Pj6QoQ/S7J5MCIAoRwj8Wj3z3ma21/DyHwLGvzA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@module-federation/runtime/-/runtime-2.0.1.tgz", + "integrity": "sha512-UQ72P5Oo40dS6vdhHetwTtIsbGciEr+bjoYvDgh1WLPfFlTYd8zo9cLfqaf3juuPfV3cMVARAVPmh16lQYpUGA==", "dev": true, "license": "MIT", "dependencies": { - "@module-federation/error-codes": "2.0.0", - "@module-federation/runtime-core": "2.0.0", - "@module-federation/sdk": "2.0.0" + "@module-federation/error-codes": "2.0.1", + "@module-federation/runtime-core": "2.0.1", + "@module-federation/sdk": "2.0.1" } }, "node_modules/@module-federation/node/node_modules/@module-federation/runtime-core": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@module-federation/runtime-core/-/runtime-core-2.0.0.tgz", - "integrity": "sha512-UhIGUs7Mg+TwMI2lgaLnj4UehpoyXbR7HDb2+vLikgBulPmFtodeWfsxCgENEwKsIY1vS0lOun15lNOn1vo3Xg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@module-federation/runtime-core/-/runtime-core-2.0.1.tgz", + "integrity": "sha512-gOuCPSHoQGUGwlxfSTMInFX+QvLxdEWegGGMiLdU5vqbXuva4E9M+kXBBO7/0MkcBPMmVs0wOJGm0XOLeV2f1Q==", "dev": true, "license": "MIT", "dependencies": { - "@module-federation/error-codes": "2.0.0", - "@module-federation/sdk": "2.0.0" + "@module-federation/error-codes": "2.0.1", + "@module-federation/sdk": "2.0.1" } }, "node_modules/@module-federation/node/node_modules/@module-federation/runtime-tools": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@module-federation/runtime-tools/-/runtime-tools-2.0.0.tgz", - "integrity": "sha512-eMDQN4hYpwvUnCNMjfQdtPVzYaO2DdauemHVc4HnyibgqijRzBwJh9bI2ph4R1xfYEm18+QmTrfXrRlaK2Xizw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@module-federation/runtime-tools/-/runtime-tools-2.0.1.tgz", + "integrity": "sha512-AStdwBtsGB3jIfDg9oP+KyVPsimdaeHsP855gqCxDp1hi2+GKjlZWZx9ThkS8NytVSXSUysxqoUL1ivDoKgcCQ==", "dev": true, "license": "MIT", "dependencies": { - "@module-federation/runtime": "2.0.0", - "@module-federation/webpack-bundler-runtime": "2.0.0" + "@module-federation/runtime": "2.0.1", + "@module-federation/webpack-bundler-runtime": "2.0.1" } }, "node_modules/@module-federation/node/node_modules/@module-federation/sdk": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@module-federation/sdk/-/sdk-2.0.0.tgz", - "integrity": "sha512-JYd1wTulsaoLT7HTk2oXL5y5797Z+H4mzxuUEKnSJo7R34RZSqehsqPSND7n0HT/1nf7uyn0Rb4qBfR3BVvdHQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@module-federation/sdk/-/sdk-2.0.1.tgz", + "integrity": "sha512-32PwudojGjog51cwpTali7D6ud82oVgsyvOx9JjAzhvXBX96YI4mRsursuWcthDxmigJP9ZvUTXDuRUEDh1OQA==", "dev": true, "license": "MIT" }, "node_modules/@module-federation/node/node_modules/@module-federation/third-party-dts-extractor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@module-federation/third-party-dts-extractor/-/third-party-dts-extractor-2.0.0.tgz", - "integrity": "sha512-B99+Wkbd2xIodVTjNCeFtFC89Uh2/AtYkSESlz4+6Cec42wyqrGxyfYm4qRY0LhJI+YmZXLk/RTm85m15eBKKg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@module-federation/third-party-dts-extractor/-/third-party-dts-extractor-2.0.1.tgz", + "integrity": "sha512-neKSr6FNUeGRh+YR57l/QZUzPytJXuJx+babF7j5iGJG3FP+kfizr6QD0hgVis5KEoXMVbQ8yyvG0slERizeyw==", "dev": true, "license": "MIT", "dependencies": { @@ -6943,14 +7008,14 @@ } }, "node_modules/@module-federation/node/node_modules/@module-federation/webpack-bundler-runtime": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@module-federation/webpack-bundler-runtime/-/webpack-bundler-runtime-2.0.0.tgz", - "integrity": "sha512-XxiFR/A1G1fa9hTyylWNbs6yEU2hC7FqHAArFptD4U9qp/xyoLgqbK4M8LwltOAyAM8hRofcMdSyiRKVlWqAfQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@module-federation/webpack-bundler-runtime/-/webpack-bundler-runtime-2.0.1.tgz", + "integrity": "sha512-u1NId3SF4lHDTmD2CHFEszulmXmIq1TGw9JYvnLx5rKJL7xt3aNxcb1GvkaYbRNVBXhSMjJ75E5LsQlZzyBx9A==", "dev": true, "license": "MIT", "dependencies": { - "@module-federation/runtime": "2.0.0", - "@module-federation/sdk": "2.0.0" + "@module-federation/runtime": "2.0.1", + "@module-federation/sdk": "2.0.1" } }, "node_modules/@module-federation/node/node_modules/jiti": { @@ -7531,9 +7596,9 @@ } }, "node_modules/@nestjs/cache-manager": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@nestjs/cache-manager/-/cache-manager-3.0.1.tgz", - "integrity": "sha512-4UxTnR0fsmKL5YDalU2eLFVnL+OBebWUpX+hEduKGncrVKH4PPNoiRn1kXyOCjmzb0UvWgqubpssNouc8e0MCw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@nestjs/cache-manager/-/cache-manager-3.1.0.tgz", + "integrity": "sha512-pEIqYZrBcE8UdkJmZRduurvoUfdU+3kRPeO1R2muiMbZnRuqlki5klFFNllO9LyYWzrx98bd1j0PSPKSJk1Wbw==", "license": "MIT", "peerDependencies": { "@nestjs/common": "^9.0.0 || ^10.0.0 || ^11.0.0", @@ -7544,12 +7609,12 @@ } }, "node_modules/@nestjs/common": { - "version": "11.1.8", - "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-11.1.8.tgz", - "integrity": "sha512-bbsOqwld/GdBfiRNc4nnjyWWENDEicq4SH+R5AuYatvf++vf1x5JIsHB1i1KtfZMD3eRte0D4K9WXuAYil6XAg==", + "version": "11.1.14", + "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-11.1.14.tgz", + "integrity": "sha512-IN/tlqd7Nl9gl6f0jsWEuOrQDaCI9vHzxv0fisHysfBQzfQIkqlv5A7w4Qge02BUQyczXT9HHPgHtWHCxhjRng==", "license": "MIT", "dependencies": { - "file-type": "21.0.0", + "file-type": "21.3.0", "iterare": "1.2.1", "load-esm": "1.0.3", "tslib": "2.8.1", @@ -7575,57 +7640,24 @@ } }, "node_modules/@nestjs/config": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@nestjs/config/-/config-4.0.2.tgz", - "integrity": "sha512-McMW6EXtpc8+CwTUwFdg6h7dYcBUpH5iUILCclAsa+MbCEvC9ZKu4dCHRlJqALuhjLw97pbQu62l4+wRwGeZqA==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@nestjs/config/-/config-4.0.3.tgz", + "integrity": "sha512-FQ3M3Ohqfl+nHAn5tp7++wUQw0f2nAk+SFKe8EpNRnIifPqvfJP6JQxPKtFLMOHbyer4X646prFG4zSRYEssQQ==", "license": "MIT", "dependencies": { - "dotenv": "16.4.7", - "dotenv-expand": "12.0.1", - "lodash": "4.17.21" + "dotenv": "17.2.3", + "dotenv-expand": "12.0.3", + "lodash": "4.17.23" }, "peerDependencies": { "@nestjs/common": "^10.0.0 || ^11.0.0", "rxjs": "^7.1.0" } }, - "node_modules/@nestjs/config/node_modules/dotenv": { - "version": "16.4.7", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", - "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/@nestjs/config/node_modules/dotenv-expand": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-12.0.1.tgz", - "integrity": "sha512-LaKRbou8gt0RNID/9RoI+J2rvXsBRPMV7p+ElHlPhcSARbCPDYcYG2s1TIzAfWv4YSgyY5taidWzzs31lNV3yQ==", - "license": "BSD-2-Clause", - "dependencies": { - "dotenv": "^16.4.5" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/@nestjs/config/node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "license": "MIT" - }, "node_modules/@nestjs/core": { - "version": "11.1.8", - "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-11.1.8.tgz", - "integrity": "sha512-7riWfmTmMhCJHZ5ZiaG+crj4t85IPCq/wLRuOUSigBYyFT2JZj0lVHtAdf4Davp9ouNI8GINBDt9h9b5Gz9nTw==", + "version": "11.1.14", + "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-11.1.14.tgz", + "integrity": "sha512-7OXPPMoDr6z+5NkoQKu4hOhfjz/YYqM3bNilPqv1WVFWrzSmuNXxvhbX69YMmNmRYascPXiwESqf5jJdjKXEww==", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -7677,13 +7709,13 @@ } }, "node_modules/@nestjs/jwt": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/@nestjs/jwt/-/jwt-11.0.1.tgz", - "integrity": "sha512-HXSsc7SAnCnjA98TsZqrE7trGtHDnYXWp4Ffy6LwSmck1QvbGYdMzBquXofX5l6tIRpeY4Qidl2Ti2CVG77Pdw==", + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/@nestjs/jwt/-/jwt-11.0.2.tgz", + "integrity": "sha512-rK8aE/3/Ma45gAWfCksAXUNbOoSOUudU0Kn3rT39htPF7wsYXtKfjALKeKKJbFrIWbLjsbqfXX5bIJNvgBugGA==", "license": "MIT", "dependencies": { "@types/jsonwebtoken": "9.0.10", - "jsonwebtoken": "9.0.2" + "jsonwebtoken": "9.0.3" }, "peerDependencies": { "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0" @@ -7700,13 +7732,13 @@ } }, "node_modules/@nestjs/platform-express": { - "version": "11.1.8", - "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-11.1.8.tgz", - "integrity": "sha512-rL6pZH9BW7BnL5X2eWbJMtt86uloAKjFgyY5+L2UkizgfEp7rgAs0+Z1z0BcW2Pgu5+q8O7RKPNyHJ/9ZNz/ZQ==", + "version": "11.1.14", + "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-11.1.14.tgz", + "integrity": "sha512-Fs+/j+mBSBSXErOQJ/YdUn/HqJGSJ4pGfiJyYOyz04l42uNVnqEakvu1kXLbxMabR6vd6/h9d6Bi4tso9p7o4Q==", "license": "MIT", "dependencies": { - "cors": "2.8.5", - "express": "5.1.0", + "cors": "2.8.6", + "express": "5.2.1", "multer": "2.0.2", "path-to-regexp": "8.3.0", "tslib": "2.8.1" @@ -7721,12 +7753,12 @@ } }, "node_modules/@nestjs/schedule": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@nestjs/schedule/-/schedule-6.0.1.tgz", - "integrity": "sha512-v3yO6cSPAoBSSyH67HWnXHzuhPhSNZhRmLY38JvCt2sqY8sPMOODpcU1D79iUMFf7k16DaMEbL4Mgx61ZhiC8Q==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@nestjs/schedule/-/schedule-6.1.1.tgz", + "integrity": "sha512-kQl1RRgi02GJ0uaUGCrXHCcwISsCsJDciCKe38ykJZgnAeeoeVWs8luWtBo4AqAAXm4nS5K8RlV0smHUJ4+2FA==", "license": "MIT", "dependencies": { - "cron": "4.3.3" + "cron": "4.4.0" }, "peerDependencies": { "@nestjs/common": "^10.0.0 || ^11.0.0", @@ -7910,9 +7942,9 @@ } }, "node_modules/@nestjs/testing": { - "version": "11.1.8", - "resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-11.1.8.tgz", - "integrity": "sha512-E6K+0UTKztcPxJzLnQa7S34lFjZbrj3Z1r7c5y5WDrL1m5HD1H4AeyBhicHgdaFmxjLAva2bq0sYKy/S7cdeYA==", + "version": "11.1.14", + "resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-11.1.14.tgz", + "integrity": "sha512-cQxX0ronsTbpfHz8/LYOVWXxoTxv6VoxrnuZoQaVX7QV2PSMqxWE7/9jSQR0GcqAFUEmFP34c6EJqfkjfX/k4Q==", "dev": true, "license": "MIT", "dependencies": { @@ -8305,20 +8337,20 @@ } }, "node_modules/@nx/angular": { - "version": "22.4.5", - "resolved": "https://registry.npmjs.org/@nx/angular/-/angular-22.4.5.tgz", - "integrity": "sha512-mwffAG7qhElwtWCEIaH7bTJuE3foaFBa3LWReqNc9HkIZmka0BDHRReg3wyhfSGq4ZQlYXK5sQS2uDJd+Qj97Q==", + "version": "22.5.3", + "resolved": "https://registry.npmjs.org/@nx/angular/-/angular-22.5.3.tgz", + "integrity": "sha512-Z5vNcPl95CsTnRhDszWZ0ort22dEtMxdqJFkVzdNwolhfiLm1eKP2Rc8q9MnUdrZMeTqDKnCckG2qs12FZrIkw==", "dev": true, "license": "MIT", "dependencies": { - "@nx/devkit": "22.4.5", - "@nx/eslint": "22.4.5", - "@nx/js": "22.4.5", - "@nx/module-federation": "22.4.5", - "@nx/rspack": "22.4.5", - "@nx/web": "22.4.5", - "@nx/webpack": "22.4.5", - "@nx/workspace": "22.4.5", + "@nx/devkit": "22.5.3", + "@nx/eslint": "22.5.3", + "@nx/js": "22.5.3", + "@nx/module-federation": "22.5.3", + "@nx/rspack": "22.5.3", + "@nx/web": "22.5.3", + "@nx/webpack": "22.5.3", + "@nx/workspace": "22.5.3", "@phenomnomnominal/tsquery": "~6.1.4", "@typescript-eslint/type-utils": "^8.0.0", "enquirer": "~2.3.6", @@ -8366,15 +8398,15 @@ } }, "node_modules/@nx/cypress": { - "version": "22.4.5", - "resolved": "https://registry.npmjs.org/@nx/cypress/-/cypress-22.4.5.tgz", - "integrity": "sha512-FAGLQa7dnMW5Z93bS5isw9WgVNapCOgRFgxl9sA1ePstte3Vh0ajRpvVjVoeVHyA3qg6aQbE41ctErOdq/p5bg==", + "version": "22.5.3", + "resolved": "https://registry.npmjs.org/@nx/cypress/-/cypress-22.5.3.tgz", + "integrity": "sha512-0jIYOhU1sFv5w2NYmyxIdpT4pC7QvUphrM4QLyUk8nEfO5gwfmON7JLNbtDveX+FeGpjy1zDjoBdd2OBzqUEcA==", "dev": true, "license": "MIT", "dependencies": { - "@nx/devkit": "22.4.5", - "@nx/eslint": "22.4.5", - "@nx/js": "22.4.5", + "@nx/devkit": "22.5.3", + "@nx/eslint": "22.5.3", + "@nx/js": "22.5.3", "@phenomnomnominal/tsquery": "~6.1.4", "detect-port": "^1.5.1", "semver": "^7.6.3", @@ -8391,16 +8423,16 @@ } }, "node_modules/@nx/devkit": { - "version": "22.4.5", - "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-22.4.5.tgz", - "integrity": "sha512-mw5G6k/XTkL675eVIcFpyZdfdIc3wQMSSGWzfA6tQGmANDYc/NFGeZR9wDqXDceHXnYKoRO6g6GhKTOHUCW23Q==", + "version": "22.5.3", + "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-22.5.3.tgz", + "integrity": "sha512-zhRNTFsi4pbwg7L/zhBHtTOSevlgwm1iKlhPlQWoOv2PR6b+3JvjL8o4P1MbkIkut3Lsn+oTuJJ1LUPlr5vprg==", "dev": true, "license": "MIT", "dependencies": { "@zkochan/js-yaml": "0.0.7", "ejs": "^3.1.7", "enquirer": "~2.3.6", - "minimatch": "10.1.1", + "minimatch": "10.2.1", "semver": "^7.6.3", "tslib": "^2.3.0", "yargs-parser": "21.1.1" @@ -8409,14 +8441,37 @@ "nx": ">= 21 <= 23 || ^22.0.0-0" } }, + "node_modules/@nx/devkit/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@nx/devkit/node_modules/brace-expansion": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, "node_modules/@nx/devkit/node_modules/minimatch": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", - "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.1.tgz", + "integrity": "sha512-MClCe8IL5nRRmawL6ib/eT4oLyeKMGCghibcDWK+J0hh0Q8kqSdia6BvbRMVk6mPa6WqUa5uR2oxt6C5jd533A==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { - "@isaacs/brace-expansion": "^5.0.0" + "brace-expansion": "^5.0.2" }, "engines": { "node": "20 || >=22" @@ -8426,33 +8481,33 @@ } }, "node_modules/@nx/docker": { - "version": "22.4.5", - "resolved": "https://registry.npmjs.org/@nx/docker/-/docker-22.4.5.tgz", - "integrity": "sha512-ZgBjd/HCgqkulYJwUH+xQvgsoupVD+2leiFmK5lFjb6IDny/W1uB3EVL5BZxrz8ftMoqiq+AP6Ubiaj99V4hzQ==", + "version": "22.5.3", + "resolved": "https://registry.npmjs.org/@nx/docker/-/docker-22.5.3.tgz", + "integrity": "sha512-4BO1hAyun2MM15w1oldUZtCvZEZlDXOCeEkimVij9znk6t4FUBnH7v87Uj4w5dhJAWB7yJFgQbF5w1fZbhRXfw==", "dev": true, "license": "MIT", "dependencies": { - "@nx/devkit": "22.4.5", + "@nx/devkit": "22.5.3", "enquirer": "~2.3.6", "tslib": "^2.3.0" } }, "node_modules/@nx/eslint": { - "version": "22.4.5", - "resolved": "https://registry.npmjs.org/@nx/eslint/-/eslint-22.4.5.tgz", - "integrity": "sha512-/N/kG86gqagDziC7Ij/WwAnjjXx55E1Jbpp3kkau3Ncj+wjPoLqCebpg6aW83VJQ7a4SUU0BO3U5bkqQZPGBXQ==", + "version": "22.5.3", + "resolved": "https://registry.npmjs.org/@nx/eslint/-/eslint-22.5.3.tgz", + "integrity": "sha512-XJKpwnSJRCat+81sUDdJWWvKz3vKo/3X9oHMGDzTYx3mexCgKgpmHBuRVgnZ9n2IVDx8S5ye4ICc9qiY6oHWIA==", "dev": true, "license": "MIT", "dependencies": { - "@nx/devkit": "22.4.5", - "@nx/js": "22.4.5", + "@nx/devkit": "22.5.3", + "@nx/js": "22.5.3", "semver": "^7.6.3", "tslib": "^2.3.0", "typescript": "~5.9.2" }, "peerDependencies": { "@zkochan/js-yaml": "0.0.7", - "eslint": "^8.0.0 || ^9.0.0" + "eslint": "^8.0.0 || ^9.0.0 || ^10.0.0" }, "peerDependenciesMeta": { "@zkochan/js-yaml": { @@ -8461,14 +8516,14 @@ } }, "node_modules/@nx/eslint-plugin": { - "version": "22.4.5", - "resolved": "https://registry.npmjs.org/@nx/eslint-plugin/-/eslint-plugin-22.4.5.tgz", - "integrity": "sha512-Kb3owVrbhRkJAjqEDsgDs8eSlI2/uEFOS35a8Z1drHIpMF6Zt9OHQf6bKELeXzG3fC2AGM3pyunauhbJ/ZmqMw==", + "version": "22.5.3", + "resolved": "https://registry.npmjs.org/@nx/eslint-plugin/-/eslint-plugin-22.5.3.tgz", + "integrity": "sha512-dFz3nSUOV+VLc+ZQxWncKINhych6h5oEfInWp1+5WkeUBW5/x77IsM3Hpq1JrjAK6dqXjmzTsFnoU8c5Cf1Q4w==", "dev": true, "license": "MIT", "dependencies": { - "@nx/devkit": "22.4.5", - "@nx/js": "22.4.5", + "@nx/devkit": "22.5.3", + "@nx/js": "22.5.3", "@phenomnomnominal/tsquery": "~6.1.4", "@typescript-eslint/type-utils": "^8.0.0", "@typescript-eslint/utils": "^8.0.0", @@ -8520,22 +8575,22 @@ } }, "node_modules/@nx/jest": { - "version": "22.4.5", - "resolved": "https://registry.npmjs.org/@nx/jest/-/jest-22.4.5.tgz", - "integrity": "sha512-qlEJc0Jbp8E14g7+piHH8DXsAm6C3w1CLuvtE57+LFMhM2zbBDiQ8oeXBdFPEHLCfpbSK/4yCSEmkUj1Yyrs2A==", + "version": "22.5.3", + "resolved": "https://registry.npmjs.org/@nx/jest/-/jest-22.5.3.tgz", + "integrity": "sha512-4yaGlApTR09zdz4fC4Ep0aENcaon5rDRDOUnEJblU67ik35jds9mczHq2rBMJO4Cnjj1pM9acm08Vb0Wg+9cuQ==", "dev": true, "license": "MIT", "dependencies": { "@jest/reporters": "^30.0.2", "@jest/test-result": "^30.0.2", - "@nx/devkit": "22.4.5", - "@nx/js": "22.4.5", + "@nx/devkit": "22.5.3", + "@nx/js": "22.5.3", "@phenomnomnominal/tsquery": "~6.1.4", "identity-obj-proxy": "3.0.0", "jest-config": "^30.0.2", "jest-resolve": "^30.0.2", "jest-util": "^30.0.2", - "minimatch": "10.1.1", + "minimatch": "10.2.1", "picocolors": "^1.1.0", "resolve.exports": "2.0.3", "semver": "^7.6.3", @@ -8543,14 +8598,37 @@ "yargs-parser": "21.1.1" } }, + "node_modules/@nx/jest/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@nx/jest/node_modules/brace-expansion": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, "node_modules/@nx/jest/node_modules/minimatch": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", - "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.1.tgz", + "integrity": "sha512-MClCe8IL5nRRmawL6ib/eT4oLyeKMGCghibcDWK+J0hh0Q8kqSdia6BvbRMVk6mPa6WqUa5uR2oxt6C5jd533A==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { - "@isaacs/brace-expansion": "^5.0.0" + "brace-expansion": "^5.0.2" }, "engines": { "node": "20 || >=22" @@ -8560,9 +8638,9 @@ } }, "node_modules/@nx/js": { - "version": "22.4.5", - "resolved": "https://registry.npmjs.org/@nx/js/-/js-22.4.5.tgz", - "integrity": "sha512-t8972z2uF6X5i4FFmTlnvSwwxfHkk87zBpKQK0yMH5CzOENViVFNbiPnbvCIJcGNrgVUSALL3f2ngwKcTZObmA==", + "version": "22.5.3", + "resolved": "https://registry.npmjs.org/@nx/js/-/js-22.5.3.tgz", + "integrity": "sha512-gglQYL6GeSH0mt6NpEFTXMFFFePU3B7TEyZq7LLUYZDH5y65izgNpdSAuEqYR7xHLtahVnesDlhPw3rtRiwMwA==", "dev": true, "license": "MIT", "dependencies": { @@ -8573,8 +8651,8 @@ "@babel/preset-env": "^7.23.2", "@babel/preset-typescript": "^7.22.5", "@babel/runtime": "^7.22.6", - "@nx/devkit": "22.4.5", - "@nx/workspace": "22.4.5", + "@nx/devkit": "22.5.3", + "@nx/workspace": "22.5.3", "@zkochan/js-yaml": "0.0.7", "babel-plugin-const-enum": "^1.0.1", "babel-plugin-macros": "^3.1.0", @@ -8648,18 +8726,18 @@ } }, "node_modules/@nx/module-federation": { - "version": "22.4.5", - "resolved": "https://registry.npmjs.org/@nx/module-federation/-/module-federation-22.4.5.tgz", - "integrity": "sha512-aNO595Xk0B4av9tpAaePF0jjDooAiXN34xEpFleSCmf8y31371JfkI8WMSnIZLa5ehyk1U+oMxHyYtt7v0RFWw==", + "version": "22.5.3", + "resolved": "https://registry.npmjs.org/@nx/module-federation/-/module-federation-22.5.3.tgz", + "integrity": "sha512-dKRkT/ULV+nXr7O25YMDwQu/4nxl27AcHJfOmVBVKquXrtrBu/d6dbypfFDMyr5pXqR5gb2euEw0mGVMyHLTiA==", "dev": true, "license": "MIT", "dependencies": { "@module-federation/enhanced": "^0.21.2", "@module-federation/node": "^2.7.21", "@module-federation/sdk": "^0.21.2", - "@nx/devkit": "22.4.5", - "@nx/js": "22.4.5", - "@nx/web": "22.4.5", + "@nx/devkit": "22.5.3", + "@nx/js": "22.5.3", + "@nx/web": "22.5.3", "@rspack/core": "1.6.8", "express": "^4.21.2", "http-proxy-middleware": "^3.0.5", @@ -8970,41 +9048,41 @@ } }, "node_modules/@nx/nest": { - "version": "22.4.5", - "resolved": "https://registry.npmjs.org/@nx/nest/-/nest-22.4.5.tgz", - "integrity": "sha512-cFufm3cPuy7Cj10D8BB2Y+Vo1w/1ihQGeduXprC0gs719dI5zvyG8bVOYJ+m87HHdFVQ8ckIVVifO6T7ujWgFw==", + "version": "22.5.3", + "resolved": "https://registry.npmjs.org/@nx/nest/-/nest-22.5.3.tgz", + "integrity": "sha512-DShcD4HdaABg9L7/qgLVgZj0LLSaaYa7Rrj8zquMGGZXrxozCTKzn/7vWrN7Am9hY4wEwaXTXwauHAFoIj9C9A==", "dev": true, "license": "MIT", "dependencies": { "@nestjs/schematics": "^11.0.0", - "@nx/devkit": "22.4.5", - "@nx/eslint": "22.4.5", - "@nx/js": "22.4.5", - "@nx/node": "22.4.5", + "@nx/devkit": "22.5.3", + "@nx/eslint": "22.5.3", + "@nx/js": "22.5.3", + "@nx/node": "22.5.3", "tslib": "^2.3.0" } }, "node_modules/@nx/node": { - "version": "22.4.5", - "resolved": "https://registry.npmjs.org/@nx/node/-/node-22.4.5.tgz", - "integrity": "sha512-ZYN3uIeUs0jKPX9Io75DkISMo5ha15djVLPNFhsh6qgQkL7+mqXGeW3QiEso16XZqbl0Iw2Ye5msrBO6UShFkQ==", + "version": "22.5.3", + "resolved": "https://registry.npmjs.org/@nx/node/-/node-22.5.3.tgz", + "integrity": "sha512-szdpsyRUzXBhMIiEk+zI3XPP/e0U1wNmIzkvgCS1e+ejsA1jq0EF5sppkdwJEQVAb6O5hiCPKED+1sSo4TR4/A==", "dev": true, "license": "MIT", "dependencies": { - "@nx/devkit": "22.4.5", - "@nx/docker": "22.4.5", - "@nx/eslint": "22.4.5", - "@nx/jest": "22.4.5", - "@nx/js": "22.4.5", + "@nx/devkit": "22.5.3", + "@nx/docker": "22.5.3", + "@nx/eslint": "22.5.3", + "@nx/jest": "22.5.3", + "@nx/js": "22.5.3", "kill-port": "^1.6.1", "tcp-port-used": "^1.0.2", "tslib": "^2.3.0" } }, "node_modules/@nx/nx-darwin-arm64": { - "version": "22.4.5", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-22.4.5.tgz", - "integrity": "sha512-zdRHZv1AMvzgp+5g2VZNXXuqk0/n1wOFksOeZ6BRyKg6hC2YkjGyn5xle/UK668MDAwe9KKm4jizvztK/LlPuA==", + "version": "22.5.3", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-22.5.3.tgz", + "integrity": "sha512-cKXBq5bJanXp8uv6+wPvx/G4q4oFpOxMSPGaeFOVhbul2QHGGq+XMcSo+D8aYJCsk1YnbyAnnQ8r8RH/kTK5Mw==", "cpu": [ "arm64" ], @@ -9016,9 +9094,9 @@ ] }, "node_modules/@nx/nx-darwin-x64": { - "version": "22.4.5", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-22.4.5.tgz", - "integrity": "sha512-1NVWaSgpa8yawi2UILX4NE9UcMuNzAAGh95JSV2yJovRfKxFQgQSB6hj0gpJu+TLLVCroTqy4woSQ2a0SPodeQ==", + "version": "22.5.3", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-22.5.3.tgz", + "integrity": "sha512-mToS41o8I+8CfxYVRMTISkgT7I1cnazgwMf7U9DoLqKOwOZzj9WD3NmsWc1h69QNJPltbeRPS8y/wnhu7RHzRA==", "cpu": [ "x64" ], @@ -9030,9 +9108,9 @@ ] }, "node_modules/@nx/nx-freebsd-x64": { - "version": "22.4.5", - "resolved": "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-22.4.5.tgz", - "integrity": "sha512-baaLz53wr/HsVfSJ7ZgIFCPAb/OtP7yPPasb3eIu65oVhSswGfgvz9+YINhuInUgW7x7STmRnhGeR8pj6iqFqw==", + "version": "22.5.3", + "resolved": "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-22.5.3.tgz", + "integrity": "sha512-CAWysdFSZVbTfdjNXojd9TgXbZiK9i0k3njROeV+jORsDWw4Eth3PDmK94Wk916b3n2hS0UjyI6RZaMy2GEqzA==", "cpu": [ "x64" ], @@ -9044,9 +9122,9 @@ ] }, "node_modules/@nx/nx-linux-arm-gnueabihf": { - "version": "22.4.5", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-22.4.5.tgz", - "integrity": "sha512-wRBPv/l39tz+sQjZUH4hygCsd/DoUXUbDYkR6lnNXWHAVyPUh48/27JozM8hD3o/G3O2Vd8PFQasIXtvy2GS0Q==", + "version": "22.5.3", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-22.5.3.tgz", + "integrity": "sha512-PRjPrijQQbdrvYwNuA3xQ3VXEQ4zfhnPjy+S2ZlQZqhFI4mlP22xfhOH1bQ7pIfzCNC2f/J9UMNYOrq/bEFjBg==", "cpu": [ "arm" ], @@ -9058,9 +9136,9 @@ ] }, "node_modules/@nx/nx-linux-arm64-gnu": { - "version": "22.4.5", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-22.4.5.tgz", - "integrity": "sha512-6B/yCFiqjvV2Bkz6MKUtfFWjwtiF53DN07K1BFksMpQef+h2yE1IrGaG/OCl6VaVl4VRzQgLOluqP96M1yhDgg==", + "version": "22.5.3", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-22.5.3.tgz", + "integrity": "sha512-dmDBio/5z4Zch2VlRMdgBPm53d8xwq1l7xLj1dFMKjfE7ByfPukjPM7ZEYBiPckfiQfJBRh6HKDN7uEkA/y8CQ==", "cpu": [ "arm64" ], @@ -9072,9 +9150,9 @@ ] }, "node_modules/@nx/nx-linux-arm64-musl": { - "version": "22.4.5", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-22.4.5.tgz", - "integrity": "sha512-n0v60vRYn7BDHWB588snPZntLO2XC8/pvLd+QunneM2VGEPf51n5llX5U3AwTt/ybaZHWhbuHv0sJBIbT4I0GA==", + "version": "22.5.3", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-22.5.3.tgz", + "integrity": "sha512-E81ET/MnnKfuLhKiovF5ueJirHOMjhC1eK0MDM2Do9wdPyusZzfGSVFQ9DOHtg7L37dAE95NNd1lCVO8gJ96vg==", "cpu": [ "arm64" ], @@ -9086,9 +9164,9 @@ ] }, "node_modules/@nx/nx-linux-x64-gnu": { - "version": "22.4.5", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-22.4.5.tgz", - "integrity": "sha512-zT7nb1PRE3NcW/HFnbgKJ9ZPtCOeVDpbJ5J4ZhHj36ZAUWZVXFEIPq9VTIZFy5+0pioLUIClQQY7OUfwnV/Zig==", + "version": "22.5.3", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-22.5.3.tgz", + "integrity": "sha512-AgXCsPCzC0sAu2VRclMjs7LrvPQfqS3sFiehlXWTbNHQitPZLuAmQGb2l4T8lbMOs0Xn3EIrg6BF6/ntTTp6Xg==", "cpu": [ "x64" ], @@ -9100,9 +9178,9 @@ ] }, "node_modules/@nx/nx-linux-x64-musl": { - "version": "22.4.5", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-22.4.5.tgz", - "integrity": "sha512-r8Rls5BS7lGQbUNX1Z1S370XrOacOU1bQ/dxY8i7qahFQKnMwpFo0W8odhgzjk+vrC/WLf9jOgz5/JPzehQBIw==", + "version": "22.5.3", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-22.5.3.tgz", + "integrity": "sha512-sKs4bFQRu8Btxf5rMYKPsRVNxkQ2ey8sqoCyhJj8fwJF05DayK2ErJAR/rhtBK0c1NV7kQiKJA8nWBV3jnCdsg==", "cpu": [ "x64" ], @@ -9114,9 +9192,9 @@ ] }, "node_modules/@nx/nx-win32-arm64-msvc": { - "version": "22.4.5", - "resolved": "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-22.4.5.tgz", - "integrity": "sha512-Lv81LTnG6sSvBOq2vDSeyfzpF9X0cTGlJdzJOJzPZXCZGFhTV1ig9TdLiij/GM2JwV4Kvq5Co6YzA5dxtGUphQ==", + "version": "22.5.3", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-22.5.3.tgz", + "integrity": "sha512-KOCQLakSO5vl4D6et9qPytOAmkgq2IIuhI8A/g0xbD1LqrIlRPa+bdkZqOGpODYAk3NyKAk7hWHsqfXKHwwX6w==", "cpu": [ "arm64" ], @@ -9128,9 +9206,9 @@ ] }, "node_modules/@nx/nx-win32-x64-msvc": { - "version": "22.4.5", - "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-22.4.5.tgz", - "integrity": "sha512-52RfBcq9PXt76soCAZAJcNmCYrdsg6BvhBmjf0IFTMZ8IaeqZ9ktxAy1TZf/gCkOaM3ly4htbYMStiZ4MHX7Eg==", + "version": "22.5.3", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-22.5.3.tgz", + "integrity": "sha512-a6ZB2La82RIHcz4nrt3H6RZaOa+xkC2IPzhU9hMo2gbkLdIxn8wyof8uGA0frncmIVHuLc3nFAhpBOgf4j6tMA==", "cpu": [ "x64" ], @@ -9142,16 +9220,16 @@ ] }, "node_modules/@nx/rspack": { - "version": "22.4.5", - "resolved": "https://registry.npmjs.org/@nx/rspack/-/rspack-22.4.5.tgz", - "integrity": "sha512-pqaJ713Jv82abDGisArEtKprAO0DuGxp7zddwpYW04J4Y8YmRAQFA3KriMPqjWTXuV3l4kpaqU7FtZ/3Xn1ShA==", + "version": "22.5.3", + "resolved": "https://registry.npmjs.org/@nx/rspack/-/rspack-22.5.3.tgz", + "integrity": "sha512-2T5dkoC08FJGF8ZMiJDaKN6giXAljV0+LK7q5GJpSEUm+wtjZ/DRVoWSnlf8Dj/e0/cLb2GMElVcfjyDDDeV9w==", "dev": true, "license": "MIT", "dependencies": { - "@nx/devkit": "22.4.5", - "@nx/js": "22.4.5", - "@nx/module-federation": "22.4.5", - "@nx/web": "22.4.5", + "@nx/devkit": "22.5.3", + "@nx/js": "22.5.3", + "@nx/module-federation": "22.5.3", + "@nx/web": "22.5.3", "@phenomnomnominal/tsquery": "~6.1.4", "@rspack/core": "1.6.8", "@rspack/dev-server": "^1.1.4", @@ -9573,16 +9651,16 @@ } }, "node_modules/@nx/storybook": { - "version": "22.4.5", - "resolved": "https://registry.npmjs.org/@nx/storybook/-/storybook-22.4.5.tgz", - "integrity": "sha512-cxJDYpfpYcK0iuiJMHk6InLXXNLedj8VlOkRtcnZKuwDlC8quMSOuHKrdvBOjeOLV4C390/94BlzkToUZSey6g==", + "version": "22.5.3", + "resolved": "https://registry.npmjs.org/@nx/storybook/-/storybook-22.5.3.tgz", + "integrity": "sha512-eP7cpRKnC1oYlOjSZU07Kf8BV8hNRPPXRib7BVdwwIUZ2v4K/b/cje2WCG729q4gk8fyoV8o7JNVgM+QGT8kBQ==", "dev": true, "license": "MIT", "dependencies": { - "@nx/cypress": "22.4.5", - "@nx/devkit": "22.4.5", - "@nx/eslint": "22.4.5", - "@nx/js": "22.4.5", + "@nx/cypress": "22.5.3", + "@nx/devkit": "22.5.3", + "@nx/eslint": "22.5.3", + "@nx/js": "22.5.3", "@phenomnomnominal/tsquery": "~6.1.4", "semver": "^7.6.3", "tslib": "^2.3.0" @@ -9592,14 +9670,14 @@ } }, "node_modules/@nx/web": { - "version": "22.4.5", - "resolved": "https://registry.npmjs.org/@nx/web/-/web-22.4.5.tgz", - "integrity": "sha512-VXXkONZS7DEDDKUE8EUCiV7XhC+HmotExPKznU6NquoFpBZqvWCfC0rt/gKk2uIxJGu8qoISqtIIHFc6iO65RA==", + "version": "22.5.3", + "resolved": "https://registry.npmjs.org/@nx/web/-/web-22.5.3.tgz", + "integrity": "sha512-Z7FYN5e9HIJAuJV0MU8jHaoEv9vgiLbpe1bbWPItfzIy02kWtSiS/aGZcLa34LDuWBfBaJVHZqFVp7OOPU26ew==", "dev": true, "license": "MIT", "dependencies": { - "@nx/devkit": "22.4.5", - "@nx/js": "22.4.5", + "@nx/devkit": "22.5.3", + "@nx/js": "22.5.3", "detect-port": "^1.5.1", "http-server": "^14.1.0", "picocolors": "^1.1.0", @@ -9607,15 +9685,15 @@ } }, "node_modules/@nx/webpack": { - "version": "22.4.5", - "resolved": "https://registry.npmjs.org/@nx/webpack/-/webpack-22.4.5.tgz", - "integrity": "sha512-3NZnJwkP1ztPc4Inz0g04rWf78P3U2np/kg3nKNf2I6kowWpcJakQCsWLufBzP48ooUtE3iPDVQoFIo3SgWqDg==", + "version": "22.5.3", + "resolved": "https://registry.npmjs.org/@nx/webpack/-/webpack-22.5.3.tgz", + "integrity": "sha512-fEWvmynjxAfdyCH00Z3oaEedv/wKZAdHl8kz7UEiOJ7eKdGbbJIK0RuobXC1r2e2ERZ35vDrOiPYdruyfi35Jg==", "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.23.2", - "@nx/devkit": "22.4.5", - "@nx/js": "22.4.5", + "@nx/devkit": "22.5.3", + "@nx/js": "22.5.3", "@phenomnomnominal/tsquery": "~6.1.4", "ajv": "^8.12.0", "autoprefixer": "^10.4.9", @@ -9824,17 +9902,17 @@ } }, "node_modules/@nx/workspace": { - "version": "22.4.5", - "resolved": "https://registry.npmjs.org/@nx/workspace/-/workspace-22.4.5.tgz", - "integrity": "sha512-QGapABrqBnRpEWbnd5UpbVCBzsYD+RlC1lWShXPpCM+dosR3qkGb+pSmxeSCsKbNVtCwYyyuRW+PvlF5Q5sU9A==", + "version": "22.5.3", + "resolved": "https://registry.npmjs.org/@nx/workspace/-/workspace-22.5.3.tgz", + "integrity": "sha512-pioGwlt5zKB9PhX36I5KAeSml19Mq+g2KyQ9mh3F+3Lvft2JM4nIMELBaUfwPicPAOwNmrsx806IXO67Q4UHxQ==", "dev": true, "license": "MIT", "dependencies": { - "@nx/devkit": "22.4.5", + "@nx/devkit": "22.5.3", "@zkochan/js-yaml": "0.0.7", "chalk": "^4.1.0", "enquirer": "~2.3.6", - "nx": "22.4.5", + "nx": "22.5.3", "picomatch": "4.0.2", "semver": "^7.6.3", "tslib": "^2.3.0", @@ -10220,34 +10298,101 @@ "tslib": "^2.8.1" } }, + "node_modules/@peculiar/asn1-cms": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-cms/-/asn1-cms-2.6.1.tgz", + "integrity": "sha512-vdG4fBF6Lkirkcl53q6eOdn3XYKt+kJTG59edgRZORlg/3atWWEReRCx5rYE1ZzTTX6vLK5zDMjHh7vbrcXGtw==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", + "@peculiar/asn1-x509-attr": "^2.6.1", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-csr": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-csr/-/asn1-csr-2.6.1.tgz", + "integrity": "sha512-WRWnKfIocHyzFYQTka8O/tXCiBquAPSrRjXbOkHbO4qdmS6loffCEGs+rby6WxxGdJCuunnhS2duHURhjyio6w==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, "node_modules/@peculiar/asn1-ecc": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.4.0.tgz", - "integrity": "sha512-fJiYUBCJBDkjh347zZe5H81BdJ0+OGIg0X9z06v8xXUoql3MFeENUX0JsjCaVaU9A0L85PefLPGYkIoGpTnXLQ==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.6.1.tgz", + "integrity": "sha512-+Vqw8WFxrtDIN5ehUdvlN2m73exS2JVG0UAyfVB31gIfor3zWEAQPD+K9ydCxaj3MLen9k0JhKpu9LqviuCE1g==", "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.4.0", - "@peculiar/asn1-x509": "^2.4.0", + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-pfx": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pfx/-/asn1-pfx-2.6.1.tgz", + "integrity": "sha512-nB5jVQy3MAAWvq0KY0R2JUZG8bO/bTLpnwyOzXyEh/e54ynGTatAR+csOnXkkVD9AFZ2uL8Z7EV918+qB1qDvw==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-cms": "^2.6.1", + "@peculiar/asn1-pkcs8": "^2.6.1", + "@peculiar/asn1-rsa": "^2.6.1", + "@peculiar/asn1-schema": "^2.6.0", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-pkcs8": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs8/-/asn1-pkcs8-2.6.1.tgz", + "integrity": "sha512-JB5iQ9Izn5yGMw3ZG4Nw3Xn/hb/G38GYF3lf7WmJb8JZUydhVGEjK/ZlFSWhnlB7K/4oqEs8HnfFIKklhR58Tw==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-pkcs9": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs9/-/asn1-pkcs9-2.6.1.tgz", + "integrity": "sha512-5EV8nZoMSxeWmcxWmmcolg22ojZRgJg+Y9MX2fnE2bGRo5KQLqV5IL9kdSQDZxlHz95tHvIq9F//bvL1OeNILw==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-cms": "^2.6.1", + "@peculiar/asn1-pfx": "^2.6.1", + "@peculiar/asn1-pkcs8": "^2.6.1", + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", + "@peculiar/asn1-x509-attr": "^2.6.1", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "node_modules/@peculiar/asn1-rsa": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.4.0.tgz", - "integrity": "sha512-6PP75voaEnOSlWR9sD25iCQyLgFZHXbmxvUfnnDcfL6Zh5h2iHW38+bve4LfH7a60x7fkhZZNmiYqAlAff9Img==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.6.1.tgz", + "integrity": "sha512-1nVMEh46SElUt5CB3RUTV4EG/z7iYc7EoaDY5ECwganibQPkZ/Y2eMsTKB/LeyrUJ+W/tKoD9WUqIy8vB+CEdA==", "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.4.0", - "@peculiar/asn1-x509": "^2.4.0", + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "node_modules/@peculiar/asn1-schema": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.4.0.tgz", - "integrity": "sha512-umbembjIWOrPSOzEGG5vxFLkeM8kzIhLkgigtsOrfLKnuzxWxejAcUX+q/SoZCdemlODOcr5WiYa7+dIEzBXZQ==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.6.0.tgz", + "integrity": "sha512-xNLYLBFTBKkCzEZIw842BxytQQATQv+lDTCEMZ8C196iJcJJMBUZxrhSTxLaohMyKK8QlzRNTRkUmanucnDSqg==", "license": "MIT", "dependencies": { "asn1js": "^3.0.6", @@ -10256,17 +10401,51 @@ } }, "node_modules/@peculiar/asn1-x509": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.4.0.tgz", - "integrity": "sha512-F7mIZY2Eao2TaoVqigGMLv+NDdpwuBKU1fucHPONfzaBS4JXXCNCmfO0Z3dsy7JzKGqtDcYC1mr9JjaZQZNiuw==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.6.1.tgz", + "integrity": "sha512-O9jT5F1A2+t3r7C4VT7LYGXqkGLK7Kj1xFpz7U0isPrubwU5PbDoyYtx6MiGst29yq7pXN5vZbQFKRCP+lLZlA==", "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.4.0", + "@peculiar/asn1-schema": "^2.6.0", "asn1js": "^3.0.6", "pvtsutils": "^1.3.6", "tslib": "^2.8.1" } }, + "node_modules/@peculiar/asn1-x509-attr": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509-attr/-/asn1-x509-attr-2.6.1.tgz", + "integrity": "sha512-tlW6cxoHwgcQghnJwv3YS+9OO1737zgPogZ+CgWRUK4roEwIPzRH4JEiG770xe5HX2ATfCpmX60gurfWIF9dcQ==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/x509": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/@peculiar/x509/-/x509-1.14.3.tgz", + "integrity": "sha512-C2Xj8FZ0uHWeCXXqX5B4/gVFQmtSkiuOolzAgutjTfseNOHT3pUjljDZsTSxXFGgio54bCzVFqmEOUrIVk8RDA==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-cms": "^2.6.0", + "@peculiar/asn1-csr": "^2.6.0", + "@peculiar/asn1-ecc": "^2.6.0", + "@peculiar/asn1-pkcs9": "^2.6.0", + "@peculiar/asn1-rsa": "^2.6.0", + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.0", + "pvtsutils": "^1.3.6", + "reflect-metadata": "^0.2.2", + "tslib": "^2.8.1", + "tsyringe": "^4.10.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, "node_modules/@phenomnomnominal/tsquery": { "version": "6.1.4", "resolved": "https://registry.npmjs.org/@phenomnomnominal/tsquery/-/tsquery-6.1.4.tgz", @@ -11573,9 +11752,9 @@ "license": "MIT" }, "node_modules/@rspack/plugin-react-refresh": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@rspack/plugin-react-refresh/-/plugin-react-refresh-1.6.0.tgz", - "integrity": "sha512-OO53gkrte/Ty4iRXxxM6lkwPGxsSsupFKdrPFnjwFIYrPvFLjeolAl5cTx+FzO5hYygJiGnw7iEKTmD+ptxqDA==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@rspack/plugin-react-refresh/-/plugin-react-refresh-1.6.1.tgz", + "integrity": "sha512-eqqW5645VG3CzGzFgNg5HqNdHVXY+567PGjtDhhrM8t67caxmsSzRmT5qfoEIfBcGgFkH9vEg7kzXwmCYQdQDw==", "dev": true, "license": "MIT", "dependencies": { @@ -11696,15 +11875,15 @@ } }, "node_modules/@simplewebauthn/browser": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@simplewebauthn/browser/-/browser-13.1.0.tgz", - "integrity": "sha512-WuHZ/PYvyPJ9nxSzgHtOEjogBhwJfC8xzYkPC+rR/+8chl/ft4ngjiK8kSU5HtRJfczupyOh33b25TjYbvwAcg==", + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/@simplewebauthn/browser/-/browser-13.2.2.tgz", + "integrity": "sha512-FNW1oLQpTJyqG5kkDg5ZsotvWgmBaC6jCHR7Ej0qUNep36Wl9tj2eZu7J5rP+uhXgHaLk+QQ3lqcw2vS5MX1IA==", "license": "MIT" }, "node_modules/@simplewebauthn/server": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/@simplewebauthn/server/-/server-13.1.1.tgz", - "integrity": "sha512-1hsLpRHfSuMB9ee2aAdh0Htza/X3f4djhYISrggqGe3xopNjOcePiSDkDDoPzDYaaMCrbqGP1H2TYU7bgL9PmA==", + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/@simplewebauthn/server/-/server-13.2.2.tgz", + "integrity": "sha512-HcWLW28yTMGXpwE9VLx9J+N2KEUaELadLrkPEEI9tpI5la70xNEVEsu/C+m3u7uoq4FulLqZQhgBCzR9IZhFpA==", "license": "MIT", "dependencies": { "@hexagon/base64": "^1.1.27", @@ -11713,7 +11892,8 @@ "@peculiar/asn1-ecc": "^2.3.8", "@peculiar/asn1-rsa": "^2.3.8", "@peculiar/asn1-schema": "^2.3.8", - "@peculiar/asn1-x509": "^2.3.8" + "@peculiar/asn1-x509": "^2.3.8", + "@peculiar/x509": "^1.13.0" }, "engines": { "node": ">=20.0.0" @@ -11753,9 +11933,9 @@ "license": "MIT" }, "node_modules/@stencil/core": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.38.0.tgz", - "integrity": "sha512-oC3QFKO0X1yXVvETgc8OLY525MNKhn9vISBrbtKnGoPlokJ6rI8Vk1RK22TevnNrHLI4SExNLbcDnqilKR35JQ==", + "version": "4.43.0", + "resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.43.0.tgz", + "integrity": "sha512-6Uj2Z3lzLuufYAE7asZ6NLKgSwsB9uxl84Eh34PASnUjfj32GkrP4DtKK7fNeh1WFGGyffsTDka3gwtl+4reUg==", "license": "MIT", "bin": { "stencil": "bin/stencil" @@ -12306,14 +12486,13 @@ } }, "node_modules/@tokenizer/inflate": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/@tokenizer/inflate/-/inflate-0.2.7.tgz", - "integrity": "sha512-MADQgmZT1eKjp06jpI2yozxaU9uVs4GzzgSL+uEq7bVcJ9V1ZXQkeGNql1fsSI0gMy1vhvNTNbUqrx+pZfJVmg==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@tokenizer/inflate/-/inflate-0.4.1.tgz", + "integrity": "sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==", "license": "MIT", "dependencies": { - "debug": "^4.4.0", - "fflate": "^0.8.2", - "token-types": "^6.0.0" + "debug": "^4.4.3", + "token-types": "^6.1.1" }, "engines": { "node": ">=18" @@ -12330,25 +12509,28 @@ "license": "MIT" }, "node_modules/@trivago/prettier-plugin-sort-imports": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-5.2.2.tgz", - "integrity": "sha512-fYDQA9e6yTNmA13TLVSA+WMQRc5Bn/c0EUBditUHNfMMxN7M82c38b1kEggVE3pLpZ0FwkwJkUEKMiOi52JXFA==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-6.0.2.tgz", + "integrity": "sha512-3DgfkukFyC/sE/VuYjaUUWoFfuVjPK55vOFDsxD56XXynFMCZDYFogH2l/hDfOsQAm1myoU/1xByJ3tWqtulXA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@babel/generator": "^7.26.5", - "@babel/parser": "^7.26.7", - "@babel/traverse": "^7.26.7", - "@babel/types": "^7.26.7", + "@babel/generator": "^7.28.0", + "@babel/parser": "^7.28.0", + "@babel/traverse": "^7.28.0", + "@babel/types": "^7.28.0", "javascript-natural-sort": "^0.7.1", - "lodash": "^4.17.21" + "lodash-es": "^4.17.21", + "minimatch": "^9.0.0", + "parse-imports-exports": "^0.2.4" }, "engines": { - "node": ">18.12" + "node": ">= 20" }, "peerDependencies": { "@vue/compiler-sfc": "3.x", "prettier": "2.x - 3.x", + "prettier-plugin-ember-template-tag": ">= 2.0.0", "prettier-plugin-svelte": "3.x", "svelte": "4.x || 5.x" }, @@ -12356,6 +12538,9 @@ "@vue/compiler-sfc": { "optional": true }, + "prettier-plugin-ember-template-tag": { + "optional": true + }, "prettier-plugin-svelte": { "optional": true }, @@ -12364,6 +12549,32 @@ } } }, + "node_modules/@trivago/prettier-plugin-sort-imports/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@trivago/prettier-plugin-sort-imports/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@trysound/sax": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", @@ -12564,6 +12775,16 @@ "@types/node": "*" } }, + "node_modules/@types/cookie-parser": { + "version": "1.4.10", + "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.10.tgz", + "integrity": "sha512-B4xqkqfZ8Wek+rCOeRxsjMS9OgvzebEzzLYw7NHYuvzb7IdxOkI0ZHGgeEBX4PUM7QGVvNSK60T3OvWj3YfBRg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/express": "*" + } + }, "node_modules/@types/d3": { "version": "7.4.3", "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz", @@ -13180,9 +13401,9 @@ } }, "node_modules/@types/passport-google-oauth20": { - "version": "2.0.16", - "resolved": "https://registry.npmjs.org/@types/passport-google-oauth20/-/passport-google-oauth20-2.0.16.tgz", - "integrity": "sha512-ayXK2CJ7uVieqhYOc6k/pIr5pcQxOLB6kBev+QUGS7oEZeTgIs1odDobXRqgfBPvXzl0wXCQHftV5220czZCPA==", + "version": "2.0.17", + "resolved": "https://registry.npmjs.org/@types/passport-google-oauth20/-/passport-google-oauth20-2.0.17.tgz", + "integrity": "sha512-MHNOd2l7gOTCn3iS+wInPQMiukliAUvMpODO3VlXxOiwNEMSyzV7UNvAdqxSN872o8OXx1SqPDVT6tLW74AtqQ==", "dev": true, "license": "MIT", "dependencies": { @@ -14855,7 +15076,6 @@ "version": "3.2.6", "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", - "dev": true, "license": "MIT" }, "node_modules/async-function": { @@ -14939,14 +15159,14 @@ } }, "node_modules/axios": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.4.tgz", - "integrity": "sha512-1wVkUaAO6WyaYtCkcYCOx12ZgpGf9Zif+qXa4n+oYzK558YryKqiL6UWwd5DqiH3VRW0GYhTZQ/vlgJrCoNQlg==", + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.6.tgz", + "integrity": "sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==", "dev": true, "license": "MIT", "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.4", + "follow-redirects": "^1.15.11", + "form-data": "^4.0.5", "proxy-from-env": "^1.1.0" } }, @@ -15249,7 +15469,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, "license": "MIT" }, "node_modules/base64-js": { @@ -15503,7 +15722,6 @@ "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -16101,25 +16319,25 @@ } }, "node_modules/cheerio": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0.tgz", - "integrity": "sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.2.0.tgz", + "integrity": "sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==", "license": "MIT", "dependencies": { "cheerio-select": "^2.1.0", "dom-serializer": "^2.0.0", "domhandler": "^5.0.3", - "domutils": "^3.1.0", - "encoding-sniffer": "^0.2.0", - "htmlparser2": "^9.1.0", - "parse5": "^7.1.2", - "parse5-htmlparser2-tree-adapter": "^7.0.0", + "domutils": "^3.2.2", + "encoding-sniffer": "^0.2.1", + "htmlparser2": "^10.1.0", + "parse5": "^7.3.0", + "parse5-htmlparser2-tree-adapter": "^7.1.0", "parse5-parser-stream": "^7.1.2", - "undici": "^6.19.5", + "undici": "^7.19.0", "whatwg-mimetype": "^4.0.0" }, "engines": { - "node": ">=18.17" + "node": ">=20.18.1" }, "funding": { "url": "https://github.com/cheeriojs/cheerio?sponsor=1" @@ -16142,25 +16360,6 @@ "url": "https://github.com/sponsors/fb55" } }, - "node_modules/cheerio/node_modules/htmlparser2": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz", - "integrity": "sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==", - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "MIT", - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.1.0", - "entities": "^4.5.0" - } - }, "node_modules/cheerio/node_modules/parse5": { "version": "7.3.0", "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", @@ -16295,14 +16494,14 @@ "license": "MIT" }, "node_modules/class-validator": { - "version": "0.14.3", - "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.3.tgz", - "integrity": "sha512-rXXekcjofVN1LTOSw+u4u9WXVEUvNBVjORW154q/IdmYWy1nMbOU9aNtZB0t8m+FJQ9q91jlr2f9CwwUFdFMRA==", + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.15.1.tgz", + "integrity": "sha512-LqoS80HBBSCVhz/3KloUly0ovokxpdOLR++Al3J3+dHXWt9sTKlKd4eYtoxhxyUjoe5+UcIM+5k9MIxyBWnRTw==", "license": "MIT", "dependencies": { "@types/validator": "^13.15.3", "libphonenumber-js": "^1.11.1", - "validator": "^13.15.20" + "validator": "^13.15.22" } }, "node_modules/clean-css": { @@ -16747,7 +16946,6 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, "license": "MIT" }, "node_modules/confbox": { @@ -16819,6 +17017,25 @@ "node": ">= 0.6" } }, + "node_modules/cookie-parser": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz", + "integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==", + "license": "MIT", + "dependencies": { + "cookie": "0.7.2", + "cookie-signature": "1.0.6" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/cookie-parser/node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" + }, "node_modules/cookie-signature": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", @@ -16901,9 +17118,9 @@ "license": "MIT" }, "node_modules/cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", "license": "MIT", "dependencies": { "object-assign": "^4", @@ -16911,6 +17128,10 @@ }, "engines": { "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/corser": { @@ -16971,9 +17192,9 @@ } }, "node_modules/countries-list": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/countries-list/-/countries-list-3.2.2.tgz", - "integrity": "sha512-ABJ/RWQBrPWy+hRuZoW+0ooK8p65Eo3WmUZwHm6v4wmfSPznNAKzjy3+UUYrJK2v3182BVsgWxdB6ROidj39kw==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/countries-list/-/countries-list-3.3.0.tgz", + "integrity": "sha512-XRUjS+dcZuNh/fg3+mka3bXgcg4TbQZ1gaK5IJqO6qulerBANl1bmrd20P2dgmPkBpP+5FnejiSF1gd7bgAg+g==", "license": "MIT" }, "node_modules/countup.js": { @@ -16990,9 +17211,9 @@ "license": "MIT" }, "node_modules/cron": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/cron/-/cron-4.3.3.tgz", - "integrity": "sha512-B/CJj5yL3sjtlun6RtYHvoSB26EmQ2NUmhq9ZiJSyKIM4K/fqfh9aelDFlIayD2YMeFZqWLi9hHV+c+pq2Djkw==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/cron/-/cron-4.4.0.tgz", + "integrity": "sha512-fkdfq+b+AHI4cKdhZlppHveI/mgz2qpiYxcm+t5E5TsxX7QrLS1VE0+7GENEk9z0EeGPcpSciGv6ez24duWhwQ==", "license": "MIT", "dependencies": { "@types/luxon": "~3.7.0", @@ -17000,6 +17221,10 @@ }, "engines": { "node": ">=18.x" + }, + "funding": { + "type": "ko-fi", + "url": "https://ko-fi.com/intcreator" } }, "node_modules/cron-parser": { @@ -18207,6 +18432,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, "license": "MIT" }, "node_modules/deepmerge": { @@ -18698,7 +18924,6 @@ "version": "3.1.10", "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", - "dev": true, "license": "Apache-2.0", "dependencies": { "jake": "^10.8.5" @@ -19167,6 +19392,37 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "license": "BSD-2-Clause", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/eslint": { "version": "9.35.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.35.0.tgz", @@ -19600,7 +19856,6 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=4.0" @@ -19769,18 +20024,19 @@ "license": "Apache-2.0" }, "node_modules/express": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", - "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "license": "MIT", "dependencies": { "accepts": "^2.0.0", - "body-parser": "^2.2.0", + "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", + "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", @@ -19947,6 +20203,7 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, "license": "MIT" }, "node_modules/fast-redact": { @@ -20046,12 +20303,6 @@ "filenamify-url": "2.1.2" } }, - "node_modules/fflate": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", - "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", - "license": "MIT" - }, "node_modules/figures": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", @@ -20092,14 +20343,14 @@ } }, "node_modules/file-type": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-21.0.0.tgz", - "integrity": "sha512-ek5xNX2YBYlXhiUXui3D/BXa3LdqPmoLJ7rqEx2bKJ7EAUEfmXgW0Das7Dc6Nr9MvqaOnIqiPV0mZk/r/UpNAg==", + "version": "21.3.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-21.3.0.tgz", + "integrity": "sha512-8kPJMIGz1Yt/aPEwOsrR97ZyZaD1Iqm8PClb1nYFclUCkBi0Ma5IsYNQzvSFS9ib51lWyIw5mIT9rWzI/xjpzA==", "license": "MIT", "dependencies": { - "@tokenizer/inflate": "^0.2.7", - "strtok3": "^10.2.2", - "token-types": "^6.0.0", + "@tokenizer/inflate": "^0.4.1", + "strtok3": "^10.3.4", + "token-types": "^6.1.1", "uint8array-extras": "^1.4.0" }, "engines": { @@ -20113,7 +20364,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", - "dev": true, "license": "Apache-2.0", "dependencies": { "minimatch": "^5.0.1" @@ -20123,7 +20373,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" @@ -20133,7 +20382,6 @@ "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" @@ -20332,9 +20580,9 @@ "license": "ISC" }, "node_modules/follow-redirects": { - "version": "1.15.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", - "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", "funding": [ { "type": "individual", @@ -20420,9 +20668,9 @@ } }, "node_modules/fork-ts-checker-webpack-plugin/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "dev": true, "license": "MIT", "dependencies": { @@ -21345,7 +21593,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "devOptional": true, "license": "MIT", "engines": { "node": ">=8" @@ -21656,9 +21903,9 @@ } }, "node_modules/htmlparser2": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.0.0.tgz", - "integrity": "sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.1.0.tgz", + "integrity": "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==", "funding": [ "https://github.com/fb55/htmlparser2?sponsor=1", { @@ -21670,14 +21917,14 @@ "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", - "domutils": "^3.2.1", - "entities": "^6.0.0" + "domutils": "^3.2.2", + "entities": "^7.0.1" } }, "node_modules/htmlparser2/node_modules/entities": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", "license": "BSD-2-Clause", "engines": { "node": ">=0.12" @@ -22985,7 +23232,6 @@ "version": "10.9.2", "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", - "dev": true, "license": "Apache-2.0", "dependencies": { "async": "^3.2.3", @@ -23004,7 +23250,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -24486,20 +24731,20 @@ "license": "MIT" }, "node_modules/jsonpath": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/jsonpath/-/jsonpath-1.1.1.tgz", - "integrity": "sha512-l6Cg7jRpixfbgoWgkrl77dgEj8RPvND0wMH6TwQmi9Qs4TFfS9u5cUFnbeKTwj5ga5Y3BTGGNI28k117LJ009w==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/jsonpath/-/jsonpath-1.2.1.tgz", + "integrity": "sha512-Jl6Jhk0jG+kP3yk59SSeGq7LFPR4JQz1DU0K+kXTysUhMostbhU3qh5mjTuf0PqFcXpAT7kvmMt9WxV10NyIgQ==", "license": "MIT", "dependencies": { - "esprima": "1.2.2", - "static-eval": "2.0.2", - "underscore": "1.12.1" + "esprima": "1.2.5", + "static-eval": "2.1.1", + "underscore": "1.13.6" } }, "node_modules/jsonpath/node_modules/esprima": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.2.tgz", - "integrity": "sha512-+JpPZam9w5DuJ3Q67SqsMGtiHKENSMRVoxvArfJZK01/BfLEObtZ6orJa/MtoGNR/rfMgp5837T41PAmTwAv/A==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz", + "integrity": "sha512-S9VbPDU0adFErpDai3qDkjq8+G05ONtKzcyNrPKg/ZKa+tf879nX2KexNU95b31UoTJjRLInNBHHHjFPoCd7lQ==", "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" @@ -24509,12 +24754,12 @@ } }, "node_modules/jsonwebtoken": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", - "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", + "integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==", "license": "MIT", "dependencies": { - "jws": "^3.2.2", + "jws": "^4.0.1", "lodash.includes": "^4.3.0", "lodash.isboolean": "^3.0.3", "lodash.isinteger": "^4.0.4", @@ -24530,27 +24775,6 @@ "npm": ">=6" } }, - "node_modules/jsonwebtoken/node_modules/jwa": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", - "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==", - "license": "MIT", - "dependencies": { - "buffer-equal-constant-time": "^1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/jsonwebtoken/node_modules/jws": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.3.tgz", - "integrity": "sha512-byiJ0FLRdLdSVSReO/U4E7RoEyOCKnEnEPMjq3HxWtvzLsV08/i5RQKsFVNkCldrCaPr2vDNAOMsfs8T/Hze7g==", - "license": "MIT", - "dependencies": { - "jwa": "^1.4.2", - "safe-buffer": "^5.0.1" - } - }, "node_modules/jsonwebtoken/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -25102,8 +25326,8 @@ "version": "4.17.22", "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.22.tgz", "integrity": "sha512-XEawp1t0gxSi9x01glktRZ5HDy0HXqrM0x5pXQM98EaI0NxO6jVM7omDOxsuEo5UIASAnm2bRp1Jt/e0a2XU8Q==", - "license": "MIT", - "optional": true + "devOptional": true, + "license": "MIT" }, "node_modules/lodash.clonedeepwith": { "version": "4.5.0", @@ -25542,9 +25766,9 @@ } }, "node_modules/marked": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/marked/-/marked-17.0.1.tgz", - "integrity": "sha512-boeBdiS0ghpWcSwoNm/jJBwdpFaMnZWRzjA6SkUMYb40SVaN1x7mmfGKp0jvexGcx+7y2La5zRZsYFZI6Qpypg==", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-17.0.2.tgz", + "integrity": "sha512-s5HZGFQea7Huv5zZcAGhJLT3qLpAfnY7v7GWkICUr0+Wd5TFEtdlRR2XUL5Gg+RH7u2Df595ifrxR03mBaw7gA==", "license": "MIT", "bin": { "marked": "bin/marked.js" @@ -25797,7 +26021,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -25816,11 +26039,11 @@ } }, "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "engines": { "node": ">=16 || 14 >=14.17" } @@ -26193,9 +26416,9 @@ "license": "MIT" }, "node_modules/ng-extract-i18n-merge": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ng-extract-i18n-merge/-/ng-extract-i18n-merge-3.2.1.tgz", - "integrity": "sha512-Yq8uEBa32/Imlo+vnyY6rk+h0VOjWQT8r4Vgiw/YlnK0AzIXFxr6H/Ji3gTJKVsuRY6Tt1swBgmnkAUeDmklRw==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/ng-extract-i18n-merge/-/ng-extract-i18n-merge-3.3.0.tgz", + "integrity": "sha512-9VCi2gMSjvlz5+bvJ9wTzHEeEiVCM0lb/uvGx2K3FavG4p0HKhg0Y9Tjr/Hr23DSHAQQXS0gssIvznWW3DHIXQ==", "license": "MIT", "dependencies": { "@angular-devkit/architect": ">=0.2000.0 <0.2200.0", @@ -26225,16 +26448,16 @@ } }, "node_modules/ngx-markdown": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/ngx-markdown/-/ngx-markdown-21.0.1.tgz", - "integrity": "sha512-TQnxrU9b+JclgXBFVg0Xp/6YEMom+hpiEjBMlE56cIWzONNh7pshMeMkz972wWzvQvTP+55/BmEZQc+4Vq1MWg==", + "version": "21.1.0", + "resolved": "https://registry.npmjs.org/ngx-markdown/-/ngx-markdown-21.1.0.tgz", + "integrity": "sha512-qiyn9Je20F9yS4/q0p1Xhk2b/HW0rHWWlJNRm8DIzJKNck9Rmn/BfFxq0webmQHPPyYkg2AjNq/ZeSqDTQJbsQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "optionalDependencies": { "clipboard": "^2.0.11", - "emoji-toolkit": ">= 8.0.0 < 10.0.0", + "emoji-toolkit": ">= 8.0.0 < 11.0.0", "katex": "^0.16.0", "mermaid": ">= 10.6.0 < 12.0.0", "prismjs": "^1.30.0" @@ -26243,7 +26466,7 @@ "@angular/common": "^21.0.0", "@angular/core": "^21.0.0", "@angular/platform-browser": "^21.0.0", - "marked": "^17.0.0 || ^16.0.0", + "marked": "^17.0.0", "rxjs": "^6.5.3 || ^7.4.0", "zone.js": "~0.15.0 || ~0.16.0" } @@ -26622,9 +26845,9 @@ "license": "MIT" }, "node_modules/nx": { - "version": "22.4.5", - "resolved": "https://registry.npmjs.org/nx/-/nx-22.4.5.tgz", - "integrity": "sha512-l68kzhnemXXGCDS9/W8eccZ7Bzse9pw1oJ466pzDM89MbA6hEaOQ0p+eDXZI++iWl0T+lYJ56EDhO23syKzt9g==", + "version": "22.5.3", + "resolved": "https://registry.npmjs.org/nx/-/nx-22.5.3.tgz", + "integrity": "sha512-IaEPqdgaFBIr0Bfmnt6WAcX3t660sOuDXQ71lpoS8GgpD8cqX1LIW2ZyzEAdOvCP1iD6HCZehpofcVvaaL1GNQ==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -26634,12 +26857,12 @@ "@yarnpkg/parsers": "3.0.2", "@zkochan/js-yaml": "0.0.7", "axios": "^1.12.0", - "chalk": "^4.1.0", "cli-cursor": "3.1.0", "cli-spinners": "2.6.1", "cliui": "^8.0.1", "dotenv": "~16.4.5", "dotenv-expand": "~11.0.6", + "ejs": "^3.1.7", "enquirer": "~2.3.6", "figures": "3.2.0", "flat": "^5.0.2", @@ -26648,11 +26871,12 @@ "jest-diff": "^30.0.2", "jsonc-parser": "3.2.0", "lines-and-columns": "2.0.3", - "minimatch": "10.1.1", + "minimatch": "10.2.1", "node-machine-id": "1.1.12", "npm-run-path": "^4.0.1", "open": "^8.4.0", "ora": "5.3.0", + "picocolors": "^1.1.0", "resolve.exports": "2.0.3", "semver": "^7.6.3", "string-width": "^4.2.3", @@ -26670,20 +26894,20 @@ "nx-cloud": "bin/nx-cloud.js" }, "optionalDependencies": { - "@nx/nx-darwin-arm64": "22.4.5", - "@nx/nx-darwin-x64": "22.4.5", - "@nx/nx-freebsd-x64": "22.4.5", - "@nx/nx-linux-arm-gnueabihf": "22.4.5", - "@nx/nx-linux-arm64-gnu": "22.4.5", - "@nx/nx-linux-arm64-musl": "22.4.5", - "@nx/nx-linux-x64-gnu": "22.4.5", - "@nx/nx-linux-x64-musl": "22.4.5", - "@nx/nx-win32-arm64-msvc": "22.4.5", - "@nx/nx-win32-x64-msvc": "22.4.5" + "@nx/nx-darwin-arm64": "22.5.3", + "@nx/nx-darwin-x64": "22.5.3", + "@nx/nx-freebsd-x64": "22.5.3", + "@nx/nx-linux-arm-gnueabihf": "22.5.3", + "@nx/nx-linux-arm64-gnu": "22.5.3", + "@nx/nx-linux-arm64-musl": "22.5.3", + "@nx/nx-linux-x64-gnu": "22.5.3", + "@nx/nx-linux-x64-musl": "22.5.3", + "@nx/nx-win32-arm64-msvc": "22.5.3", + "@nx/nx-win32-x64-msvc": "22.5.3" }, "peerDependencies": { - "@swc-node/register": "^1.8.0", - "@swc/core": "^1.3.85" + "@swc-node/register": "^1.11.1", + "@swc/core": "^1.15.8" }, "peerDependenciesMeta": { "@swc-node/register": { @@ -26716,6 +26940,29 @@ "tslib": "^2.4.0" } }, + "node_modules/nx/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/nx/node_modules/brace-expansion": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, "node_modules/nx/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -26829,13 +27076,13 @@ "license": "MIT" }, "node_modules/nx/node_modules/minimatch": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", - "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.1.tgz", + "integrity": "sha512-MClCe8IL5nRRmawL6ib/eT4oLyeKMGCghibcDWK+J0hh0Q8kqSdia6BvbRMVk6mPa6WqUa5uR2oxt6C5jd533A==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { - "@isaacs/brace-expansion": "^5.0.0" + "brace-expansion": "^5.0.2" }, "engines": { "node": "20 || >=22" @@ -27551,6 +27798,16 @@ "node": ">=6" } }, + "node_modules/parse-imports-exports": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/parse-imports-exports/-/parse-imports-exports-0.2.4.tgz", + "integrity": "sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse-statements": "1.0.11" + } + }, "node_modules/parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", @@ -27604,6 +27861,13 @@ "node": ">=0.10.0" } }, + "node_modules/parse-statements": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/parse-statements/-/parse-statements-1.0.11.tgz", + "integrity": "sha512-HlsyYdMBnbPQ9Jr/VgJ1YF4scnldvJpJxCVx6KgqPL4dxppsWrJHCIIxQXMJrqGnsRkNPATbeMJ8Yxu7JMsYcA==", + "dev": true, + "license": "MIT" + }, "node_modules/parse5": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.0.tgz", @@ -29389,6 +29653,15 @@ "node": ">=4" } }, + "node_modules/redis-info": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/redis-info/-/redis-info-3.1.0.tgz", + "integrity": "sha512-ER4L9Sh/vm63DkIE0bkSjxluQlioBiBgf5w1UuldaW/3vPcecdljVDisZhmnCMvsxHNiARTTDDHGg9cGwTfrKg==", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.11" + } + }, "node_modules/redis-parser": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", @@ -29647,15 +29920,15 @@ } }, "node_modules/replace-in-file": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/replace-in-file/-/replace-in-file-8.3.0.tgz", - "integrity": "sha512-4VhddQiMCPIuypiwHDTM+XHjZoVu9h7ngBbSCnwGRcwdHwxltjt/m//Ep3GDwqaOx1fDSrKFQ+n7uo4uVcEz9Q==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/replace-in-file/-/replace-in-file-8.4.0.tgz", + "integrity": "sha512-D28k8jy2LtUGbCzCnR3znajaTWIjJ/Uee3UdodzcHRxE7zn6NmYW/dcSqyivnsYU3W+MxdX6SbF28NvJ0GRoLA==", "dev": true, "license": "MIT", "dependencies": { - "chalk": "^5.3.0", - "glob": "^10.4.2", - "yargs": "^17.7.2" + "chalk": "^5.6.2", + "glob": "^13.0.0", + "yargs": "^18.0.0" }, "bin": { "replace-in-file": "bin/cli.js" @@ -29664,10 +29937,33 @@ "node": ">=18" } }, + "node_modules/replace-in-file/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/replace-in-file/node_modules/brace-expansion": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, "node_modules/replace-in-file/node_modules/chalk": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", - "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", "dev": true, "license": "MIT", "engines": { @@ -29677,23 +29973,65 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/replace-in-file/node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "node_modules/replace-in-file/node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", "dev": true, - "license": "MIT", + "license": "BlueOak-1.0.0", "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" }, "engines": { - "node": ">=12" + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/replace-in-file/node_modules/lru-cache": { + "version": "11.2.7", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.7.tgz", + "integrity": "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/replace-in-file/node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/replace-in-file/node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/require-directory": { @@ -31660,103 +31998,12 @@ "license": "MIT" }, "node_modules/static-eval": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.0.2.tgz", - "integrity": "sha512-N/D219Hcr2bPjLxPiV+TQE++Tsmrady7TqAJugLy7Xk1EumfDWS/f5dtBbkRCGE7wKKXuYockQoj8Rm2/pVKyg==", - "license": "MIT", - "dependencies": { - "escodegen": "^1.8.1" - } - }, - "node_modules/static-eval/node_modules/escodegen": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", - "license": "BSD-2-Clause", - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=4.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/static-eval/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/static-eval/node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", - "license": "MIT", - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/static-eval/node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "license": "MIT", - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/static-eval/node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/static-eval/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "license": "BSD-3-Clause", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-eval/node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.1.1.tgz", + "integrity": "sha512-MgWpQ/ZjGieSVB3eOJVs4OA2LT/q1vx98KPCTTQPzq/aLr0YUXTsgryTXr4SLfR0ZfUUCiedM9n/ABeDIyy4mA==", "license": "MIT", "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" + "escodegen": "^2.1.0" } }, "node_modules/statuses": { @@ -32104,9 +32351,9 @@ } }, "node_modules/stripe": { - "version": "20.3.0", - "resolved": "https://registry.npmjs.org/stripe/-/stripe-20.3.0.tgz", - "integrity": "sha512-DYzcmV1MfYhycr1GwjCjeQVYk9Gu8dpxyTlu7qeDCsuguug7oUTxPsUQuZeSf/OPzK7pofqobvOKVqAwlpgf/Q==", + "version": "20.4.1", + "resolved": "https://registry.npmjs.org/stripe/-/stripe-20.4.1.tgz", + "integrity": "sha512-axCguHItc8Sxt0HC6aSkdVRPffjYPV7EQqZRb2GkIa8FzWDycE7nHJM19C6xAIynH1Qp1/BHiopSi96jGBxT0w==", "license": "MIT", "engines": { "node": ">=16" @@ -32181,7 +32428,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -32210,9 +32456,9 @@ "license": "BSD-2-Clause" }, "node_modules/svgmap": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/svgmap/-/svgmap-2.14.0.tgz", - "integrity": "sha512-+Vklx4DO1uv1SFq6wnJWl/dRjX4uRT9CcsIHuADxAcZ+h5X1OSyDVbNdIu837fx5TtYYuaGRhWuFCXIioN/1ww==", + "version": "2.19.2", + "resolved": "https://registry.npmjs.org/svgmap/-/svgmap-2.19.2.tgz", + "integrity": "sha512-mRqRcQiwwSTh9kTOPhjTmd3ywxA9aTfybBHGAoyuGn9CI9PnAQsuZ7H/2/VEIvgJhi1xM5IGBfk8i4/Ke4iTCQ==", "license": "MIT", "dependencies": { "svg-pan-zoom": "^3.6.2" @@ -32817,11 +33063,12 @@ } }, "node_modules/token-types": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/token-types/-/token-types-6.0.4.tgz", - "integrity": "sha512-MD9MjpVNhVyH4fyd5rKphjvt/1qj+PtQUz65aFqAZA6XniWAuSFRjLk3e2VALEFlh9OwBpXUN7rfeqSnT/Fmkw==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-6.1.2.tgz", + "integrity": "sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==", "license": "MIT", "dependencies": { + "@borewit/text-codec": "^0.2.1", "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" }, @@ -32955,18 +33202,15 @@ } }, "node_modules/ts-checker-rspack-plugin": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/ts-checker-rspack-plugin/-/ts-checker-rspack-plugin-1.2.6.tgz", - "integrity": "sha512-aAJIfoNr2cPu8G6mqp/oPoNlUT/LgNoqt2n3SsbxWG0TwQogbjsYsr2f/fdsufUDoGDu8Jolmpf3L4PmIH/cEg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-checker-rspack-plugin/-/ts-checker-rspack-plugin-1.3.0.tgz", + "integrity": "sha512-89oK/BtApjdid1j9CGjPGiYry+EZBhsnTAM481/8ipgr/y2IOgCbW1HPnan+fs5FnzlpUgf9dWGNZ4Ayw3Bd8A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", "@rspack/lite-tapable": "^1.1.0", "chokidar": "^3.6.0", - "is-glob": "^4.0.3", - "memfs": "^4.51.1", - "minimatch": "^9.0.5", + "memfs": "^4.56.10", "picocolors": "^1.1.1" }, "peerDependencies": { @@ -32979,16 +33223,6 @@ } } }, - "node_modules/ts-checker-rspack-plugin/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/ts-checker-rspack-plugin/node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -33057,22 +33291,6 @@ "tslib": "2" } }, - "node_modules/ts-checker-rspack-plugin/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/ts-checker-rspack-plugin/node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", @@ -33367,6 +33585,24 @@ "node": ">=0.6.x" } }, + "node_modules/tsyringe": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/tsyringe/-/tsyringe-4.10.0.tgz", + "integrity": "sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==", + "license": "MIT", + "dependencies": { + "tslib": "^1.9.3" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/tsyringe/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, "node_modules/tuf-js": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-4.1.0.tgz", @@ -33589,9 +33825,9 @@ "license": "MIT" }, "node_modules/uint8array-extras": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/uint8array-extras/-/uint8array-extras-1.4.0.tgz", - "integrity": "sha512-ZPtzy0hu4cZjv3z5NW9gfKnNLjoz4y6uv4HlelAjDK7sY/xOkKZv9xK/WQpcsBB3jEybChz9DPC2U/+cusjJVQ==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/uint8array-extras/-/uint8array-extras-1.5.0.tgz", + "integrity": "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==", "license": "MIT", "engines": { "node": ">=18" @@ -33620,18 +33856,18 @@ } }, "node_modules/underscore": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz", - "integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==", + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", + "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", "license": "MIT" }, "node_modules/undici": { - "version": "6.21.3", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.21.3.tgz", - "integrity": "sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw==", + "version": "7.22.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.22.0.tgz", + "integrity": "sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg==", "license": "MIT", "engines": { - "node": ">=18.17" + "node": ">=20.18.1" } }, "node_modules/undici-types": { @@ -35225,6 +35461,7 @@ "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -35375,9 +35612,9 @@ } }, "node_modules/yahoo-finance2": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/yahoo-finance2/-/yahoo-finance2-3.13.0.tgz", - "integrity": "sha512-czBj2q/MD68YEsB7aXNnGhJvWxYZn01O5r/i7VYiQV2m2sWwhca6tKgjwf/LT7zHHEVxhKNiGLB46glLnmq9Ag==", + "version": "3.13.2", + "resolved": "https://registry.npmjs.org/yahoo-finance2/-/yahoo-finance2-3.13.2.tgz", + "integrity": "sha512-aAOJEjuLClfDxVPRKxjcwFoyzMr8BE/svgUqr5IjnQR+kppYbKO92Wl3SbAGz5DRghy6FiUfqi5FBDSBA/e2jg==", "license": "MIT", "dependencies": { "@deno/shim-deno": "~0.18.0", diff --git a/package.json b/package.json index 4bfad50ff..b7f9bc2e7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "2.238.0", + "version": "2.251.0", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "repository": "https://github.com/ghostfolio/ghostfolio", @@ -43,10 +43,11 @@ "start:production": "npm run database:migrate && npm run database:seed && node main", "start:server": "nx run api:copy-assets && nx run api:serve --watch", "start:storybook": "nx run ui:storybook", - "test": "npm run test:api && npm run test:common", + "test": "npx dotenv-cli -e .env.example -- npx nx run-many --target=test --all --parallel=4", "test:api": "npx dotenv-cli -e .env.example -- nx test api", "test:common": "npx dotenv-cli -e .env.example -- nx test common", "test:single": "nx run api:test --test-file object.helper.spec.ts", + "test:ui": "npx dotenv-cli -e .env.example -- nx test ui", "ts-node": "ts-node", "update": "nx migrate latest", "watch:server": "nx run api:copy-assets && nx run api:build --watch", @@ -65,26 +66,29 @@ "@angular/platform-browser-dynamic": "21.1.1", "@angular/router": "21.1.1", "@angular/service-worker": "21.1.1", + "@bull-board/api": "6.20.3", + "@bull-board/express": "6.20.3", + "@bull-board/nestjs": "6.20.3", "@codewithdan/observable-store": "2.2.15", "@date-fns/utc": "2.1.1", "@internationalized/number": "3.6.5", - "@ionic/angular": "8.7.8", + "@ionic/angular": "8.8.1", "@keyv/redis": "4.4.0", "@nestjs/bull": "11.0.4", - "@nestjs/cache-manager": "3.0.1", - "@nestjs/common": "11.1.8", - "@nestjs/config": "4.0.2", - "@nestjs/core": "11.1.8", + "@nestjs/cache-manager": "3.1.0", + "@nestjs/common": "11.1.14", + "@nestjs/config": "4.0.3", + "@nestjs/core": "11.1.14", "@nestjs/event-emitter": "3.0.1", - "@nestjs/jwt": "11.0.1", + "@nestjs/jwt": "11.0.2", "@nestjs/passport": "11.0.5", - "@nestjs/platform-express": "11.1.8", - "@nestjs/schedule": "6.0.1", + "@nestjs/platform-express": "11.1.14", + "@nestjs/schedule": "6.1.1", "@nestjs/serve-static": "5.0.4", "@openrouter/ai-sdk-provider": "0.7.2", "@prisma/client": "6.19.0", - "@simplewebauthn/browser": "13.1.0", - "@simplewebauthn/server": "13.1.1", + "@simplewebauthn/browser": "13.2.2", + "@simplewebauthn/server": "13.2.2", "ai": "4.3.16", "alphavantage": "2.2.0", "big.js": "7.0.1", @@ -95,12 +99,13 @@ "chartjs-chart-treemap": "3.1.0", "chartjs-plugin-annotation": "3.1.0", "chartjs-plugin-datalabels": "2.2.0", - "cheerio": "1.0.0", + "cheerio": "1.2.0", "class-transformer": "0.5.1", - "class-validator": "0.14.3", + "class-validator": "0.15.1", "color": "5.0.3", + "cookie-parser": "1.4.7", "countries-and-timezones": "3.8.0", - "countries-list": "3.2.2", + "countries-list": "3.3.0", "countup.js": "2.9.0", "date-fns": "4.1.0", "dotenv": "17.2.3", @@ -112,13 +117,13 @@ "helmet": "7.0.0", "http-status-codes": "2.3.0", "ionicons": "8.0.13", - "jsonpath": "1.1.1", + "jsonpath": "1.2.1", "lodash": "4.17.23", - "marked": "17.0.1", + "marked": "17.0.2", "ms": "3.0.0-canary.1", - "ng-extract-i18n-merge": "3.2.1", + "ng-extract-i18n-merge": "3.3.0", "ngx-device-detector": "11.0.0", - "ngx-markdown": "21.0.1", + "ngx-markdown": "21.1.0", "ngx-skeleton-loader": "12.0.0", "open-color": "1.9.1", "papaparse": "5.3.1", @@ -129,11 +134,11 @@ "passport-openidconnect": "0.1.2", "reflect-metadata": "0.2.2", "rxjs": "7.8.1", - "stripe": "20.3.0", - "svgmap": "2.14.0", + "stripe": "20.4.1", + "svgmap": "2.19.2", "tablemark": "4.1.0", "twitter-api-v2": "1.29.0", - "yahoo-finance2": "3.13.0", + "yahoo-finance2": "3.13.2", "zone.js": "0.16.0" }, "devDependencies": { @@ -151,22 +156,23 @@ "@eslint/eslintrc": "3.3.1", "@eslint/js": "9.35.0", "@nestjs/schematics": "11.0.9", - "@nestjs/testing": "11.1.8", - "@nx/angular": "22.4.5", - "@nx/eslint-plugin": "22.4.5", - "@nx/jest": "22.4.5", - "@nx/js": "22.4.5", - "@nx/module-federation": "22.4.5", - "@nx/nest": "22.4.5", - "@nx/node": "22.4.5", - "@nx/storybook": "22.4.5", - "@nx/web": "22.4.5", - "@nx/workspace": "22.4.5", + "@nestjs/testing": "11.1.14", + "@nx/angular": "22.5.3", + "@nx/eslint-plugin": "22.5.3", + "@nx/jest": "22.5.3", + "@nx/js": "22.5.3", + "@nx/module-federation": "22.5.3", + "@nx/nest": "22.5.3", + "@nx/node": "22.5.3", + "@nx/storybook": "22.5.3", + "@nx/web": "22.5.3", + "@nx/workspace": "22.5.3", "@schematics/angular": "21.1.1", "@storybook/addon-docs": "10.1.10", "@storybook/angular": "10.1.10", - "@trivago/prettier-plugin-sort-imports": "5.2.2", + "@trivago/prettier-plugin-sort-imports": "6.0.2", "@types/big.js": "6.2.2", + "@types/cookie-parser": "1.4.10", "@types/fast-redact": "3.0.4", "@types/google-spreadsheet": "3.1.5", "@types/jest": "30.0.0", @@ -174,7 +180,7 @@ "@types/lodash": "4.17.23", "@types/node": "22.15.17", "@types/papaparse": "5.3.7", - "@types/passport-google-oauth20": "2.0.16", + "@types/passport-google-oauth20": "2.0.17", "@types/passport-openidconnect": "0.1.3", "@typescript-eslint/eslint-plugin": "8.43.0", "@typescript-eslint/parser": "8.43.0", @@ -186,13 +192,13 @@ "jest": "30.2.0", "jest-environment-jsdom": "30.2.0", "jest-preset-angular": "16.0.0", - "nx": "22.4.5", + "nx": "22.5.3", "prettier": "3.8.1", "prettier-plugin-organize-attributes": "1.0.0", "prisma": "6.19.0", "react": "18.2.0", "react-dom": "18.2.0", - "replace-in-file": "8.3.0", + "replace-in-file": "8.4.0", "shx": "0.4.0", "storybook": "10.1.10", "ts-jest": "29.4.0", diff --git a/test/import/ok/penthouse-apartment.json b/test/import/ok/penthouse-apartment.json index 0c35521e6..3b5e5420b 100644 --- a/test/import/ok/penthouse-apartment.json +++ b/test/import/ok/penthouse-apartment.json @@ -21,10 +21,8 @@ "isin": null, "marketData": [], "name": "Penthouse Apartment", - "scraperConfiguration": null, "sectors": [], "symbol": "7e91b7d4-1430-4212-8380-289a06c9bbc1", - "symbolMapping": {}, "url": null } ], diff --git a/test/import/ok/sample.json b/test/import/ok/sample.json index bc2798718..be385812a 100644 --- a/test/import/ok/sample.json +++ b/test/import/ok/sample.json @@ -41,10 +41,8 @@ "isin": null, "marketData": [], "name": "Account Opening Fee", - "scraperConfiguration": null, "sectors": [], "symbol": "14a69cb9-1e31-43fa-b320-83703d8ed74b", - "symbolMapping": {}, "url": null }, { @@ -63,10 +61,8 @@ "isin": null, "marketData": [], "name": "Penthouse Apartment", - "scraperConfiguration": null, "sectors": [], "symbol": "7e91b7d4-1430-4212-8380-289a06c9bbc1", - "symbolMapping": {}, "url": null } ],