diff --git a/CHANGELOG.md b/CHANGELOG.md index df6e56450..5cdaefeb7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,11 +5,58 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased +## 1.220.0 - 2022-12-23 + +### Added + +- Added the position detail dialog to the _Top 3_ and _Bottom 3_ performers of the analysis page +- Added the `dryRun` option to the import activities endpoint + +### Changed + +- Increased the historical data chart of the _Fear & Greed Index_ (market mood) to 365 days +- Upgraded `color` from version `4.0.1` to `4.2.3` +- Upgraded `prettier` from version `2.7.1` to `2.8.1` + +### Fixed + +- Fixed the rounding of the y-axis ticks in the benchmark comparator + +## 1.219.0 - 2022-12-17 + +### Added + +- Added support to disable user sign up in the admin control panel +- Extended the glossary of the resources page by _Deflation_, _Inflation_ and _Stagflation_ + +### Changed + +- Added the name to the symbol column in the activities table +- Combined the name and symbol column in the holdings table (former positions table) + +## 1.218.0 - 2022-12-12 + +### Added + +- Added the date of the first activity to the positions table +- Added an endpoint to fetch the logo of an asset or a platform + +### Changed + +- Improved the asset profile details dialog in the admin control panel +- Upgraded `chart.js` from version `3.8.0` to `4.0.1` + +## 1.217.0 - 2022-12-10 + +### Added + +- Added the dividend timeline grouped by month ### Changed +- Improved the value redaction interceptor (including `comment`) - Improved the language localization for Español (`es`) +- Upgraded `cheerio` from version `1.0.0-rc.6` to `1.0.0-rc.12` - Upgraded `prisma` from version `4.6.1` to `4.7.1` ### Fixed diff --git a/README.md b/README.md index f63530051..a44174edf 100644 --- a/README.md +++ b/README.md @@ -15,14 +15,16 @@ Ghostfol.ioLive Demo | Ghostfolio Premium | FAQ | Blog | Slack | Twitter

+ + - + License: AGPL v3

-**Ghostfolio** is an open source wealth management software built with web technology. The application empowers busy people to keep track of stocks, ETFs or cryptocurrencies and make solid, data-driven investment decisions. +**Ghostfolio** is an open source wealth management software built with web technology. The application empowers busy people to keep track of stocks, ETFs or cryptocurrencies and make solid, data-driven investment decisions. The software is designed for personal use in continuous operation.
diff --git a/apps/api/src/app/app.module.ts b/apps/api/src/app/app.module.ts index 47c19991c..9f8eb28b8 100644 --- a/apps/api/src/app/app.module.ts +++ b/apps/api/src/app/app.module.ts @@ -27,6 +27,7 @@ import { ExportModule } from './export/export.module'; import { FrontendMiddleware } from './frontend.middleware'; 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 { PortfolioModule } from './portfolio/portfolio.module'; import { SubscriptionModule } from './subscription/subscription.module'; @@ -58,6 +59,7 @@ import { UserModule } from './user/user.module'; ExportModule, ImportModule, InfoModule, + LogoModule, OrderModule, PortfolioModule, PrismaModule, diff --git a/apps/api/src/app/auth/auth.controller.ts b/apps/api/src/app/auth/auth.controller.ts index 749f6f037..08d1c1a31 100644 --- a/apps/api/src/app/auth/auth.controller.ts +++ b/apps/api/src/app/auth/auth.controller.ts @@ -16,6 +16,7 @@ import { Version } from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; +import { Request, Response } from 'express'; import { StatusCodes, getReasonPhrase } from 'http-status-codes'; import { AuthService } from './auth.service'; @@ -58,18 +59,21 @@ export class AuthController { @Get('google/callback') @UseGuards(AuthGuard('google')) @Version(VERSION_NEUTRAL) - public googleLoginCallback(@Req() req, @Res() res) { + public googleLoginCallback( + @Req() request: Request, + @Res() response: Response + ) { // Handles the Google OAuth2 callback - const jwt: string = req.user.jwt; + const jwt: string = (request.user).jwt; if (jwt) { - res.redirect( + response.redirect( `${this.configurationService.get( 'ROOT_URL' )}/${DEFAULT_LANGUAGE_CODE}/auth/${jwt}` ); } else { - res.redirect( + response.redirect( `${this.configurationService.get( 'ROOT_URL' )}/${DEFAULT_LANGUAGE_CODE}/auth` diff --git a/apps/api/src/app/auth/auth.module.ts b/apps/api/src/app/auth/auth.module.ts index b25e4c18b..dfdec5655 100644 --- a/apps/api/src/app/auth/auth.module.ts +++ b/apps/api/src/app/auth/auth.module.ts @@ -4,6 +4,7 @@ import { SubscriptionModule } from '@ghostfolio/api/app/subscription/subscriptio import { UserModule } from '@ghostfolio/api/app/user/user.module'; import { ConfigurationModule } from '@ghostfolio/api/services/configuration.module'; import { PrismaModule } from '@ghostfolio/api/services/prisma.module'; +import { PropertyModule } from '@ghostfolio/api/services/property/property.module'; import { Module } from '@nestjs/common'; import { JwtModule } from '@nestjs/jwt'; @@ -21,6 +22,7 @@ import { JwtStrategy } from './jwt.strategy'; signOptions: { expiresIn: '180 days' } }), PrismaModule, + PropertyModule, SubscriptionModule, UserModule ], diff --git a/apps/api/src/app/auth/auth.service.ts b/apps/api/src/app/auth/auth.service.ts index 3178ce9ac..0be9f2877 100644 --- a/apps/api/src/app/auth/auth.service.ts +++ b/apps/api/src/app/auth/auth.service.ts @@ -1,5 +1,6 @@ import { UserService } from '@ghostfolio/api/app/user/user.service'; import { ConfigurationService } from '@ghostfolio/api/services/configuration.service'; +import { PropertyService } from '@ghostfolio/api/services/property/property.service'; import { Injectable, InternalServerErrorException } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import { Provider } from '@prisma/client'; @@ -11,6 +12,7 @@ export class AuthService { public constructor( private readonly configurationService: ConfigurationService, private readonly jwtService: JwtService, + private readonly propertyService: PropertyService, private readonly userService: UserService ) {} @@ -50,6 +52,13 @@ export class AuthService { }); if (!user) { + const isUserSignupEnabled = + await this.propertyService.isUserSignupEnabled(); + + if (!isUserSignupEnabled) { + throw new Error('Sign up forbidden'); + } + // Create new user if not found user = await this.userService.createUser({ provider, @@ -78,6 +87,13 @@ export class AuthService { }); if (!user) { + const isUserSignupEnabled = + await this.propertyService.isUserSignupEnabled(); + + if (!isUserSignupEnabled) { + throw new Error('Sign up forbidden'); + } + // Create new user if not found user = await this.userService.createUser({ provider, diff --git a/apps/api/src/app/benchmark/benchmark.controller.ts b/apps/api/src/app/benchmark/benchmark.controller.ts index b5562bf86..4daa14009 100644 --- a/apps/api/src/app/benchmark/benchmark.controller.ts +++ b/apps/api/src/app/benchmark/benchmark.controller.ts @@ -30,8 +30,8 @@ export class BenchmarkController { } @Get(':dataSource/:symbol/:startDateString') - @UseInterceptors(TransformDataSourceInRequestInterceptor) @UseGuards(AuthGuard('jwt')) + @UseInterceptors(TransformDataSourceInRequestInterceptor) public async getBenchmarkMarketDataBySymbol( @Param('dataSource') dataSource: DataSource, @Param('startDateString') startDateString: string, diff --git a/apps/api/src/app/frontend.middleware.ts b/apps/api/src/app/frontend.middleware.ts index dde9a0b32..41238fdec 100644 --- a/apps/api/src/app/frontend.middleware.ts +++ b/apps/api/src/app/frontend.middleware.ts @@ -50,66 +50,66 @@ export class FrontendMiddleware implements NestMiddleware { } catch {} } - public use(req: Request, res: Response, next: NextFunction) { + public use(request: Request, response: Response, next: NextFunction) { let featureGraphicPath = 'assets/cover.png'; - if (req.path.startsWith('/en/blog/2022/08/500-stars-on-github')) { + if (request.path.startsWith('/en/blog/2022/08/500-stars-on-github')) { featureGraphicPath = 'assets/images/blog/500-stars-on-github.jpg'; - } else if (req.path.startsWith('/en/blog/2022/10/hacktoberfest-2022')) { + } else if (request.path.startsWith('/en/blog/2022/10/hacktoberfest-2022')) { featureGraphicPath = 'assets/images/blog/hacktoberfest-2022.png'; - } else if (req.path.startsWith('/en/blog/2022/11/black-friday-2022')) { + } else if (request.path.startsWith('/en/blog/2022/11/black-friday-2022')) { featureGraphicPath = 'assets/images/blog/black-friday-2022.jpg'; } if ( - req.path.startsWith('/api/') || - this.isFileRequest(req.url) || + request.path.startsWith('/api/') || + this.isFileRequest(request.url) || !this.isProduction ) { // Skip next(); - } else if (req.path === '/de' || req.path.startsWith('/de/')) { - res.send( + } else if (request.path === '/de' || request.path.startsWith('/de/')) { + response.send( this.interpolate(this.indexHtmlDe, { featureGraphicPath, languageCode: 'de', - path: req.path, + path: request.path, rootUrl: this.configurationService.get('ROOT_URL') }) ); - } else if (req.path === '/es' || req.path.startsWith('/es/')) { - res.send( + } else if (request.path === '/es' || request.path.startsWith('/es/')) { + response.send( this.interpolate(this.indexHtmlEs, { featureGraphicPath, languageCode: 'es', - path: req.path, + path: request.path, rootUrl: this.configurationService.get('ROOT_URL') }) ); - } else if (req.path === '/it' || req.path.startsWith('/it/')) { - res.send( + } else if (request.path === '/it' || request.path.startsWith('/it/')) { + response.send( this.interpolate(this.indexHtmlIt, { featureGraphicPath, languageCode: 'it', - path: req.path, + path: request.path, rootUrl: this.configurationService.get('ROOT_URL') }) ); - } else if (req.path === '/nl' || req.path.startsWith('/nl/')) { - res.send( + } else if (request.path === '/nl' || request.path.startsWith('/nl/')) { + response.send( this.interpolate(this.indexHtmlNl, { featureGraphicPath, languageCode: 'nl', - path: req.path, + path: request.path, rootUrl: this.configurationService.get('ROOT_URL') }) ); } else { - res.send( + response.send( this.interpolate(this.indexHtmlEn, { featureGraphicPath, languageCode: DEFAULT_LANGUAGE_CODE, - path: req.path, + path: request.path, rootUrl: this.configurationService.get('ROOT_URL') }) ); diff --git a/apps/api/src/app/import/import.controller.ts b/apps/api/src/app/import/import.controller.ts index 422e1cb9f..4976e9511 100644 --- a/apps/api/src/app/import/import.controller.ts +++ b/apps/api/src/app/import/import.controller.ts @@ -1,4 +1,5 @@ import { ConfigurationService } from '@ghostfolio/api/services/configuration.service'; +import { ImportResponse } from '@ghostfolio/common/interfaces'; import type { RequestWithUser } from '@ghostfolio/common/types'; import { Body, @@ -7,6 +8,7 @@ import { Inject, Logger, Post, + Query, UseGuards } from '@nestjs/common'; import { REQUEST } from '@nestjs/core'; @@ -26,7 +28,10 @@ export class ImportController { @Post() @UseGuards(AuthGuard('jwt')) - public async import(@Body() importData: ImportDataDto): Promise { + public async import( + @Body() importData: ImportDataDto, + @Query('dryRun') isDryRun?: boolean + ): Promise { if (!this.configurationService.get('ENABLE_FEATURE_IMPORT')) { throw new HttpException( getReasonPhrase(StatusCodes.FORBIDDEN), @@ -45,12 +50,18 @@ export class ImportController { maxActivitiesToImport = Number.MAX_SAFE_INTEGER; } + const userCurrency = this.request.user.Settings.settings.baseCurrency; + try { - return await this.importService.import({ + const activities = await this.importService.import({ maxActivitiesToImport, - activities: importData.activities, + isDryRun, + userCurrency, + activitiesDto: importData.activities, userId: this.request.user.id }); + + return { activities }; } catch (error) { Logger.error(error, ImportController); diff --git a/apps/api/src/app/import/import.module.ts b/apps/api/src/app/import/import.module.ts index 62d227bf5..64b3a79f3 100644 --- a/apps/api/src/app/import/import.module.ts +++ b/apps/api/src/app/import/import.module.ts @@ -5,6 +5,7 @@ import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.mo import { ConfigurationModule } from '@ghostfolio/api/services/configuration.module'; import { DataGatheringModule } from '@ghostfolio/api/services/data-gathering.module'; import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module'; +import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data.module'; import { PrismaModule } from '@ghostfolio/api/services/prisma.module'; import { Module } from '@nestjs/common'; @@ -19,6 +20,7 @@ import { ImportService } from './import.service'; ConfigurationModule, DataGatheringModule, DataProviderModule, + ExchangeRateDataModule, OrderModule, PrismaModule, RedisCacheModule diff --git a/apps/api/src/app/import/import.service.ts b/apps/api/src/app/import/import.service.ts index 7617b8cb3..ea6eea9ba 100644 --- a/apps/api/src/app/import/import.service.ts +++ b/apps/api/src/app/import/import.service.ts @@ -1,30 +1,38 @@ import { AccountService } from '@ghostfolio/api/app/account/account.service'; import { CreateOrderDto } from '@ghostfolio/api/app/order/create-order.dto'; +import { Activity } from '@ghostfolio/api/app/order/interfaces/activities.interface'; import { OrderService } from '@ghostfolio/api/app/order/order.service'; -import { ConfigurationService } from '@ghostfolio/api/services/configuration.service'; import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service'; +import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service'; +import { OrderWithAccount } from '@ghostfolio/common/types'; import { Injectable } from '@nestjs/common'; -import { isSameDay, parseISO } from 'date-fns'; +import Big from 'big.js'; +import { endOfToday, isAfter, isSameDay, parseISO } from 'date-fns'; +import { v4 as uuidv4 } from 'uuid'; @Injectable() export class ImportService { public constructor( private readonly accountService: AccountService, - private readonly configurationService: ConfigurationService, private readonly dataProviderService: DataProviderService, + private readonly exchangeRateDataService: ExchangeRateDataService, private readonly orderService: OrderService ) {} public async import({ - activities, + activitiesDto, + isDryRun = false, maxActivitiesToImport, + userCurrency, userId }: { - activities: Partial[]; + activitiesDto: Partial[]; + isDryRun?: boolean; maxActivitiesToImport: number; + userCurrency: string; userId: string; - }): Promise { - for (const activity of activities) { + }): Promise { + for (const activity of activitiesDto) { if (!activity.dataSource) { if (activity.type === 'ITEM') { activity.dataSource = 'MANUAL'; @@ -35,7 +43,7 @@ export class ImportService { } await this.validateActivities({ - activities, + activitiesDto, maxActivitiesToImport, userId }); @@ -46,57 +54,121 @@ export class ImportService { } ); + const activities: Activity[] = []; + for (const { accountId, comment, currency, dataSource, - date, + date: dateString, fee, quantity, symbol, type, unitPrice - } of activities) { - await this.orderService.createOrder({ - comment, - fee, - quantity, - type, - unitPrice, - userId, - accountId: accountIds.includes(accountId) ? accountId : undefined, - date: parseISO((date)), - SymbolProfile: { - connectOrCreate: { - create: { - currency, - dataSource, - symbol - }, - where: { - dataSource_symbol: { + } of activitiesDto) { + const date = parseISO((dateString)); + const validatedAccountId = accountIds.includes(accountId) + ? accountId + : undefined; + + let order: OrderWithAccount; + + if (isDryRun) { + order = { + comment, + date, + fee, + quantity, + type, + unitPrice, + userId, + accountId: validatedAccountId, + accountUserId: undefined, + createdAt: new Date(), + id: uuidv4(), + isDraft: isAfter(date, endOfToday()), + SymbolProfile: { + currency, + dataSource, + symbol, + assetClass: null, + assetSubClass: null, + comment: null, + countries: null, + createdAt: undefined, + id: undefined, + name: null, + scraperConfiguration: null, + sectors: null, + symbolMapping: null, + updatedAt: undefined, + url: null + }, + symbolProfileId: undefined, + updatedAt: new Date() + }; + } else { + order = await this.orderService.createOrder({ + comment, + date, + fee, + quantity, + type, + unitPrice, + userId, + accountId: validatedAccountId, + SymbolProfile: { + connectOrCreate: { + create: { + currency, dataSource, symbol + }, + where: { + dataSource_symbol: { + dataSource, + symbol + } } } - } - }, - User: { connect: { id: userId } } + }, + User: { connect: { id: userId } } + }); + } + + const value = new Big(quantity).mul(unitPrice).toNumber(); + + activities.push({ + ...order, + value, + feeInBaseCurrency: this.exchangeRateDataService.toCurrency( + fee, + currency, + userCurrency + ), + valueInBaseCurrency: this.exchangeRateDataService.toCurrency( + value, + currency, + userCurrency + ) }); } + + return activities; } private async validateActivities({ - activities, + activitiesDto, maxActivitiesToImport, userId }: { - activities: Partial[]; + activitiesDto: Partial[]; maxActivitiesToImport: number; userId: string; }) { - if (activities?.length > maxActivitiesToImport) { + if (activitiesDto?.length > maxActivitiesToImport) { throw new Error(`Too many activities (${maxActivitiesToImport} at most)`); } @@ -109,7 +181,7 @@ export class ImportService { for (const [ index, { currency, dataSource, date, fee, quantity, symbol, type, unitPrice } - ] of activities.entries()) { + ] of activitiesDto.entries()) { const duplicateActivity = existingActivities.find((activity) => { return ( activity.SymbolProfile.currency === currency && diff --git a/apps/api/src/app/info/info.service.ts b/apps/api/src/app/info/info.service.ts index 8ed589cb5..f9eab7018 100644 --- a/apps/api/src/app/info/info.service.ts +++ b/apps/api/src/app/info/info.service.ts @@ -8,6 +8,7 @@ import { TagService } from '@ghostfolio/api/services/tag/tag.service'; import { DEMO_USER_ID, PROPERTY_IS_READ_ONLY_MODE, + PROPERTY_IS_USER_SIGNUP_ENABLED, PROPERTY_SLACK_COMMUNITY_USERS, PROPERTY_STRIPE_CONFIG, PROPERTY_SYSTEM_MESSAGE, @@ -103,6 +104,13 @@ export class InfoService { )) as string; } + const isUserSignupEnabled = + await this.propertyService.isUserSignupEnabled(); + + if (isUserSignupEnabled) { + globalPermissions.push(permissions.createUserAccount); + } + return { ...info, globalPermissions, diff --git a/apps/api/src/app/logo/logo.controller.ts b/apps/api/src/app/logo/logo.controller.ts new file mode 100644 index 000000000..22bafc061 --- /dev/null +++ b/apps/api/src/app/logo/logo.controller.ts @@ -0,0 +1,54 @@ +import { TransformDataSourceInRequestInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-request.interceptor'; +import { + Controller, + Get, + HttpStatus, + Param, + Query, + Res, + UseInterceptors +} from '@nestjs/common'; +import { DataSource } from '@prisma/client'; +import { Response } from 'express'; + +import { LogoService } from './logo.service'; + +@Controller('logo') +export class LogoController { + public constructor(private readonly logoService: LogoService) {} + + @Get(':dataSource/:symbol') + @UseInterceptors(TransformDataSourceInRequestInterceptor) + public async getLogoByDataSourceAndSymbol( + @Param('dataSource') dataSource: DataSource, + @Param('symbol') symbol: string, + @Res() response: Response + ) { + try { + const buffer = await this.logoService.getLogoByDataSourceAndSymbol({ + dataSource, + symbol + }); + + response.contentType('image/png'); + response.send(buffer); + } catch { + response.status(HttpStatus.NOT_FOUND).send(); + } + } + + @Get() + public async getLogoByUrl( + @Query('url') url: string, + @Res() response: Response + ) { + try { + const buffer = await this.logoService.getLogoByUrl(url); + + response.contentType('image/png'); + response.send(buffer); + } catch { + response.status(HttpStatus.NOT_FOUND).send(); + } + } +} diff --git a/apps/api/src/app/logo/logo.module.ts b/apps/api/src/app/logo/logo.module.ts new file mode 100644 index 000000000..518010f39 --- /dev/null +++ b/apps/api/src/app/logo/logo.module.ts @@ -0,0 +1,13 @@ +import { ConfigurationModule } from '@ghostfolio/api/services/configuration.module'; +import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile.module'; +import { Module } from '@nestjs/common'; + +import { LogoController } from './logo.controller'; +import { LogoService } from './logo.service'; + +@Module({ + controllers: [LogoController], + imports: [ConfigurationModule, SymbolProfileModule], + providers: [LogoService] +}) +export class LogoModule {} diff --git a/apps/api/src/app/logo/logo.service.ts b/apps/api/src/app/logo/logo.service.ts new file mode 100644 index 000000000..3bea44ca9 --- /dev/null +++ b/apps/api/src/app/logo/logo.service.ts @@ -0,0 +1,55 @@ +import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile.service'; +import { UniqueAsset } from '@ghostfolio/common/interfaces'; +import { HttpException, Injectable } from '@nestjs/common'; +import { DataSource } from '@prisma/client'; +import * as bent from 'bent'; +import { StatusCodes, getReasonPhrase } from 'http-status-codes'; + +@Injectable() +export class LogoService { + public constructor( + private readonly symbolProfileService: SymbolProfileService + ) {} + + public async getLogoByDataSourceAndSymbol({ + dataSource, + symbol + }: UniqueAsset) { + if (!DataSource[dataSource]) { + throw new HttpException( + getReasonPhrase(StatusCodes.NOT_FOUND), + StatusCodes.NOT_FOUND + ); + } + + const [assetProfile] = await this.symbolProfileService.getSymbolProfiles([ + { dataSource, symbol } + ]); + + if (!assetProfile) { + throw new HttpException( + getReasonPhrase(StatusCodes.NOT_FOUND), + StatusCodes.NOT_FOUND + ); + } + + return this.getBuffer(assetProfile.url); + } + + public async getLogoByUrl(aUrl: string) { + return this.getBuffer(aUrl); + } + + private getBuffer(aUrl: string) { + const get = bent( + `https://t0.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=${aUrl}&size=64`, + 'GET', + 'buffer', + 200, + { + 'User-Agent': 'request' + } + ); + return get(); + } +} diff --git a/apps/api/src/app/order/interfaces/activities.interface.ts b/apps/api/src/app/order/interfaces/activities.interface.ts index e14adce0b..31b345b46 100644 --- a/apps/api/src/app/order/interfaces/activities.interface.ts +++ b/apps/api/src/app/order/interfaces/activities.interface.ts @@ -6,5 +6,6 @@ export interface Activities { export interface Activity extends OrderWithAccount { feeInBaseCurrency: number; + value: number; valueInBaseCurrency: number; } diff --git a/apps/api/src/app/order/order.controller.ts b/apps/api/src/app/order/order.controller.ts index 5f9e1522d..5a46f0866 100644 --- a/apps/api/src/app/order/order.controller.ts +++ b/apps/api/src/app/order/order.controller.ts @@ -1,5 +1,3 @@ -import { UserService } from '@ghostfolio/api/app/user/user.service'; -import { nullifyValuesInObjects } from '@ghostfolio/api/helper/object.helper'; import { RedactValuesInResponseInterceptor } from '@ghostfolio/api/interceptors/redact-values-in-response.interceptor'; import { TransformDataSourceInRequestInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-request.interceptor'; import { TransformDataSourceInResponseInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-response.interceptor'; @@ -39,8 +37,7 @@ export class OrderController { private readonly apiService: ApiService, private readonly impersonationService: ImpersonationService, private readonly orderService: OrderService, - @Inject(REQUEST) private readonly request: RequestWithUser, - private readonly userService: UserService + @Inject(REQUEST) private readonly request: RequestWithUser ) {} @Delete(':id') @@ -87,7 +84,7 @@ export class OrderController { ); const userCurrency = this.request.user.Settings.settings.baseCurrency; - let activities = await this.orderService.getOrders({ + const activities = await this.orderService.getOrders({ filters, userCurrency, includeDrafts: true, @@ -95,20 +92,6 @@ export class OrderController { withExcludedAccounts: true }); - if ( - impersonationUserId || - this.userService.isRestrictedView(this.request.user) - ) { - activities = nullifyValuesInObjects(activities, [ - 'fee', - 'feeInBaseCurrency', - 'quantity', - 'unitPrice', - 'value', - 'valueInBaseCurrency' - ]); - } - return { activities }; } diff --git a/apps/api/src/app/portfolio/portfolio.controller.ts b/apps/api/src/app/portfolio/portfolio.controller.ts index 7ce976185..49ba3c845 100644 --- a/apps/api/src/app/portfolio/portfolio.controller.ts +++ b/apps/api/src/app/portfolio/portfolio.controller.ts @@ -12,6 +12,7 @@ import { ConfigurationService } from '@ghostfolio/api/services/configuration.ser import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service'; import { PortfolioDetails, + PortfolioDividends, PortfolioInvestments, PortfolioPerformanceResponse, PortfolioPublicDetails, @@ -185,6 +186,55 @@ export class PortfolioController { }; } + @Get('dividends') + @UseGuards(AuthGuard('jwt')) + public async getDividends( + @Headers('impersonation-id') impersonationId: string, + @Query('range') dateRange: DateRange = 'max', + @Query('groupBy') groupBy?: GroupBy + ): Promise { + let dividends: InvestmentItem[]; + + if (groupBy === 'month') { + dividends = await this.portfolioService.getDividends({ + dateRange, + groupBy, + impersonationId + }); + } else { + dividends = await this.portfolioService.getDividends({ + dateRange, + impersonationId + }); + } + + if ( + impersonationId || + this.userService.isRestrictedView(this.request.user) + ) { + const maxDividend = dividends.reduce( + (investment, item) => Math.max(investment, item.investment), + 1 + ); + + dividends = dividends.map((item) => ({ + date: item.date, + investment: item.investment / maxDividend + })); + } + + if ( + this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') && + this.request.user.subscription.type === 'Basic' + ) { + dividends = dividends.map((item) => { + return nullifyValuesInObject(item, ['investment']); + }); + } + + return { dividends }; + } + @Get('investments') @UseGuards(AuthGuard('jwt')) public async getInvestments( @@ -197,8 +247,8 @@ export class PortfolioController { if (groupBy === 'month') { investments = await this.portfolioService.getInvestments({ dateRange, - impersonationId, - groupBy: 'month' + groupBy, + impersonationId }); } else { investments = await this.portfolioService.getInvestments({ @@ -323,6 +373,7 @@ export class PortfolioController { } @Get('public/:accessId') + @UseInterceptors(TransformDataSourceInResponseInterceptor) public async getPublic( @Param('accessId') accessId ): Promise { @@ -372,6 +423,8 @@ export class PortfolioController { allocationCurrent: portfolioPosition.value / totalValue, countries: hasDetails ? portfolioPosition.countries : [], currency: hasDetails ? portfolioPosition.currency : undefined, + dataSource: portfolioPosition.dataSource, + dateOfFirstActivity: portfolioPosition.dateOfFirstActivity, markets: hasDetails ? portfolioPosition.markets : undefined, name: portfolioPosition.name, netPerformancePercent: portfolioPosition.netPerformancePercent, diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index 125002b36..a8c26afa4 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -67,6 +67,8 @@ import { format, isAfter, isBefore, + isSameMonth, + isSameYear, max, parseISO, set, @@ -206,6 +208,44 @@ export class PortfolioService { }; } + public async getDividends({ + dateRange, + impersonationId, + groupBy + }: { + dateRange: DateRange; + impersonationId: string; + groupBy?: GroupBy; + }): Promise { + const userId = await this.getUserId(impersonationId, this.request.user.id); + + const activities = await this.orderService.getOrders({ + userId, + types: ['DIVIDEND'], + userCurrency: this.request.user.Settings.settings.baseCurrency + }); + + let dividends = activities.map((dividend) => { + return { + date: format(dividend.date, DATE_FORMAT), + investment: dividend.valueInBaseCurrency + }; + }); + + if (groupBy === 'month') { + dividends = this.getDividendsByMonth(dividends); + } + + const startDate = this.getStartDate( + dateRange, + parseDate(dividends[0]?.date) + ); + + return dividends.filter(({ date }) => { + return !isBefore(parseDate(date), startDate); + }); + } + public async getInvestments({ dateRange, impersonationId, @@ -493,6 +533,7 @@ export class PortfolioService { countries: symbolProfile.countries, currency: item.currency, dataSource: symbolProfile.dataSource, + dateOfFirstActivity: parseDate(item.firstBuyDate), grossPerformance: item.grossPerformance?.toNumber() ?? 0, grossPerformancePercent: item.grossPerformancePercentage?.toNumber() ?? 0, @@ -1204,6 +1245,49 @@ export class PortfolioService { ); } + private getDividendsByMonth(aDividends: InvestmentItem[]): InvestmentItem[] { + if (aDividends.length === 0) { + return []; + } + + const dividends = []; + let currentDate: Date; + let investmentByMonth = new Big(0); + + for (const [index, dividend] of aDividends.entries()) { + if ( + isSameMonth(parseDate(dividend.date), currentDate) && + isSameYear(parseDate(dividend.date), currentDate) + ) { + // Same month: Add up divididends + + investmentByMonth = investmentByMonth.plus(dividend.investment); + } else { + // New month: Store previous month and reset + + if (currentDate) { + dividends.push({ + date: format(set(currentDate, { date: 1 }), DATE_FORMAT), + investment: investmentByMonth + }); + } + + currentDate = parseDate(dividend.date); + investmentByMonth = new Big(dividend.investment); + } + + if (index === aDividends.length - 1) { + // Store current month (latest order) + dividends.push({ + date: format(set(currentDate, { date: 1 }), DATE_FORMAT), + investment: investmentByMonth + }); + } + } + + return dividends; + } + private getFees({ date = new Date(0), orders, @@ -1246,6 +1330,7 @@ export class PortfolioService { assetSubClass: AssetClass.CASH, countries: [], dataSource: undefined, + dateOfFirstActivity: undefined, grossPerformance: 0, grossPerformancePercent: 0, investment: balance, diff --git a/apps/api/src/app/subscription/subscription.controller.ts b/apps/api/src/app/subscription/subscription.controller.ts index 70317fe76..eee815652 100644 --- a/apps/api/src/app/subscription/subscription.controller.ts +++ b/apps/api/src/app/subscription/subscription.controller.ts @@ -21,6 +21,7 @@ import { } from '@nestjs/common'; import { REQUEST } from '@nestjs/core'; import { AuthGuard } from '@nestjs/passport'; +import { Request, Response } from 'express'; import { StatusCodes, getReasonPhrase } from 'http-status-codes'; import { SubscriptionService } from './subscription.service'; @@ -86,9 +87,12 @@ export class SubscriptionController { } @Get('stripe/callback') - public async stripeCallback(@Req() req, @Res() res) { + public async stripeCallback( + @Req() request: Request, + @Res() response: Response + ) { const userId = await this.subscriptionService.createSubscriptionViaStripe( - req.query.checkoutSessionId + request.query.checkoutSessionId ); Logger.log( @@ -96,7 +100,7 @@ export class SubscriptionController { 'SubscriptionController' ); - res.redirect( + response.redirect( `${this.configurationService.get( 'ROOT_URL' )}/${DEFAULT_LANGUAGE_CODE}/account` diff --git a/apps/api/src/app/user/user.controller.ts b/apps/api/src/app/user/user.controller.ts index 2b1f063bf..de79eaee9 100644 --- a/apps/api/src/app/user/user.controller.ts +++ b/apps/api/src/app/user/user.controller.ts @@ -1,6 +1,6 @@ import { ConfigurationService } from '@ghostfolio/api/services/configuration.service'; import { PropertyService } from '@ghostfolio/api/services/property/property.service'; -import { PROPERTY_IS_READ_ONLY_MODE } from '@ghostfolio/common/config'; +import { PROPERTY_IS_USER_SIGNUP_ENABLED } from '@ghostfolio/common/config'; import { User, UserSettings } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import type { RequestWithUser } from '@ghostfolio/common/types'; @@ -69,17 +69,14 @@ export class UserController { @Post() public async signupUser(): Promise { - if (this.configurationService.get('ENABLE_FEATURE_READ_ONLY_MODE')) { - const isReadOnlyMode = (await this.propertyService.getByKey( - PROPERTY_IS_READ_ONLY_MODE - )) as boolean; + const isUserSignupEnabled = + await this.propertyService.isUserSignupEnabled(); - if (isReadOnlyMode) { - throw new HttpException( - getReasonPhrase(StatusCodes.FORBIDDEN), - StatusCodes.FORBIDDEN - ); - } + if (!isUserSignupEnabled) { + throw new HttpException( + getReasonPhrase(StatusCodes.FORBIDDEN), + StatusCodes.FORBIDDEN + ); } const hasAdmin = await this.userService.hasAdmin(); diff --git a/apps/api/src/interceptors/redact-values-in-response.interceptor.ts b/apps/api/src/interceptors/redact-values-in-response.interceptor.ts index 4a9c5bef2..fa1b7f7f7 100644 --- a/apps/api/src/interceptors/redact-values-in-response.interceptor.ts +++ b/apps/api/src/interceptors/redact-values-in-response.interceptor.ts @@ -1,4 +1,5 @@ import { Activity } from '@ghostfolio/api/app/order/interfaces/activities.interface'; +import { UserService } from '@ghostfolio/api/app/user/user.service'; import { CallHandler, ExecutionContext, @@ -12,7 +13,7 @@ import { map } from 'rxjs/operators'; export class RedactValuesInResponseInterceptor implements NestInterceptor { - public constructor() {} + public constructor(private userService: UserService) {} public intercept( context: ExecutionContext, @@ -23,7 +24,10 @@ export class RedactValuesInResponseInterceptor const request = context.switchToHttp().getRequest(); const hasImpersonationId = !!request.headers?.['impersonation-id']; - if (hasImpersonationId) { + if ( + hasImpersonationId || + this.userService.isRestrictedView(request.user) + ) { if (data.accounts) { for (const accountId of Object.keys(data.accounts)) { if (data.accounts[accountId]?.balance !== undefined) { @@ -38,6 +42,34 @@ export class RedactValuesInResponseInterceptor activity.Account.balance = null; } + if (activity.comment !== undefined) { + activity.comment = null; + } + + if (activity.fee !== undefined) { + activity.fee = null; + } + + if (activity.feeInBaseCurrency !== undefined) { + activity.feeInBaseCurrency = null; + } + + if (activity.quantity !== undefined) { + activity.quantity = null; + } + + if (activity.unitPrice !== undefined) { + activity.unitPrice = null; + } + + if (activity.value !== undefined) { + activity.value = null; + } + + if (activity.valueInBaseCurrency !== undefined) { + activity.valueInBaseCurrency = null; + } + return activity; }); } diff --git a/apps/api/src/services/data-provider/rapid-api/rapid-api.service.ts b/apps/api/src/services/data-provider/rapid-api/rapid-api.service.ts index 5aace3d24..1bf057745 100644 --- a/apps/api/src/services/data-provider/rapid-api/rapid-api.service.ts +++ b/apps/api/src/services/data-provider/rapid-api/rapid-api.service.ts @@ -5,20 +5,18 @@ import { IDataProviderHistoricalResponse, IDataProviderResponse } from '@ghostfolio/api/services/interfaces/interfaces'; -import { PrismaService } from '@ghostfolio/api/services/prisma.service'; import { ghostfolioFearAndGreedIndexSymbol } from '@ghostfolio/common/config'; -import { DATE_FORMAT, getToday, getYesterday } from '@ghostfolio/common/helper'; +import { DATE_FORMAT, getYesterday } from '@ghostfolio/common/helper'; import { Granularity } from '@ghostfolio/common/types'; import { Injectable, Logger } from '@nestjs/common'; import { DataSource, SymbolProfile } from '@prisma/client'; import bent from 'bent'; -import { format, subMonths, subWeeks, subYears } from 'date-fns'; +import { format } from 'date-fns'; @Injectable() export class RapidApiService implements DataProviderInterface { public constructor( - private readonly configurationService: ConfigurationService, - private readonly prismaService: PrismaService + private readonly configurationService: ConfigurationService ) {} public canHandle(symbol: string) { @@ -47,41 +45,6 @@ export class RapidApiService implements DataProviderInterface { if (symbol === ghostfolioFearAndGreedIndexSymbol) { const fgi = await this.getFearAndGreedIndex(); - try { - // Rebuild historical data - // TODO: can be removed after all data from the last year has been gathered - // (introduced on 27.03.2021) - - await this.prismaService.marketData.create({ - data: { - symbol, - dataSource: this.getName(), - date: subWeeks(getToday(), 1), - marketPrice: fgi.oneWeekAgo.value - } - }); - - await this.prismaService.marketData.create({ - data: { - symbol, - dataSource: this.getName(), - date: subMonths(getToday(), 1), - marketPrice: fgi.oneMonthAgo.value - } - }); - - await this.prismaService.marketData.create({ - data: { - symbol, - dataSource: this.getName(), - date: subYears(getToday(), 1), - marketPrice: fgi.oneYearAgo.value - } - }); - - /////////////////////////////////////////////////////////////////////////// - } catch {} - return { [ghostfolioFearAndGreedIndexSymbol]: { [format(getYesterday(), DATE_FORMAT)]: { diff --git a/apps/api/src/services/property/property.service.ts b/apps/api/src/services/property/property.service.ts index 4760c3a94..69e7ff46b 100644 --- a/apps/api/src/services/property/property.service.ts +++ b/apps/api/src/services/property/property.service.ts @@ -1,5 +1,8 @@ import { PrismaService } from '@ghostfolio/api/services/prisma.service'; -import { PROPERTY_CURRENCIES } from '@ghostfolio/common/config'; +import { + PROPERTY_CURRENCIES, + PROPERTY_IS_USER_SIGNUP_ENABLED +} from '@ghostfolio/common/config'; import { Injectable } from '@nestjs/common'; @Injectable() @@ -39,6 +42,13 @@ export class PropertyService { return properties?.[aKey]; } + public async isUserSignupEnabled() { + return ( + ((await this.getByKey(PROPERTY_IS_USER_SIGNUP_ENABLED)) as boolean) ?? + true + ); + } + public async put({ key, value }: { key: string; value: string }) { return this.prismaService.property.upsert({ create: { key, value }, diff --git a/apps/api/src/services/symbol-profile.service.ts b/apps/api/src/services/symbol-profile.service.ts index 6cbbd8a4e..75c386bd0 100644 --- a/apps/api/src/services/symbol-profile.service.ts +++ b/apps/api/src/services/symbol-profile.service.ts @@ -36,6 +36,13 @@ export class SymbolProfileService { _count: { select: { Order: true } }, + Order: { + orderBy: { + date: 'asc' + }, + select: { date: true }, + take: 1 + }, SymbolProfileOverrides: true }, where: { @@ -118,6 +125,9 @@ export class SymbolProfileService { private getSymbols( symbolProfiles: (SymbolProfile & { _count: { Order: number }; + Order?: { + date: Date; + }[]; SymbolProfileOverrides: SymbolProfileOverrides; })[] ): EnhancedSymbolProfile[] { @@ -128,6 +138,7 @@ export class SymbolProfileService { countries: this.getCountries( symbolProfile?.countries as unknown as Prisma.JsonArray ), + dateOfFirstActivity: undefined, scraperConfiguration: this.getScraperConfiguration(symbolProfile), sectors: this.getSectors(symbolProfile), symbolMapping: this.getSymbolMapping(symbolProfile) @@ -136,6 +147,9 @@ export class SymbolProfileService { item.activitiesCount = symbolProfile._count.Order; delete item._count; + item.dateOfFirstActivity = symbolProfile.Order?.[0]?.date; + delete item.Order; + if (item.SymbolProfileOverrides) { item.assetClass = item.SymbolProfileOverrides.assetClass ?? item.assetClass; diff --git a/apps/client/src/app/components/accounts-table/accounts-table.component.html b/apps/client/src/app/components/accounts-table/accounts-table.component.html index 7c12c735e..377989431 100644 --- a/apps/client/src/app/components/accounts-table/accounts-table.component.html +++ b/apps/client/src/app/components/accounts-table/accounts-table.component.html @@ -18,14 +18,8 @@ - - Name + + Name {}); } - public onOpenAssetProfileDialog({ - dataSource, - dateOfFirstActivity, - symbol - }: UniqueAsset & { dateOfFirstActivity: string }) { - try { - dateOfFirstActivity = format(parseISO(dateOfFirstActivity), DATE_FORMAT); - } catch {} - + public onOpenAssetProfileDialog({ dataSource, symbol }: UniqueAsset) { this.router.navigate([], { queryParams: { - dateOfFirstActivity, dataSource, symbol, assetProfileDialog: true @@ -221,11 +210,9 @@ export class AdminMarketDataComponent implements OnDestroy, OnInit { private openAssetProfileDialog({ dataSource, - dateOfFirstActivity, symbol }: { dataSource: DataSource; - dateOfFirstActivity: string; symbol: string; }) { this.userService @@ -238,7 +225,6 @@ export class AdminMarketDataComponent implements OnDestroy, OnInit { autoFocus: false, data: { dataSource, - dateOfFirstActivity, symbol, deviceType: this.deviceType, locale: this.user?.settings?.locale diff --git a/apps/client/src/app/components/admin-market-data/admin-market-data.html b/apps/client/src/app/components/admin-market-data/admin-market-data.html index cea4bd684..0471ddfc5 100644 --- a/apps/client/src/app/components/admin-market-data/admin-market-data.html +++ b/apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -176,7 +176,7 @@ *matRowDef="let row; columns: displayedColumns" class="cursor-pointer" mat-row - (click)="onOpenAssetProfileDialog({ dateOfFirstActivity: row.date, dataSource: row.dataSource, symbol: row.symbol })" + (click)="onOpenAssetProfileDialog({ dataSource: row.dataSource, symbol: row.symbol })" >
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 3d7a539b3..9c126862f 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 @@ -87,8 +87,8 @@ export class AssetProfileDialog implements OnDestroy, OnInit { } this.assetProfileForm.setValue({ - comment: this.assetProfile?.comment, - symbolMapping: JSON.stringify(this.assetProfile?.symbolMapping) + comment: this.assetProfile?.comment ?? '', + symbolMapping: JSON.stringify(this.assetProfile?.symbolMapping ?? {}) }); this.assetProfileForm.markAsPristine(); 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 e4ada64d6..7cd4f4d07 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 @@ -44,7 +44,7 @@ First Buy DateFirst Activity
@@ -67,7 +67,7 @@ size="medium" [locale]="data.locale" [value]="assetProfile?.activitiesCount ?? 0" - >TransactionsActivities
diff --git a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/interfaces/interfaces.ts b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/interfaces/interfaces.ts index 05c70f749..c230a39ee 100644 --- a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/interfaces/interfaces.ts +++ b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/interfaces/interfaces.ts @@ -1,7 +1,6 @@ import { DataSource } from '@prisma/client'; export interface AssetProfileDialogParams { - dateOfFirstActivity: string; dataSource: DataSource; deviceType: string; locale: 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 033f78c69..f629b620d 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 @@ -7,6 +7,7 @@ import { PROPERTY_COUPONS, PROPERTY_CURRENCIES, PROPERTY_IS_READ_ONLY_MODE, + PROPERTY_IS_USER_SIGNUP_ENABLED, PROPERTY_SYSTEM_MESSAGE } from '@ghostfolio/common/config'; import { Coupon, InfoItem, User } from '@ghostfolio/common/interfaces'; @@ -35,6 +36,7 @@ export class AdminOverviewComponent implements OnDestroy, OnInit { public hasPermissionForSystemMessage: boolean; public hasPermissionToToggleReadOnlyMode: boolean; public info: InfoItem; + public permissions = permissions; public transactionCount: number; public userCount: number; public user: User; @@ -167,6 +169,13 @@ export class AdminOverviewComponent implements OnDestroy, OnInit { }); } + public onEnableUserSignupModeChange(aEvent: MatSlideToggleChange) { + this.putAdminSetting({ + key: PROPERTY_IS_USER_SIGNUP_ENABLED, + value: aEvent.checked ? undefined : false + }); + } + public onSetSystemMessage() { const systemMessage = prompt($localize`Please set your system message:`); @@ -214,7 +223,7 @@ export class AdminOverviewComponent implements OnDestroy, OnInit { private putAdminSetting({ key, value }: { key: string; value: any }) { this.dataService .putAdminSetting(key, { - value: value ? JSON.stringify(value) : undefined + value: value || value === false ? JSON.stringify(value) : undefined }) .pipe(takeUntil(this.unsubscribeSubject)) .subscribe(() => { diff --git a/apps/client/src/app/components/admin-overview/admin-overview.html b/apps/client/src/app/components/admin-overview/admin-overview.html index c9414201b..44d851a8c 100644 --- a/apps/client/src/app/components/admin-overview/admin-overview.html +++ b/apps/client/src/app/components/admin-overview/admin-overview.html @@ -82,6 +82,26 @@
+
+
User Signup
+
+ +
+
+
+
Read-only Mode
+
+ +
+
System Message
@@ -109,16 +129,6 @@
-
-
Read-only Mode
-
- -
-
{ - return `${value} %`; + return `${value.toFixed(2)} %`; }, display: true, mirror: true, diff --git a/apps/client/src/app/components/header/header.component.html b/apps/client/src/app/components/header/header.component.html index 336bc6d24..ce3b98dff 100644 --- a/apps/client/src/app/components/header/header.component.html +++ b/apps/client/src/app/components/header/header.component.html @@ -1,9 +1,9 @@ @@ -289,7 +289,7 @@ Sign in (); diff --git a/apps/client/src/app/components/investment-chart/investment-chart.component.ts b/apps/client/src/app/components/investment-chart/investment-chart.component.ts index eb51a728c..249b9cdb6 100644 --- a/apps/client/src/app/components/investment-chart/investment-chart.component.ts +++ b/apps/client/src/app/components/investment-chart/investment-chart.component.ts @@ -48,6 +48,7 @@ import { last } from 'lodash'; }) export class InvestmentChartComponent implements OnChanges, OnDestroy { @Input() benchmarkDataItems: InvestmentItem[] = []; + @Input() benchmarkDataLabel = ''; @Input() colorScheme: ColorScheme; @Input() currency: string; @Input() daysInMarket: number; @@ -153,7 +154,7 @@ export class InvestmentChartComponent implements OnChanges, OnDestroy { y: this.isInPercent ? investment * 100 : investment }; }), - label: $localize`Deposit`, + label: this.benchmarkDataLabel, segment: { borderColor: (context: unknown) => this.isInFuture( @@ -194,6 +195,9 @@ export class InvestmentChartComponent implements OnChanges, OnDestroy { this.chart.options.plugins.tooltip = ( this.getTooltipPluginConfiguration() ); + this.chart.options.scales.x.min = this.daysInMarket + ? subDays(new Date(), this.daysInMarket).toISOString() + : undefined; this.chart.update(); } else { this.chart = new Chart(this.chartCanvas.nativeElement, { @@ -257,13 +261,19 @@ export class InvestmentChartComponent implements OnChanges, OnDestroy { responsive: true, scales: { x: { + border: { + color: `rgba(${getTextColor(this.colorScheme)}, 0.1)`, + width: this.groupBy ? 0 : 1 + }, display: true, grid: { - borderColor: `rgba(${getTextColor(this.colorScheme)}, 0.1)`, - borderWidth: this.groupBy ? 0 : 1, color: `rgba(${getTextColor(this.colorScheme)}, 0.8)`, display: false }, + min: this.daysInMarket + ? subDays(new Date(), this.daysInMarket).toISOString() + : undefined, + suggestedMax: new Date().toISOString(), type: 'time', time: { tooltipFormat: getDateFormatString(this.locale), @@ -271,12 +281,14 @@ export class InvestmentChartComponent implements OnChanges, OnDestroy { } }, y: { + border: { + color: `rgba(${getTextColor(this.colorScheme)}, 0.1)`, + display: false + }, display: !this.isInPercent, grid: { - borderColor: `rgba(${getTextColor(this.colorScheme)}, 0.1)`, color: `rgba(${getTextColor(this.colorScheme)}, 0.8)`, - display: false, - drawBorder: false + display: false }, position: 'right', ticks: { diff --git a/apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html b/apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html index 4004f077f..c888ab9be 100644 --- a/apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html +++ b/apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -223,7 +223,7 @@ [hasPermissionToOpenDetails]="false" [locale]="data.locale" [showActions]="false" - [showSymbolColumn]="false" + [showNameColumn]="false" (export)="onExport()" >
diff --git a/apps/client/src/app/components/position/position.component.html b/apps/client/src/app/components/position/position.component.html index cbd12e094..2f6b76bd9 100644 --- a/apps/client/src/app/components/position/position.component.html +++ b/apps/client/src/app/components/position/position.component.html @@ -3,12 +3,12 @@
{{ position?.name }}
- {{ position?.symbol | gfSymbol }} + {{ position?.symbol | gfSymbol }}
- - - - - - - - - - Symbol - - - {{ element.symbol | gfSymbol }} - - - - - - Name - - - {{ - element.name - }} - - - - - - Value - - -
- -
- -
- - - - Allocation - - -
- -
- -
- - - - Performance - - -
- -
- -
- - - - - - - -
- -
- -
- -
- - diff --git a/apps/client/src/app/components/positions-table/positions-table.component.scss b/apps/client/src/app/components/positions-table/positions-table.component.scss deleted file mode 100644 index 72df638e1..000000000 --- a/apps/client/src/app/components/positions-table/positions-table.component.scss +++ /dev/null @@ -1,33 +0,0 @@ -@import '~apps/client/src/styles/ghostfolio-style'; - -:host { - display: block; - - ::ng-deep { - .mat-form-field-infix { - border-top: 0 solid transparent !important; - } - } - - .mat-table { - th { - ::ng-deep { - .mat-sort-header-container { - justify-content: inherit; - } - } - } - - .mat-row { - &.cursor-pointer { - cursor: pointer; - } - } - } -} - -:host-context(.is-dark-theme) { - .mat-form-field { - color: rgba(var(--light-primary-text)); - } -} diff --git a/apps/client/src/app/components/symbol-icon/symbol-icon.component.html b/apps/client/src/app/components/symbol-icon/symbol-icon.component.html index a544ddef6..0aebd0e5b 100644 --- a/apps/client/src/app/components/symbol-icon/symbol-icon.component.html +++ b/apps/client/src/app/components/symbol-icon/symbol-icon.component.html @@ -1,6 +1,7 @@ diff --git a/apps/client/src/app/components/symbol-icon/symbol-icon.component.ts b/apps/client/src/app/components/symbol-icon/symbol-icon.component.ts index 4a2817329..a6fa0901a 100644 --- a/apps/client/src/app/components/symbol-icon/symbol-icon.component.ts +++ b/apps/client/src/app/components/symbol-icon/symbol-icon.component.ts @@ -2,8 +2,9 @@ import { ChangeDetectionStrategy, Component, Input, - OnInit + OnChanges } from '@angular/core'; +import { DataSource } from '@prisma/client'; @Component({ selector: 'gf-symbol-icon', @@ -11,12 +12,22 @@ import { templateUrl: './symbol-icon.component.html', styleUrls: ['./symbol-icon.component.scss'] }) -export class SymbolIconComponent implements OnInit { +export class SymbolIconComponent implements OnChanges { + @Input() dataSource: DataSource; @Input() size: 'large'; + @Input() symbol: string; @Input() tooltip: string; @Input() url: string; + public src: string; + public constructor() {} - public ngOnInit() {} + public ngOnChanges() { + if (this.dataSource && this.symbol) { + this.src = `../api/v1/logo/${this.dataSource}/${this.symbol}`; + } else if (this.url) { + this.src = `../api/v1/logo?url=${this.url}`; + } + } } 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 34757b2ca..f8c2c6a23 100644 --- a/apps/client/src/app/pages/landing/landing-page.component.ts +++ b/apps/client/src/app/pages/landing/landing-page.component.ts @@ -17,6 +17,7 @@ export class LandingPageComponent implements OnDestroy, OnInit { public demoAuthToken: string; public deviceType: string; public hasPermissionForStatistics: boolean; + public hasPermissionToCreateUser: boolean; public statistics: Statistics; public testimonials = [ { @@ -54,6 +55,11 @@ export class LandingPageComponent implements OnDestroy, OnInit { permissions.enableStatistics ); + this.hasPermissionToCreateUser = hasPermission( + globalPermissions, + permissions.createUserAccount + ); + this.statistics = statistics; } diff --git a/apps/client/src/app/pages/landing/landing-page.html b/apps/client/src/app/pages/landing/landing-page.html index 9b1a5202f..48b448dca 100644 --- a/apps/client/src/app/pages/landing/landing-page.html +++ b/apps/client/src/app/pages/landing/landing-page.html @@ -31,15 +31,18 @@
- + + Get Started + +
or
- Get Started - -
or
+ Live Demo @@ -306,7 +309,7 @@
-
+

Are you ready?

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 640ba2869..ea0f65ac0 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,7 @@ import { Market, ToggleOption } from '@ghostfolio/common/types'; import { translate } from '@ghostfolio/ui/i18n'; import { Account, AssetClass, DataSource } from '@prisma/client'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject, Subscription } from 'rxjs'; +import { Subject } from 'rxjs'; import { distinctUntilChanged, switchMap, takeUntil } from 'rxjs/operators'; @Component({ @@ -71,7 +71,6 @@ export class AllocationsPageComponent implements OnDestroy, OnInit { | 'value' >; }; - public routeQueryParams: Subscription; public sectors: { [name: string]: { name: string; value: number }; }; @@ -98,7 +97,7 @@ export class AllocationsPageComponent implements OnDestroy, OnInit { private router: Router, private userService: UserService ) { - this.routeQueryParams = route.queryParams + route.queryParams .pipe(takeUntil(this.unsubscribeSubject)) .subscribe((params) => { if (params['accountId'] && params['accountDetailDialog']) { 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 c7442e1f3..2f7e3ff58 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 @@ -1,4 +1,8 @@ import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; +import { MatDialog } from '@angular/material/dialog'; +import { ActivatedRoute, Router } from '@angular/router'; +import { PositionDetailDialogParams } from '@ghostfolio/client/components/position/position-detail-dialog/interfaces/interfaces'; +import { PositionDetailDialog } from '@ghostfolio/client/components/position/position-detail-dialog/position-detail-dialog.component'; import { ToggleComponent } from '@ghostfolio/client/components/toggle/toggle.component'; import { DataService } from '@ghostfolio/client/services/data.service'; import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service'; @@ -9,8 +13,9 @@ import { User } from '@ghostfolio/common/interfaces'; import { InvestmentItem } from '@ghostfolio/common/interfaces/investment-item.interface'; +import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { DateRange, GroupBy, ToggleOption } from '@ghostfolio/common/types'; -import { SymbolProfile } from '@prisma/client'; +import { DataSource, SymbolProfile } from '@prisma/client'; import { differenceInDays } from 'date-fns'; import { sortBy } from 'lodash'; import { DeviceDetectorService } from 'ngx-device-detector'; @@ -30,9 +35,12 @@ export class AnalysisPageComponent implements OnDestroy, OnInit { public dateRangeOptions = ToggleComponent.DEFAULT_DATE_RANGE_OPTIONS; public daysInMarket: number; public deviceType: string; + public dividendsByMonth: InvestmentItem[]; + public dividendTimelineDataLabel = $localize`Dividend`; public firstOrderDate: Date; public hasImpersonationId: boolean; public investments: InvestmentItem[]; + public investmentTimelineDataLabel = $localize`Deposit`; public investmentsByMonth: InvestmentItem[]; public isLoadingBenchmarkComparator: boolean; public isLoadingInvestmentChart: boolean; @@ -42,6 +50,7 @@ export class AnalysisPageComponent implements OnDestroy, OnInit { ]; public performanceDataItems: HistoricalDataItem[]; public performanceDataItemsInPercentage: HistoricalDataItem[]; + public portfolioEvolutionDataLabel = $localize`Deposit`; public top3: Position[]; public user: User; @@ -50,12 +59,30 @@ export class AnalysisPageComponent implements OnDestroy, OnInit { public constructor( private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private dialog: MatDialog, private deviceService: DeviceDetectorService, private impersonationStorageService: ImpersonationStorageService, + private route: ActivatedRoute, + private router: Router, private userService: UserService ) { const { benchmarks } = this.dataService.fetchInfo(); this.benchmarks = benchmarks; + + route.queryParams + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe((params) => { + if ( + params['dataSource'] && + params['positionDetailDialog'] && + params['symbol'] + ) { + this.openPositionDialog({ + dataSource: params['dataSource'], + symbol: params['symbol'] + }); + } + }); } public ngOnInit() { @@ -124,6 +151,47 @@ export class AnalysisPageComponent implements OnDestroy, OnInit { this.unsubscribeSubject.complete(); } + private openPositionDialog({ + dataSource, + symbol + }: { + dataSource: DataSource; + symbol: string; + }) { + this.userService + .get() + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe((user) => { + this.user = user; + + const dialogRef = this.dialog.open(PositionDetailDialog, { + autoFocus: false, + data: { + dataSource, + symbol, + baseCurrency: this.user?.settings?.baseCurrency, + colorScheme: this.user?.settings?.colorScheme, + deviceType: this.deviceType, + hasImpersonationId: this.hasImpersonationId, + hasPermissionToReportDataGlitch: hasPermission( + this.user?.permissions, + permissions.reportDataGlitch + ), + locale: this.user?.settings?.locale + }, + height: this.deviceType === 'mobile' ? '97.5vh' : '80vh', + width: this.deviceType === 'mobile' ? '100vw' : '50rem' + }); + + dialogRef + .afterClosed() + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe(() => { + this.router.navigate(['.'], { relativeTo: this.route }); + }); + }); + } + private update() { this.isLoadingBenchmarkComparator = true; this.isLoadingInvestmentChart = true; @@ -165,6 +233,18 @@ export class AnalysisPageComponent implements OnDestroy, OnInit { this.changeDetectorRef.markForCheck(); }); + this.dataService + .fetchDividends({ + groupBy: 'month', + range: this.user?.settings?.dateRange + }) + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe(({ dividends }) => { + this.dividendsByMonth = dividends; + + this.changeDetectorRef.markForCheck(); + }); + this.dataService .fetchInvestments({ groupBy: 'month', diff --git a/apps/client/src/app/pages/portfolio/analysis/analysis-page.html b/apps/client/src/app/pages/portfolio/analysis/analysis-page.html index 6fff81da3..2f54f96d3 100644 --- a/apps/client/src/app/pages/portfolio/analysis/analysis-page.html +++ b/apps/client/src/app/pages/portfolio/analysis/analysis-page.html @@ -35,20 +35,30 @@ > -

-
- {{ i + 1 }}. {{ position.name }} -
-
- -
+
-
-
- {{ i + 1 }}. {{ position.name }} -
-
- -
+
-
+
+ +
+
+
+
+ Dividend Timeline + +
+ +
+
+ +
+
+
diff --git a/apps/client/src/app/pages/portfolio/holdings/holdings-page.component.ts b/apps/client/src/app/pages/portfolio/holdings/holdings-page.component.ts index 414e68678..16f96a700 100644 --- a/apps/client/src/app/pages/portfolio/holdings/holdings-page.component.ts +++ b/apps/client/src/app/pages/portfolio/holdings/holdings-page.component.ts @@ -16,7 +16,7 @@ import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { translate } from '@ghostfolio/ui/i18n'; import { AssetClass, DataSource } from '@prisma/client'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject, Subscription } from 'rxjs'; +import { Subject } from 'rxjs'; import { distinctUntilChanged, switchMap, takeUntil } from 'rxjs/operators'; @Component({ @@ -36,7 +36,6 @@ export class HoldingsPageComponent implements OnDestroy, OnInit { public placeholder = ''; public portfolioDetails: PortfolioDetails; public positionsArray: PortfolioPosition[]; - public routeQueryParams: Subscription; public user: User; private unsubscribeSubject = new Subject(); @@ -51,7 +50,7 @@ export class HoldingsPageComponent implements OnDestroy, OnInit { private router: Router, private userService: UserService ) { - this.routeQueryParams = route.queryParams + route.queryParams .pipe(takeUntil(this.unsubscribeSubject)) .subscribe((params) => { if ( diff --git a/apps/client/src/app/pages/portfolio/holdings/holdings-page.html b/apps/client/src/app/pages/portfolio/holdings/holdings-page.html index 632569e6c..4c8e5b9e5 100644 --- a/apps/client/src/app/pages/portfolio/holdings/holdings-page.html +++ b/apps/client/src/app/pages/portfolio/holdings/holdings-page.html @@ -12,13 +12,13 @@
- + >
- + >
diff --git a/apps/client/src/app/pages/public/public-page.module.ts b/apps/client/src/app/pages/public/public-page.module.ts index 352bb6180..cf43b1bc0 100644 --- a/apps/client/src/app/pages/public/public-page.module.ts +++ b/apps/client/src/app/pages/public/public-page.module.ts @@ -2,7 +2,7 @@ import { CommonModule } from '@angular/common'; import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; -import { GfPositionsTableModule } from '@ghostfolio/client/components/positions-table/positions-table.module'; +import { GfHoldingsTableModule } from '@ghostfolio/ui/holdings-table/holdings-table.module'; import { GfWorldMapChartModule } from '@ghostfolio/client/components/world-map-chart/world-map-chart.module'; import { GfPortfolioProportionChartModule } from '@ghostfolio/ui/portfolio-proportion-chart/portfolio-proportion-chart.module'; import { GfValueModule } from '@ghostfolio/ui/value'; @@ -14,8 +14,8 @@ import { PublicPageComponent } from './public-page.component'; declarations: [PublicPageComponent], imports: [ CommonModule, + GfHoldingsTableModule, GfPortfolioProportionChartModule, - GfPositionsTableModule, GfValueModule, GfWorldMapChartModule, MatButtonModule, 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 ee18a024c..29a428fe1 100644 --- a/apps/client/src/app/pages/register/register-page.component.ts +++ b/apps/client/src/app/pages/register/register-page.component.ts @@ -25,6 +25,7 @@ export class RegisterPageComponent implements OnDestroy, OnInit { public demoAuthToken: string; public deviceType: string; public hasPermissionForSocialLogin: boolean; + public hasPermissionToCreateUser: boolean; public historicalDataItems: LineChartItem[]; public info: InfoItem; @@ -52,6 +53,10 @@ export class RegisterPageComponent implements OnDestroy, OnInit { globalPermissions, permissions.enableSocialLogin ); + this.hasPermissionToCreateUser = hasPermission( + globalPermissions, + permissions.createUserAccount + ); } public async createAccount() { diff --git a/apps/client/src/app/pages/register/register-page.html b/apps/client/src/app/pages/register/register-page.html index 0542af79c..130346ef5 100644 --- a/apps/client/src/app/pages/register/register-page.html +++ b/apps/client/src/app/pages/register/register-page.html @@ -14,14 +14,14 @@
-
+
+
+
+

Deflation

+
+ Deflation is a decrease of the general price level for goods and + services in an economy over a period of time. +
+ +
+

Dollar-Cost Averaging (DCA)

@@ -109,7 +125,7 @@
-
+

Financial Independence

@@ -126,6 +142,38 @@
+
+
+

Inflation

+
+ Inflation is an increase of the general price level for goods and + services in an economy over a period of time. +
+ +
+
+
+
+

Stagflation

+
+ Stagflation describes a situation in which there is a stagnant + economy with high unemployment and high inflation. +
+ +
+
diff --git a/apps/client/src/app/services/data.service.ts b/apps/client/src/app/services/data.service.ts index fc98da0fa..12c54e181 100644 --- a/apps/client/src/app/services/data.service.ts +++ b/apps/client/src/app/services/data.service.ts @@ -27,6 +27,7 @@ import { InfoItem, OAuthResponse, PortfolioDetails, + PortfolioDividends, PortfolioInvestments, PortfolioPerformanceResponse, PortfolioPublicDetails, @@ -35,7 +36,7 @@ import { User } from '@ghostfolio/common/interfaces'; import { filterGlobalPermissions } from '@ghostfolio/common/permissions'; -import { AccountWithValue, DateRange } from '@ghostfolio/common/types'; +import { AccountWithValue, DateRange, GroupBy } from '@ghostfolio/common/types'; import { translate } from '@ghostfolio/ui/i18n'; import { DataSource, Order as OrderModel } from '@prisma/client'; import { format, parseISO } from 'date-fns'; @@ -100,6 +101,18 @@ export class DataService { }); } + public fetchDividends({ + groupBy = 'month', + range + }: { + groupBy?: GroupBy; + range: DateRange; + }) { + return this.http.get('/api/v1/portfolio/dividends', { + params: { groupBy, range } + }); + } + public fetchExchangeRateForDate({ date, symbol @@ -178,10 +191,10 @@ export class DataService { } public fetchInvestments({ - groupBy, + groupBy = 'month', range }: { - groupBy?: 'month'; + groupBy?: GroupBy; range: DateRange; }) { return this.http.get( @@ -256,6 +269,12 @@ export class DataService { response.holdings[symbol].assetSubClass = translate( response.holdings[symbol].assetSubClass ); + + response.holdings[symbol].dateOfFirstActivity = response.holdings[ + symbol + ].dateOfFirstActivity + ? parseISO(response.holdings[symbol].dateOfFirstActivity) + : undefined; } } diff --git a/apps/client/src/locales/messages.de.xlf b/apps/client/src/locales/messages.de.xlf index b2c014534..6cce7bbe8 100644 --- a/apps/client/src/locales/messages.de.xlf +++ b/apps/client/src/locales/messages.de.xlf @@ -90,7 +90,11 @@ apps/client/src/app/components/accounts-table/accounts-table.component.html - 81 + 93 + + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 70 apps/client/src/app/components/admin-users/admin-users.html @@ -110,11 +114,7 @@ Name apps/client/src/app/components/accounts-table/accounts-table.component.html - 21 - - - apps/client/src/app/components/positions-table/positions-table.component.html - 36 + 22 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -124,13 +124,21 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html 70,72 + + libs/ui/src/lib/activities-table/activities-table.component.html + 93 + + + libs/ui/src/lib/holdings-table/holdings-table.component.html + 28 + Total Gesamt apps/client/src/app/components/accounts-table/accounts-table.component.html - 36 + 38 libs/ui/src/lib/activities-table/activities-table.component.html @@ -142,23 +150,23 @@ Wert apps/client/src/app/components/accounts-table/accounts-table.component.html - 135 + 147 apps/client/src/app/components/accounts-table/accounts-table.component.html - 170 + 182 - apps/client/src/app/components/positions-table/positions-table.component.html - 52 + libs/ui/src/lib/activities-table/activities-table.component.html + 235 libs/ui/src/lib/activities-table/activities-table.component.html - 225 + 270 - libs/ui/src/lib/activities-table/activities-table.component.html - 260 + libs/ui/src/lib/holdings-table/holdings-table.component.html + 71 @@ -166,11 +174,11 @@ Bearbeiten apps/client/src/app/components/accounts-table/accounts-table.component.html - 212 + 224 libs/ui/src/lib/activities-table/activities-table.component.html - 369 + 404 @@ -178,19 +186,19 @@ Löschen apps/client/src/app/components/accounts-table/accounts-table.component.html - 220 + 232 apps/client/src/app/components/admin-market-data/admin-market-data.html - 152 + 168 apps/client/src/app/components/admin-users/admin-users.html - 87 + 88 libs/ui/src/lib/activities-table/activities-table.component.html - 385 + 420 @@ -198,7 +206,7 @@ Möchtest du dieses Konto wirklich löschen? apps/client/src/app/components/accounts-table/accounts-table.component.ts - 79 + 81 @@ -220,14 +228,6 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html 24 - - apps/client/src/app/components/positions-table/positions-table.component.html - 22 - - - libs/ui/src/lib/activities-table/activities-table.component.html - 88 - Data Source @@ -362,7 +362,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 154 + 166 apps/client/src/app/pages/account/create-or-update-access-dialog/create-or-update-access-dialog.html @@ -374,7 +374,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 201,205 + 218,222 apps/client/src/app/pages/register/show-access-token-dialog/show-access-token-dialog.html @@ -390,7 +390,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 161 + 173 apps/client/src/app/pages/account/create-or-update-access-dialog/create-or-update-access-dialog.html @@ -402,7 +402,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 208,213 + 225,230 @@ -412,6 +412,14 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html 60 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 61 + + + libs/ui/src/lib/holdings-table/holdings-table.component.html + 47 + Activity Count @@ -434,7 +442,7 @@ Daten einholen apps/client/src/app/components/admin-market-data/admin-market-data.html - 139 + 155 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -446,7 +454,7 @@ Bitte Währung hinzufügen: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 104 + 106 @@ -454,7 +462,7 @@ Möchtest du diesen Gutscheincode wirklich löschen? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 118 + 120 @@ -462,7 +470,7 @@ Möchtest du diese Währung wirklich löschen? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 131 + 133 @@ -470,7 +478,7 @@ Möchtest du den Cache wirklich leeren? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 148 + 150 @@ -478,7 +486,7 @@ Bitte gebe deine Systemmeldung ein: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 171 + 180 @@ -502,7 +510,7 @@ Letzte Daten einholen apps/client/src/app/components/admin-market-data/admin-market-data.html - 115 + 131 @@ -510,7 +518,7 @@ Alle Daten einholen apps/client/src/app/components/admin-market-data/admin-market-data.html - 118 + 134 @@ -518,11 +526,11 @@ Profildaten einholen apps/client/src/app/components/admin-market-data/admin-market-data.html - 121 + 137 apps/client/src/app/components/admin-market-data/admin-market-data.html - 145 + 161 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -550,7 +558,7 @@ Systemmeldung apps/client/src/app/components/admin-overview/admin-overview.html - 86 + 106 @@ -558,7 +566,7 @@ Systemmeldung setzen apps/client/src/app/components/admin-overview/admin-overview.html - 108 + 128 @@ -566,7 +574,7 @@ Lese-Modus apps/client/src/app/components/admin-overview/admin-overview.html - 113 + 96 @@ -574,7 +582,7 @@ Gutscheincodes apps/client/src/app/components/admin-overview/admin-overview.html - 126 + 136 @@ -582,7 +590,7 @@ Hinzufügen apps/client/src/app/components/admin-overview/admin-overview.html - 161 + 171 @@ -590,7 +598,7 @@ Verwaltung apps/client/src/app/components/admin-overview/admin-overview.html - 168 + 178 @@ -598,7 +606,7 @@ Cache leeren apps/client/src/app/components/admin-overview/admin-overview.html - 172 + 182 @@ -810,7 +818,7 @@ Einloggen apps/client/src/app/components/header/header.component.ts - 112 + 118 apps/client/src/app/pages/webauthn/webauthn-page-routing.module.ts @@ -822,7 +830,7 @@ Ups! Falsches Sicherheits-Token. apps/client/src/app/components/header/header.component.ts - 126 + 132 @@ -1106,7 +1114,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 184,186 + 201,203 @@ -1121,8 +1129,8 @@ Allocation Allokation - apps/client/src/app/components/positions-table/positions-table.component.html - 72 + libs/ui/src/lib/holdings-table/holdings-table.component.html + 95 @@ -1137,16 +1145,16 @@ 57 - apps/client/src/app/components/positions-table/positions-table.component.html - 91 + libs/ui/src/lib/holdings-table/holdings-table.component.html + 115 Show all Alle anzeigen - apps/client/src/app/components/positions-table/positions-table.component.html - 137 + libs/ui/src/lib/holdings-table/holdings-table.component.html + 171 @@ -1338,7 +1346,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 286 + 301 @@ -1514,7 +1522,7 @@ Währung apps/client/src/app/components/accounts-table/accounts-table.component.html - 46 + 48 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1526,7 +1534,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 113 + 123 @@ -1534,7 +1542,7 @@ Cash-Bestand apps/client/src/app/components/accounts-table/accounts-table.component.html - 100 + 112 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1550,7 +1558,7 @@ apps/client/src/app/components/accounts-table/accounts-table.component.html - 58 + 65 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1659,7 +1667,7 @@ By Asset Class - Nach Asset Class + Nach Anlageklasse apps/client/src/app/pages/portfolio/allocations/allocations-page.html 96 @@ -1730,7 +1738,7 @@ Zeitstrahl der Investitionen apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 142 + 143 @@ -1870,7 +1878,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 134 + 144 @@ -1882,7 +1890,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 163 + 173 @@ -1892,17 +1900,25 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html 131,132 + + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html + 148,149 + libs/ui/src/lib/activities-table/activities-table.component.html - 192 + 202 Note Kommentar + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 153 + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 140,143 + 157,160 @@ -1922,7 +1938,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 154,156 + 171,173 @@ -2082,7 +2098,7 @@ Geplant libs/ui/src/lib/activities-table/activities-table.component.html - 99 + 103 @@ -2090,7 +2106,7 @@ Aktivitäten importieren libs/ui/src/lib/activities-table/activities-table.component.html - 323 + 367 @@ -2098,7 +2114,7 @@ Aktivitäten exportieren libs/ui/src/lib/activities-table/activities-table.component.html - 333 + 377 @@ -2106,7 +2122,7 @@ Geplante Aktivitäten als ICS exportieren libs/ui/src/lib/activities-table/activities-table.component.html - 343 + 387 @@ -2114,7 +2130,7 @@ Kopieren libs/ui/src/lib/activities-table/activities-table.component.html - 373 + 408 @@ -2122,7 +2138,7 @@ Geplante Aktivität als ICS exportieren libs/ui/src/lib/activities-table/activities-table.component.html - 381 + 416 @@ -2130,7 +2146,7 @@ Möchtest du diese Aktivität wirklich löschen? libs/ui/src/lib/activities-table/activities-table.component.ts - 147 + 149 @@ -2284,10 +2300,6 @@ First Buy Date Datum des Erstkaufs - - apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 61 - apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html 129 @@ -2310,7 +2322,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 169,171 + 186,188 @@ -2376,10 +2388,6 @@ Transactions Transaktionen - - apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 70 - apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html 138 @@ -2414,15 +2422,19 @@ Monatlich apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 41 + 44 Deposit Einlage - apps/client/src/app/components/investment-chart/investment-chart.component.ts - 156 + apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts + 38 + + + apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts + 48 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts @@ -2502,7 +2514,7 @@ Filtern nach Konto, Währung, Symbol oder Typ... libs/ui/src/lib/activities-table/activities-table.component.ts - 319 + 321 @@ -2634,7 +2646,7 @@ Gesamtbetrag apps/client/src/app/components/investment-chart/investment-chart.component.ts - 177 + 178 @@ -2650,7 +2662,7 @@ Sparrate apps/client/src/app/components/investment-chart/investment-chart.component.ts - 226 + 230 @@ -2674,7 +2686,7 @@ Symbol libs/ui/src/lib/i18n.ts - 8 + 9 @@ -2682,7 +2694,7 @@ Tag libs/ui/src/lib/i18n.ts - 9 + 10 @@ -2690,7 +2702,7 @@ Bargeld libs/ui/src/lib/i18n.ts - 12 + 13 @@ -2698,7 +2710,7 @@ Rohstoff libs/ui/src/lib/i18n.ts - 13 + 14 @@ -2706,7 +2718,7 @@ Anteilskapital libs/ui/src/lib/i18n.ts - 14 + 15 @@ -2714,7 +2726,7 @@ Feste Einkünfte libs/ui/src/lib/i18n.ts - 15 + 16 @@ -2722,7 +2734,7 @@ Immobilien libs/ui/src/lib/i18n.ts - 16 + 17 @@ -2730,7 +2742,7 @@ Anleihe libs/ui/src/lib/i18n.ts - 19 + 20 @@ -2738,7 +2750,7 @@ Kryptowährung libs/ui/src/lib/i18n.ts - 20 + 21 @@ -2746,7 +2758,7 @@ ETF libs/ui/src/lib/i18n.ts - 21 + 22 @@ -2754,7 +2766,7 @@ Investmentfonds libs/ui/src/lib/i18n.ts - 22 + 23 @@ -2762,7 +2774,7 @@ Edelmetall libs/ui/src/lib/i18n.ts - 23 + 24 @@ -2770,7 +2782,7 @@ Privates Beteiligungskapital libs/ui/src/lib/i18n.ts - 24 + 25 @@ -2778,7 +2790,7 @@ Aktie libs/ui/src/lib/i18n.ts - 25 + 26 @@ -2786,7 +2798,7 @@ Notfallfonds libs/ui/src/lib/i18n.ts - 6 + 7 @@ -2794,7 +2806,7 @@ Andere libs/ui/src/lib/i18n.ts - 7 + 8 libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts @@ -2818,7 +2830,7 @@ Nordamerika libs/ui/src/lib/i18n.ts - 31 + 32 @@ -2826,7 +2838,7 @@ Afrika libs/ui/src/lib/i18n.ts - 28 + 29 @@ -2834,15 +2846,15 @@ Asien libs/ui/src/lib/i18n.ts - 29 + 30 Europe - Europa + Europa libs/ui/src/lib/i18n.ts - 30 + 31 @@ -2850,7 +2862,7 @@ Ozeanien libs/ui/src/lib/i18n.ts - 32 + 33 @@ -2858,7 +2870,7 @@ Südamerika libs/ui/src/lib/i18n.ts - 33 + 34 @@ -2925,6 +2937,38 @@ 142 + + Dividend Timeline + Zeitstrahl der Dividenden + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 180 + + + + Dividend + Dividenden + + apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts + 34 + + + + Asset Sub Class + Anlageunterklasse + + libs/ui/src/lib/i18n.ts + 6 + + + + User Signup + Benutzer Registrierung + + apps/client/src/app/components/admin-overview/admin-overview.html + 86 + + diff --git a/apps/client/src/locales/messages.es.xlf b/apps/client/src/locales/messages.es.xlf index eab325aa3..787c8664d 100644 --- a/apps/client/src/locales/messages.es.xlf +++ b/apps/client/src/locales/messages.es.xlf @@ -91,7 +91,11 @@ apps/client/src/app/components/accounts-table/accounts-table.component.html - 81 + 93 + + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 70 apps/client/src/app/components/admin-users/admin-users.html @@ -111,11 +115,7 @@ Nombre apps/client/src/app/components/accounts-table/accounts-table.component.html - 21 - - - apps/client/src/app/components/positions-table/positions-table.component.html - 36 + 22 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -125,13 +125,21 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html 70,72 + + libs/ui/src/lib/activities-table/activities-table.component.html + 93 + + + libs/ui/src/lib/holdings-table/holdings-table.component.html + 28 + Total Total apps/client/src/app/components/accounts-table/accounts-table.component.html - 36 + 38 libs/ui/src/lib/activities-table/activities-table.component.html @@ -143,23 +151,23 @@ Valor apps/client/src/app/components/accounts-table/accounts-table.component.html - 135 + 147 apps/client/src/app/components/accounts-table/accounts-table.component.html - 170 + 182 - apps/client/src/app/components/positions-table/positions-table.component.html - 52 + libs/ui/src/lib/activities-table/activities-table.component.html + 235 libs/ui/src/lib/activities-table/activities-table.component.html - 225 + 270 - libs/ui/src/lib/activities-table/activities-table.component.html - 260 + libs/ui/src/lib/holdings-table/holdings-table.component.html + 71 @@ -167,11 +175,11 @@ Edita apps/client/src/app/components/accounts-table/accounts-table.component.html - 212 + 224 libs/ui/src/lib/activities-table/activities-table.component.html - 369 + 404 @@ -179,19 +187,19 @@ Elimina apps/client/src/app/components/accounts-table/accounts-table.component.html - 220 + 232 apps/client/src/app/components/admin-market-data/admin-market-data.html - 152 + 168 apps/client/src/app/components/admin-users/admin-users.html - 87 + 88 libs/ui/src/lib/activities-table/activities-table.component.html - 385 + 420 @@ -199,7 +207,7 @@ ¿Estás seguro de eliminar esta cuenta? apps/client/src/app/components/accounts-table/accounts-table.component.ts - 79 + 81 @@ -221,14 +229,6 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html 24 - - apps/client/src/app/components/positions-table/positions-table.component.html - 22 - - - libs/ui/src/lib/activities-table/activities-table.component.html - 88 - Data Source @@ -363,7 +363,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 154 + 166 apps/client/src/app/pages/account/create-or-update-access-dialog/create-or-update-access-dialog.html @@ -375,7 +375,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 201,205 + 218,222 apps/client/src/app/pages/register/show-access-token-dialog/show-access-token-dialog.html @@ -391,7 +391,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 161 + 173 apps/client/src/app/pages/account/create-or-update-access-dialog/create-or-update-access-dialog.html @@ -403,7 +403,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 208,213 + 225,230 @@ -413,6 +413,14 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html 60 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 61 + + + libs/ui/src/lib/holdings-table/holdings-table.component.html + 47 + Activity Count @@ -435,7 +443,7 @@ Recoger datos apps/client/src/app/components/admin-market-data/admin-market-data.html - 139 + 155 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -447,7 +455,7 @@ Por favor, añade una divisa: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 104 + 106 @@ -455,7 +463,7 @@ ¿Estás seguro de eliminar este cupón? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 118 + 120 @@ -463,7 +471,7 @@ ¿Estás seguro de eliminar esta divisa? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 131 + 133 @@ -471,7 +479,7 @@ ¿Estás seguro de limpiar la caché? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 148 + 150 @@ -479,7 +487,7 @@ Por favor, establece tu mensaje del sistema: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 171 + 180 @@ -503,7 +511,7 @@ Recoger datos recientes apps/client/src/app/components/admin-market-data/admin-market-data.html - 115 + 131 @@ -511,7 +519,7 @@ Recoger todos los datos apps/client/src/app/components/admin-market-data/admin-market-data.html - 118 + 134 @@ -519,11 +527,11 @@ Recoger los datos del perfil apps/client/src/app/components/admin-market-data/admin-market-data.html - 121 + 137 apps/client/src/app/components/admin-market-data/admin-market-data.html - 145 + 161 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -551,7 +559,7 @@ Mensaje del sistema apps/client/src/app/components/admin-overview/admin-overview.html - 86 + 106 @@ -559,7 +567,7 @@ Establecer mensaje apps/client/src/app/components/admin-overview/admin-overview.html - 108 + 128 @@ -567,7 +575,7 @@ Modo de solo lectura apps/client/src/app/components/admin-overview/admin-overview.html - 113 + 96 @@ -575,7 +583,7 @@ Cupones apps/client/src/app/components/admin-overview/admin-overview.html - 126 + 136 @@ -583,7 +591,7 @@ Añadir apps/client/src/app/components/admin-overview/admin-overview.html - 161 + 171 @@ -591,7 +599,7 @@ Tareas domésticas apps/client/src/app/components/admin-overview/admin-overview.html - 168 + 178 @@ -599,7 +607,7 @@ Limpiar caché apps/client/src/app/components/admin-overview/admin-overview.html - 172 + 182 @@ -811,7 +819,7 @@ Iniciar sesión apps/client/src/app/components/header/header.component.ts - 112 + 118 apps/client/src/app/pages/webauthn/webauthn-page-routing.module.ts @@ -823,7 +831,7 @@ Vaya! Token de seguridad incorrecto. apps/client/src/app/components/header/header.component.ts - 126 + 132 @@ -1107,7 +1115,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 184,186 + 201,203 @@ -1122,8 +1130,8 @@ Allocation Distribución - apps/client/src/app/components/positions-table/positions-table.component.html - 72 + libs/ui/src/lib/holdings-table/holdings-table.component.html + 95 @@ -1138,16 +1146,16 @@ 57 - apps/client/src/app/components/positions-table/positions-table.component.html - 91 + libs/ui/src/lib/holdings-table/holdings-table.component.html + 115 Show all Mostrar todos - apps/client/src/app/components/positions-table/positions-table.component.html - 137 + libs/ui/src/lib/holdings-table/holdings-table.component.html + 171 @@ -1339,7 +1347,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 286 + 301 @@ -1515,7 +1523,7 @@ Divisa base apps/client/src/app/components/accounts-table/accounts-table.component.html - 46 + 48 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1527,7 +1535,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 113 + 123 @@ -1535,7 +1543,7 @@ Saldo en efectivo apps/client/src/app/components/accounts-table/accounts-table.component.html - 100 + 112 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1551,7 +1559,7 @@ apps/client/src/app/components/accounts-table/accounts-table.component.html - 58 + 65 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1731,7 +1739,7 @@ Cronología de la inversión apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 142 + 143 @@ -1871,7 +1879,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 134 + 144 @@ -1883,7 +1891,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 163 + 173 @@ -1893,17 +1901,25 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html 131,132 + + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html + 148,149 + libs/ui/src/lib/activities-table/activities-table.component.html - 192 + 202 Note Nota + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 153 + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 140,143 + 157,160 @@ -1923,7 +1939,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 154,156 + 171,173 @@ -2083,7 +2099,7 @@ Borrador libs/ui/src/lib/activities-table/activities-table.component.html - 99 + 103 @@ -2091,7 +2107,7 @@ Importar operaciones libs/ui/src/lib/activities-table/activities-table.component.html - 323 + 367 @@ -2099,7 +2115,7 @@ Exportar operaciones libs/ui/src/lib/activities-table/activities-table.component.html - 333 + 377 @@ -2107,7 +2123,7 @@ Exportar borrador como ICS libs/ui/src/lib/activities-table/activities-table.component.html - 343 + 387 @@ -2115,7 +2131,7 @@ Clonar libs/ui/src/lib/activities-table/activities-table.component.html - 373 + 408 @@ -2123,7 +2139,7 @@ Exportar borrador como ICS libs/ui/src/lib/activities-table/activities-table.component.html - 381 + 416 @@ -2131,7 +2147,7 @@ ¿Estás seguro de eliminar esta operación? libs/ui/src/lib/activities-table/activities-table.component.ts - 147 + 149 @@ -2287,7 +2303,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 169,171 + 186,188 @@ -2365,10 +2381,6 @@ First Buy Date Fecha de la primera compra - - apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 61 - apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html 129 @@ -2377,10 +2389,6 @@ Transactions Transacciones - - apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 70 - apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html 138 @@ -2422,8 +2430,12 @@ Deposit Depósito - apps/client/src/app/components/investment-chart/investment-chart.component.ts - 156 + apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts + 38 + + + apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts + 48 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts @@ -2443,7 +2455,7 @@ Mensual apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 41 + 44 @@ -2503,7 +2515,7 @@ Filtrar por cuenta, divisa, símbolo o tipo... libs/ui/src/lib/activities-table/activities-table.component.ts - 319 + 321 @@ -2635,7 +2647,7 @@ Importe total apps/client/src/app/components/investment-chart/investment-chart.component.ts - 177 + 178 @@ -2651,7 +2663,7 @@ Tasa de ahorro apps/client/src/app/components/investment-chart/investment-chart.component.ts - 226 + 230 @@ -2675,7 +2687,7 @@ Símbolo libs/ui/src/lib/i18n.ts - 8 + 9 @@ -2683,7 +2695,7 @@ Etiqueta libs/ui/src/lib/i18n.ts - 9 + 10 @@ -2691,7 +2703,7 @@ Efectivo libs/ui/src/lib/i18n.ts - 12 + 13 @@ -2699,7 +2711,7 @@ Bien libs/ui/src/lib/i18n.ts - 13 + 14 @@ -2707,7 +2719,7 @@ Capital libs/ui/src/lib/i18n.ts - 14 + 15 @@ -2715,7 +2727,7 @@ Renta fija libs/ui/src/lib/i18n.ts - 15 + 16 @@ -2723,7 +2735,7 @@ Propiedad inmobiliaria libs/ui/src/lib/i18n.ts - 16 + 17 @@ -2731,7 +2743,7 @@ Bono libs/ui/src/lib/i18n.ts - 19 + 20 @@ -2739,7 +2751,7 @@ Criptomoneda libs/ui/src/lib/i18n.ts - 20 + 21 @@ -2747,7 +2759,7 @@ ETF libs/ui/src/lib/i18n.ts - 21 + 22 @@ -2755,7 +2767,7 @@ Fondo de inversión libs/ui/src/lib/i18n.ts - 22 + 23 @@ -2763,7 +2775,7 @@ Metal precioso libs/ui/src/lib/i18n.ts - 23 + 24 @@ -2771,7 +2783,7 @@ Capital riesgo libs/ui/src/lib/i18n.ts - 24 + 25 @@ -2779,7 +2791,7 @@ Acción libs/ui/src/lib/i18n.ts - 25 + 26 @@ -2787,7 +2799,7 @@ Fondo de emergencia libs/ui/src/lib/i18n.ts - 6 + 7 @@ -2795,7 +2807,7 @@ Otros libs/ui/src/lib/i18n.ts - 7 + 8 libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts @@ -2819,7 +2831,7 @@ América del Norte libs/ui/src/lib/i18n.ts - 31 + 32 @@ -2827,7 +2839,7 @@ África libs/ui/src/lib/i18n.ts - 28 + 29 @@ -2835,7 +2847,7 @@ Asia libs/ui/src/lib/i18n.ts - 29 + 30 @@ -2843,7 +2855,7 @@ Europa libs/ui/src/lib/i18n.ts - 30 + 31 @@ -2851,7 +2863,7 @@ Oceanía libs/ui/src/lib/i18n.ts - 32 + 33 @@ -2859,7 +2871,7 @@ América del Sur libs/ui/src/lib/i18n.ts - 33 + 34 @@ -2926,6 +2938,38 @@ 142 + + Dividend + Dividend + + apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts + 34 + + + + Dividend Timeline + Dividend Timeline + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 180 + + + + Asset Sub Class + Subtipo de activo + + libs/ui/src/lib/i18n.ts + 6 + + + + User Signup + User Signup + + apps/client/src/app/components/admin-overview/admin-overview.html + 86 + + diff --git a/apps/client/src/locales/messages.it.xlf b/apps/client/src/locales/messages.it.xlf index 2807f38f0..5f20dd9f3 100644 --- a/apps/client/src/locales/messages.it.xlf +++ b/apps/client/src/locales/messages.it.xlf @@ -91,7 +91,11 @@ apps/client/src/app/components/accounts-table/accounts-table.component.html - 81 + 93 + + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 70 apps/client/src/app/components/admin-users/admin-users.html @@ -111,11 +115,7 @@ Nome apps/client/src/app/components/accounts-table/accounts-table.component.html - 21 - - - apps/client/src/app/components/positions-table/positions-table.component.html - 36 + 22 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -125,13 +125,21 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html 70,72 + + libs/ui/src/lib/activities-table/activities-table.component.html + 93 + + + libs/ui/src/lib/holdings-table/holdings-table.component.html + 28 + Total Totale apps/client/src/app/components/accounts-table/accounts-table.component.html - 36 + 38 libs/ui/src/lib/activities-table/activities-table.component.html @@ -143,23 +151,23 @@ Valore apps/client/src/app/components/accounts-table/accounts-table.component.html - 135 + 147 apps/client/src/app/components/accounts-table/accounts-table.component.html - 170 + 182 - apps/client/src/app/components/positions-table/positions-table.component.html - 52 + libs/ui/src/lib/activities-table/activities-table.component.html + 235 libs/ui/src/lib/activities-table/activities-table.component.html - 225 + 270 - libs/ui/src/lib/activities-table/activities-table.component.html - 260 + libs/ui/src/lib/holdings-table/holdings-table.component.html + 71 @@ -167,11 +175,11 @@ Modifica apps/client/src/app/components/accounts-table/accounts-table.component.html - 212 + 224 libs/ui/src/lib/activities-table/activities-table.component.html - 369 + 404 @@ -179,19 +187,19 @@ Elimina apps/client/src/app/components/accounts-table/accounts-table.component.html - 220 + 232 apps/client/src/app/components/admin-market-data/admin-market-data.html - 152 + 168 apps/client/src/app/components/admin-users/admin-users.html - 87 + 88 libs/ui/src/lib/activities-table/activities-table.component.html - 385 + 420 @@ -199,7 +207,7 @@ Vuoi davvero eliminare questo account? apps/client/src/app/components/accounts-table/accounts-table.component.ts - 79 + 81 @@ -221,14 +229,6 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html 24 - - apps/client/src/app/components/positions-table/positions-table.component.html - 22 - - - libs/ui/src/lib/activities-table/activities-table.component.html - 88 - Data Source @@ -363,7 +363,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 154 + 166 apps/client/src/app/pages/account/create-or-update-access-dialog/create-or-update-access-dialog.html @@ -375,7 +375,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 201,205 + 218,222 apps/client/src/app/pages/register/show-access-token-dialog/show-access-token-dialog.html @@ -391,7 +391,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 161 + 173 apps/client/src/app/pages/account/create-or-update-access-dialog/create-or-update-access-dialog.html @@ -403,7 +403,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 208,213 + 225,230 @@ -413,6 +413,14 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html 60 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 61 + + + libs/ui/src/lib/holdings-table/holdings-table.component.html + 47 + Activity Count @@ -435,7 +443,7 @@ Raccogli i dati apps/client/src/app/components/admin-market-data/admin-market-data.html - 139 + 155 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -447,7 +455,7 @@ Aggiungi una valuta: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 104 + 106 @@ -455,7 +463,7 @@ Vuoi davvero eliminare questo buono? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 118 + 120 @@ -463,7 +471,7 @@ Vuoi davvero eliminare questa valuta? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 131 + 133 @@ -471,7 +479,7 @@ Vuoi davvero svuotare la cache? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 148 + 150 @@ -479,7 +487,7 @@ Imposta il messaggio di sistema: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 171 + 180 @@ -503,7 +511,7 @@ Raccogli dati recenti apps/client/src/app/components/admin-market-data/admin-market-data.html - 115 + 131 @@ -511,7 +519,7 @@ Raccogli tutti i dati apps/client/src/app/components/admin-market-data/admin-market-data.html - 118 + 134 @@ -519,11 +527,11 @@ Raccogli i dati del profilo apps/client/src/app/components/admin-market-data/admin-market-data.html - 121 + 137 apps/client/src/app/components/admin-market-data/admin-market-data.html - 145 + 161 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -551,7 +559,7 @@ Messaggio di sistema apps/client/src/app/components/admin-overview/admin-overview.html - 86 + 106 @@ -559,7 +567,7 @@ Imposta messaggio apps/client/src/app/components/admin-overview/admin-overview.html - 108 + 128 @@ -567,7 +575,7 @@ Modalità di sola lettura apps/client/src/app/components/admin-overview/admin-overview.html - 113 + 96 @@ -575,7 +583,7 @@ Buoni sconto apps/client/src/app/components/admin-overview/admin-overview.html - 126 + 136 @@ -583,7 +591,7 @@ Aggiungi apps/client/src/app/components/admin-overview/admin-overview.html - 161 + 171 @@ -591,7 +599,7 @@ Bilancio domestico apps/client/src/app/components/admin-overview/admin-overview.html - 168 + 178 @@ -599,7 +607,7 @@ Svuota la cache apps/client/src/app/components/admin-overview/admin-overview.html - 172 + 182 @@ -811,7 +819,7 @@ Accedi apps/client/src/app/components/header/header.component.ts - 112 + 118 apps/client/src/app/pages/webauthn/webauthn-page-routing.module.ts @@ -823,7 +831,7 @@ Ops! Token di sicurezza errato. apps/client/src/app/components/header/header.component.ts - 126 + 132 @@ -1107,7 +1115,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 184,186 + 201,203 @@ -1122,8 +1130,8 @@ Allocation Allocazione - apps/client/src/app/components/positions-table/positions-table.component.html - 72 + libs/ui/src/lib/holdings-table/holdings-table.component.html + 95 @@ -1138,16 +1146,16 @@ 57 - apps/client/src/app/components/positions-table/positions-table.component.html - 91 + libs/ui/src/lib/holdings-table/holdings-table.component.html + 115 Show all Mostra tutti - apps/client/src/app/components/positions-table/positions-table.component.html - 137 + libs/ui/src/lib/holdings-table/holdings-table.component.html + 171 @@ -1339,7 +1347,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 286 + 301 @@ -1515,7 +1523,7 @@ Valuta apps/client/src/app/components/accounts-table/accounts-table.component.html - 46 + 48 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1527,7 +1535,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 113 + 123 @@ -1535,7 +1543,7 @@ Saldo di cassa apps/client/src/app/components/accounts-table/accounts-table.component.html - 100 + 112 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1551,7 +1559,7 @@ apps/client/src/app/components/accounts-table/accounts-table.component.html - 58 + 65 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1731,7 +1739,7 @@ Cronologia degli investimenti apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 142 + 143 @@ -1871,7 +1879,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 134 + 144 @@ -1883,7 +1891,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 163 + 173 @@ -1893,17 +1901,25 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html 131,132 + + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html + 148,149 + libs/ui/src/lib/activities-table/activities-table.component.html - 192 + 202 Note Nota + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 153 + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 140,143 + 157,160 @@ -1923,7 +1939,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 154,156 + 171,173 @@ -2083,7 +2099,7 @@ Bozza libs/ui/src/lib/activities-table/activities-table.component.html - 99 + 103 @@ -2091,7 +2107,7 @@ Importa le attività libs/ui/src/lib/activities-table/activities-table.component.html - 323 + 367 @@ -2099,7 +2115,7 @@ Esporta le attività libs/ui/src/lib/activities-table/activities-table.component.html - 333 + 377 @@ -2107,7 +2123,7 @@ Esporta le bozze come ICS libs/ui/src/lib/activities-table/activities-table.component.html - 343 + 387 @@ -2115,7 +2131,7 @@ Clona libs/ui/src/lib/activities-table/activities-table.component.html - 373 + 408 @@ -2123,7 +2139,7 @@ Esporta la bozza come ICS libs/ui/src/lib/activities-table/activities-table.component.html - 381 + 416 @@ -2131,7 +2147,7 @@ Vuoi davvero eliminare questa attività? libs/ui/src/lib/activities-table/activities-table.component.ts - 147 + 149 @@ -2287,7 +2303,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 169,171 + 186,188 @@ -2365,10 +2381,6 @@ First Buy Date Data del primo acquisto - - apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 61 - apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html 129 @@ -2377,10 +2389,6 @@ Transactions Transazioni - - apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 70 - apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html 138 @@ -2422,8 +2430,12 @@ Deposit Deposito - apps/client/src/app/components/investment-chart/investment-chart.component.ts - 156 + apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts + 38 + + + apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts + 48 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts @@ -2443,7 +2455,7 @@ Mensile apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 41 + 44 @@ -2503,7 +2515,7 @@ Filtra per account, valuta, simbolo o tipo... libs/ui/src/lib/activities-table/activities-table.component.ts - 319 + 321 @@ -2635,7 +2647,7 @@ Total Amount apps/client/src/app/components/investment-chart/investment-chart.component.ts - 177 + 178 @@ -2651,7 +2663,7 @@ Tasso di risparmio apps/client/src/app/components/investment-chart/investment-chart.component.ts - 226 + 230 @@ -2675,7 +2687,7 @@ Symbol libs/ui/src/lib/i18n.ts - 8 + 9 @@ -2683,7 +2695,7 @@ Tag libs/ui/src/lib/i18n.ts - 9 + 10 @@ -2691,7 +2703,7 @@ Cash libs/ui/src/lib/i18n.ts - 12 + 13 @@ -2699,7 +2711,7 @@ Commodity libs/ui/src/lib/i18n.ts - 13 + 14 @@ -2707,7 +2719,7 @@ Equity libs/ui/src/lib/i18n.ts - 14 + 15 @@ -2715,7 +2727,7 @@ Fixed Income libs/ui/src/lib/i18n.ts - 15 + 16 @@ -2723,7 +2735,7 @@ Real Estate libs/ui/src/lib/i18n.ts - 16 + 17 @@ -2731,7 +2743,7 @@ Bond libs/ui/src/lib/i18n.ts - 19 + 20 @@ -2739,7 +2751,7 @@ Cryptocurrency libs/ui/src/lib/i18n.ts - 20 + 21 @@ -2747,7 +2759,7 @@ ETF libs/ui/src/lib/i18n.ts - 21 + 22 @@ -2755,7 +2767,7 @@ Mutual Fund libs/ui/src/lib/i18n.ts - 22 + 23 @@ -2763,7 +2775,7 @@ Precious Metal libs/ui/src/lib/i18n.ts - 23 + 24 @@ -2771,7 +2783,7 @@ Private Equity libs/ui/src/lib/i18n.ts - 24 + 25 @@ -2779,7 +2791,7 @@ Stock libs/ui/src/lib/i18n.ts - 25 + 26 @@ -2787,7 +2799,7 @@ Emergency Fund libs/ui/src/lib/i18n.ts - 6 + 7 @@ -2795,7 +2807,7 @@ Other libs/ui/src/lib/i18n.ts - 7 + 8 libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts @@ -2819,7 +2831,7 @@ North America libs/ui/src/lib/i18n.ts - 31 + 32 @@ -2827,7 +2839,7 @@ Africa libs/ui/src/lib/i18n.ts - 28 + 29 @@ -2835,7 +2847,7 @@ Asia libs/ui/src/lib/i18n.ts - 29 + 30 @@ -2843,7 +2855,7 @@ Europe libs/ui/src/lib/i18n.ts - 30 + 31 @@ -2851,7 +2863,7 @@ Oceania libs/ui/src/lib/i18n.ts - 32 + 33 @@ -2859,7 +2871,7 @@ South America libs/ui/src/lib/i18n.ts - 33 + 34 @@ -2926,6 +2938,38 @@ 142 + + Dividend + Dividend + + apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts + 34 + + + + Dividend Timeline + Dividend Timeline + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 180 + + + + Asset Sub Class + Sub-asset class + + libs/ui/src/lib/i18n.ts + 6 + + + + User Signup + User Signup + + apps/client/src/app/components/admin-overview/admin-overview.html + 86 + + diff --git a/apps/client/src/locales/messages.nl.xlf b/apps/client/src/locales/messages.nl.xlf index e72bde28b..af4e00ba2 100644 --- a/apps/client/src/locales/messages.nl.xlf +++ b/apps/client/src/locales/messages.nl.xlf @@ -90,7 +90,11 @@ apps/client/src/app/components/accounts-table/accounts-table.component.html - 81 + 93 + + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 70 apps/client/src/app/components/admin-users/admin-users.html @@ -110,11 +114,7 @@ Naam apps/client/src/app/components/accounts-table/accounts-table.component.html - 21 - - - apps/client/src/app/components/positions-table/positions-table.component.html - 36 + 22 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -124,13 +124,21 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html 70,72 + + libs/ui/src/lib/activities-table/activities-table.component.html + 93 + + + libs/ui/src/lib/holdings-table/holdings-table.component.html + 28 + Total Totaal apps/client/src/app/components/accounts-table/accounts-table.component.html - 36 + 38 libs/ui/src/lib/activities-table/activities-table.component.html @@ -142,23 +150,23 @@ Waarde apps/client/src/app/components/accounts-table/accounts-table.component.html - 135 + 147 apps/client/src/app/components/accounts-table/accounts-table.component.html - 170 + 182 - apps/client/src/app/components/positions-table/positions-table.component.html - 52 + libs/ui/src/lib/activities-table/activities-table.component.html + 235 libs/ui/src/lib/activities-table/activities-table.component.html - 225 + 270 - libs/ui/src/lib/activities-table/activities-table.component.html - 260 + libs/ui/src/lib/holdings-table/holdings-table.component.html + 71 @@ -166,11 +174,11 @@ Bewerken apps/client/src/app/components/accounts-table/accounts-table.component.html - 212 + 224 libs/ui/src/lib/activities-table/activities-table.component.html - 369 + 404 @@ -178,19 +186,19 @@ Verwijderen apps/client/src/app/components/accounts-table/accounts-table.component.html - 220 + 232 apps/client/src/app/components/admin-market-data/admin-market-data.html - 152 + 168 apps/client/src/app/components/admin-users/admin-users.html - 87 + 88 libs/ui/src/lib/activities-table/activities-table.component.html - 385 + 420 @@ -198,7 +206,7 @@ Wilt u deze account echt verwijderen? apps/client/src/app/components/accounts-table/accounts-table.component.ts - 79 + 81 @@ -220,14 +228,6 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html 24 - - apps/client/src/app/components/positions-table/positions-table.component.html - 22 - - - libs/ui/src/lib/activities-table/activities-table.component.html - 88 - Data Source @@ -362,7 +362,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 154 + 166 apps/client/src/app/pages/account/create-or-update-access-dialog/create-or-update-access-dialog.html @@ -374,7 +374,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 201,205 + 218,222 apps/client/src/app/pages/register/show-access-token-dialog/show-access-token-dialog.html @@ -390,7 +390,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 161 + 173 apps/client/src/app/pages/account/create-or-update-access-dialog/create-or-update-access-dialog.html @@ -402,7 +402,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 208,213 + 225,230 @@ -412,6 +412,14 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html 60 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 61 + + + libs/ui/src/lib/holdings-table/holdings-table.component.html + 47 + Activity Count @@ -434,7 +442,7 @@ Gegevens verzamelen apps/client/src/app/components/admin-market-data/admin-market-data.html - 139 + 155 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -446,7 +454,7 @@ Voeg een valuta toe: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 104 + 106 @@ -454,7 +462,7 @@ Wilt u deze coupon echt verwijderen? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 118 + 120 @@ -462,7 +470,7 @@ Wilt u deze valuta echt verwijderen? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 131 + 133 @@ -470,7 +478,7 @@ Wilt u echt de cache legen? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 148 + 150 @@ -478,7 +486,7 @@ Stel uw systeemboodschap in: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 171 + 180 @@ -502,7 +510,7 @@ Verzamel recente gegevens apps/client/src/app/components/admin-market-data/admin-market-data.html - 115 + 131 @@ -510,7 +518,7 @@ Alle gegevens verzamelen apps/client/src/app/components/admin-market-data/admin-market-data.html - 118 + 134 @@ -518,11 +526,11 @@ Verzamel profielgegevens apps/client/src/app/components/admin-market-data/admin-market-data.html - 121 + 137 apps/client/src/app/components/admin-market-data/admin-market-data.html - 145 + 161 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -550,7 +558,7 @@ Systeembericht apps/client/src/app/components/admin-overview/admin-overview.html - 86 + 106 @@ -558,7 +566,7 @@ Bericht instellen apps/client/src/app/components/admin-overview/admin-overview.html - 108 + 128 @@ -566,7 +574,7 @@ Alleen lezen apps/client/src/app/components/admin-overview/admin-overview.html - 113 + 96 @@ -574,7 +582,7 @@ Coupons apps/client/src/app/components/admin-overview/admin-overview.html - 126 + 136 @@ -582,7 +590,7 @@ Toevoegen apps/client/src/app/components/admin-overview/admin-overview.html - 161 + 171 @@ -590,7 +598,7 @@ Huishouding apps/client/src/app/components/admin-overview/admin-overview.html - 168 + 178 @@ -598,7 +606,7 @@ Cache legen apps/client/src/app/components/admin-overview/admin-overview.html - 172 + 182 @@ -810,7 +818,7 @@ Aanmelden apps/client/src/app/components/header/header.component.ts - 112 + 118 apps/client/src/app/pages/webauthn/webauthn-page-routing.module.ts @@ -822,7 +830,7 @@ Oeps! Onjuiste beveiligingstoken. apps/client/src/app/components/header/header.component.ts - 126 + 132 @@ -1106,7 +1114,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 184,186 + 201,203 @@ -1121,8 +1129,8 @@ Allocation Toewijzing - apps/client/src/app/components/positions-table/positions-table.component.html - 72 + libs/ui/src/lib/holdings-table/holdings-table.component.html + 95 @@ -1137,16 +1145,16 @@ 57 - apps/client/src/app/components/positions-table/positions-table.component.html - 91 + libs/ui/src/lib/holdings-table/holdings-table.component.html + 115 Show all Toon alle - apps/client/src/app/components/positions-table/positions-table.component.html - 137 + libs/ui/src/lib/holdings-table/holdings-table.component.html + 171 @@ -1338,7 +1346,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 286 + 301 @@ -1514,7 +1522,7 @@ Valuta apps/client/src/app/components/accounts-table/accounts-table.component.html - 46 + 48 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1526,7 +1534,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 113 + 123 @@ -1534,7 +1542,7 @@ Geldbalans apps/client/src/app/components/accounts-table/accounts-table.component.html - 100 + 112 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1550,7 +1558,7 @@ apps/client/src/app/components/accounts-table/accounts-table.component.html - 58 + 65 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1730,7 +1738,7 @@ Tijdlijn investeringen apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 142 + 143 @@ -1870,7 +1878,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 134 + 144 @@ -1882,7 +1890,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 163 + 173 @@ -1892,17 +1900,25 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html 131,132 + + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html + 148,149 + libs/ui/src/lib/activities-table/activities-table.component.html - 192 + 202 Note Opmerking + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 153 + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 140,143 + 157,160 @@ -1922,7 +1938,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 154,156 + 171,173 @@ -2082,7 +2098,7 @@ Ontwerp libs/ui/src/lib/activities-table/activities-table.component.html - 99 + 103 @@ -2090,7 +2106,7 @@ Activiteiten importeren libs/ui/src/lib/activities-table/activities-table.component.html - 323 + 367 @@ -2098,7 +2114,7 @@ Activiteiten exporteren libs/ui/src/lib/activities-table/activities-table.component.html - 333 + 377 @@ -2106,7 +2122,7 @@ Concepten exporteren als ICS libs/ui/src/lib/activities-table/activities-table.component.html - 343 + 387 @@ -2114,7 +2130,7 @@ Kloon libs/ui/src/lib/activities-table/activities-table.component.html - 373 + 408 @@ -2122,7 +2138,7 @@ Concepten exporteren als ICS libs/ui/src/lib/activities-table/activities-table.component.html - 381 + 416 @@ -2130,7 +2146,7 @@ Wilt u deze activiteit echt verwijderen? libs/ui/src/lib/activities-table/activities-table.component.ts - 147 + 149 @@ -2286,7 +2302,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 169,171 + 186,188 @@ -2364,10 +2380,6 @@ First Buy Date Eerste aankoopdatum - - apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 61 - apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html 129 @@ -2376,10 +2388,6 @@ Transactions Transacties - - apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 70 - apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html 138 @@ -2421,8 +2429,12 @@ Deposit Storting - apps/client/src/app/components/investment-chart/investment-chart.component.ts - 156 + apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts + 38 + + + apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts + 48 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts @@ -2442,7 +2454,7 @@ Maandelijks apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 41 + 44 @@ -2502,7 +2514,7 @@ Filter op rekening, valuta, symbool of type... libs/ui/src/lib/activities-table/activities-table.component.ts - 319 + 321 @@ -2634,7 +2646,7 @@ Total Amount apps/client/src/app/components/investment-chart/investment-chart.component.ts - 177 + 178 @@ -2650,7 +2662,7 @@ Spaarquote apps/client/src/app/components/investment-chart/investment-chart.component.ts - 226 + 230 @@ -2674,7 +2686,7 @@ Symbol libs/ui/src/lib/i18n.ts - 8 + 9 @@ -2682,7 +2694,7 @@ Tag libs/ui/src/lib/i18n.ts - 9 + 10 @@ -2690,7 +2702,7 @@ Cash libs/ui/src/lib/i18n.ts - 12 + 13 @@ -2698,7 +2710,7 @@ Commodity libs/ui/src/lib/i18n.ts - 13 + 14 @@ -2706,7 +2718,7 @@ Equity libs/ui/src/lib/i18n.ts - 14 + 15 @@ -2714,7 +2726,7 @@ Fixed Income libs/ui/src/lib/i18n.ts - 15 + 16 @@ -2722,7 +2734,7 @@ Real Estate libs/ui/src/lib/i18n.ts - 16 + 17 @@ -2730,7 +2742,7 @@ Bond libs/ui/src/lib/i18n.ts - 19 + 20 @@ -2738,7 +2750,7 @@ Cryptocurrency libs/ui/src/lib/i18n.ts - 20 + 21 @@ -2746,7 +2758,7 @@ ETF libs/ui/src/lib/i18n.ts - 21 + 22 @@ -2754,7 +2766,7 @@ Mutual Fund libs/ui/src/lib/i18n.ts - 22 + 23 @@ -2762,7 +2774,7 @@ Precious Metal libs/ui/src/lib/i18n.ts - 23 + 24 @@ -2770,7 +2782,7 @@ Private Equity libs/ui/src/lib/i18n.ts - 24 + 25 @@ -2778,7 +2790,7 @@ Stock libs/ui/src/lib/i18n.ts - 25 + 26 @@ -2786,7 +2798,7 @@ Emergency Fund libs/ui/src/lib/i18n.ts - 6 + 7 @@ -2794,7 +2806,7 @@ Other libs/ui/src/lib/i18n.ts - 7 + 8 libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts @@ -2818,7 +2830,7 @@ North America libs/ui/src/lib/i18n.ts - 31 + 32 @@ -2826,7 +2838,7 @@ Africa libs/ui/src/lib/i18n.ts - 28 + 29 @@ -2834,7 +2846,7 @@ Asia libs/ui/src/lib/i18n.ts - 29 + 30 @@ -2842,7 +2854,7 @@ Europe libs/ui/src/lib/i18n.ts - 30 + 31 @@ -2850,7 +2862,7 @@ Oceania libs/ui/src/lib/i18n.ts - 32 + 33 @@ -2858,7 +2870,7 @@ South America libs/ui/src/lib/i18n.ts - 33 + 34 @@ -2925,6 +2937,38 @@ 142 + + Dividend + Dividend + + apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts + 34 + + + + Dividend Timeline + Dividend Timeline + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 180 + + + + Asset Sub Class + Activa Subklasse + + libs/ui/src/lib/i18n.ts + 6 + + + + User Signup + User Signup + + apps/client/src/app/components/admin-overview/admin-overview.html + 86 + + diff --git a/apps/client/src/locales/messages.xlf b/apps/client/src/locales/messages.xlf index a7ffb72aa..3feb9cb12 100644 --- a/apps/client/src/locales/messages.xlf +++ b/apps/client/src/locales/messages.xlf @@ -83,7 +83,11 @@ apps/client/src/app/components/accounts-table/accounts-table.component.html - 81 + 93 + + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 70 apps/client/src/app/components/admin-users/admin-users.html @@ -102,11 +106,7 @@ Name apps/client/src/app/components/accounts-table/accounts-table.component.html - 21 - - - apps/client/src/app/components/positions-table/positions-table.component.html - 36 + 22 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -116,12 +116,20 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html 70,72 + + libs/ui/src/lib/activities-table/activities-table.component.html + 93 + + + libs/ui/src/lib/holdings-table/holdings-table.component.html + 28 + Total apps/client/src/app/components/accounts-table/accounts-table.component.html - 36 + 38 libs/ui/src/lib/activities-table/activities-table.component.html @@ -132,60 +140,60 @@ Value apps/client/src/app/components/accounts-table/accounts-table.component.html - 135 + 147 apps/client/src/app/components/accounts-table/accounts-table.component.html - 170 + 182 - apps/client/src/app/components/positions-table/positions-table.component.html - 52 + libs/ui/src/lib/activities-table/activities-table.component.html + 235 libs/ui/src/lib/activities-table/activities-table.component.html - 225 + 270 - libs/ui/src/lib/activities-table/activities-table.component.html - 260 + libs/ui/src/lib/holdings-table/holdings-table.component.html + 71 Edit apps/client/src/app/components/accounts-table/accounts-table.component.html - 212 + 224 libs/ui/src/lib/activities-table/activities-table.component.html - 369 + 404 Delete apps/client/src/app/components/accounts-table/accounts-table.component.html - 220 + 232 apps/client/src/app/components/admin-market-data/admin-market-data.html - 152 + 168 apps/client/src/app/components/admin-users/admin-users.html - 87 + 88 libs/ui/src/lib/activities-table/activities-table.component.html - 385 + 420 Do you really want to delete this account? apps/client/src/app/components/accounts-table/accounts-table.component.ts - 79 + 81 @@ -205,14 +213,6 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html 24 - - apps/client/src/app/components/positions-table/positions-table.component.html - 22 - - - libs/ui/src/lib/activities-table/activities-table.component.html - 88 - Data Source @@ -333,7 +333,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 154 + 166 apps/client/src/app/pages/account/create-or-update-access-dialog/create-or-update-access-dialog.html @@ -345,7 +345,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 201,205 + 218,222 apps/client/src/app/pages/register/show-access-token-dialog/show-access-token-dialog.html @@ -360,7 +360,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 161 + 173 apps/client/src/app/pages/account/create-or-update-access-dialog/create-or-update-access-dialog.html @@ -372,7 +372,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 208,213 + 225,230 @@ -381,6 +381,14 @@ apps/client/src/app/components/admin-market-data/admin-market-data.html 60 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 61 + + + libs/ui/src/lib/holdings-table/holdings-table.component.html + 47 + Activity Count @@ -400,7 +408,7 @@ Gather Data apps/client/src/app/components/admin-market-data/admin-market-data.html - 139 + 155 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -411,35 +419,35 @@ Please add a currency: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 104 + 106 Do you really want to delete this coupon? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 118 + 120 Do you really want to delete this currency? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 131 + 133 Do you really want to flush the cache? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 148 + 150 Please set your system message: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 171 + 180 @@ -460,25 +468,25 @@ Gather Recent Data apps/client/src/app/components/admin-market-data/admin-market-data.html - 115 + 131 Gather All Data apps/client/src/app/components/admin-market-data/admin-market-data.html - 118 + 134 Gather Profile Data apps/client/src/app/components/admin-market-data/admin-market-data.html - 121 + 137 apps/client/src/app/components/admin-market-data/admin-market-data.html - 145 + 161 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -503,49 +511,49 @@ System Message apps/client/src/app/components/admin-overview/admin-overview.html - 86 + 106 Set Message apps/client/src/app/components/admin-overview/admin-overview.html - 108 + 128 Read-only Mode apps/client/src/app/components/admin-overview/admin-overview.html - 113 + 96 Coupons apps/client/src/app/components/admin-overview/admin-overview.html - 126 + 136 Add apps/client/src/app/components/admin-overview/admin-overview.html - 161 + 171 Housekeeping apps/client/src/app/components/admin-overview/admin-overview.html - 168 + 178 Flush Cache apps/client/src/app/components/admin-overview/admin-overview.html - 172 + 182 @@ -737,7 +745,7 @@ Sign in apps/client/src/app/components/header/header.component.ts - 112 + 118 apps/client/src/app/pages/webauthn/webauthn-page-routing.module.ts @@ -748,7 +756,7 @@ Oops! Incorrect Security Token. apps/client/src/app/components/header/header.component.ts - 126 + 132 @@ -1002,7 +1010,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 184,186 + 201,203 @@ -1015,8 +1023,8 @@ Allocation - apps/client/src/app/components/positions-table/positions-table.component.html - 72 + libs/ui/src/lib/holdings-table/holdings-table.component.html + 95 @@ -1030,15 +1038,15 @@ 57 - apps/client/src/app/components/positions-table/positions-table.component.html - 91 + libs/ui/src/lib/holdings-table/holdings-table.component.html + 115 Show all - apps/client/src/app/components/positions-table/positions-table.component.html - 137 + libs/ui/src/lib/holdings-table/holdings-table.component.html + 171 @@ -1208,7 +1216,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 286 + 301 @@ -1362,7 +1370,7 @@ Currency apps/client/src/app/components/accounts-table/accounts-table.component.html - 46 + 48 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1374,14 +1382,14 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 113 + 123 Cash Balance apps/client/src/app/components/accounts-table/accounts-table.component.html - 100 + 112 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1396,7 +1404,7 @@ apps/client/src/app/components/accounts-table/accounts-table.component.html - 58 + 65 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1555,7 +1563,7 @@ Investment Timeline apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 142 + 143 @@ -1679,7 +1687,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 134 + 144 @@ -1690,7 +1698,7 @@ libs/ui/src/lib/activities-table/activities-table.component.html - 163 + 173 @@ -1699,16 +1707,24 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html 131,132 + + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html + 148,149 + libs/ui/src/lib/activities-table/activities-table.component.html - 192 + 202 Note + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 153 + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 140,143 + 157,160 @@ -1727,7 +1743,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 154,156 + 171,173 @@ -1868,49 +1884,49 @@ Draft libs/ui/src/lib/activities-table/activities-table.component.html - 99 + 103 Import Activities libs/ui/src/lib/activities-table/activities-table.component.html - 323 + 367 Export Activities libs/ui/src/lib/activities-table/activities-table.component.html - 333 + 377 Export Drafts as ICS libs/ui/src/lib/activities-table/activities-table.component.html - 343 + 387 Clone libs/ui/src/lib/activities-table/activities-table.component.html - 373 + 408 Export Draft as ICS libs/ui/src/lib/activities-table/activities-table.component.html - 381 + 416 Do you really want to delete this activity? libs/ui/src/lib/activities-table/activities-table.component.ts - 147 + 149 @@ -2049,7 +2065,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 169,171 + 186,188 @@ -2119,10 +2135,6 @@ First Buy Date - - apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 61 - apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html 129 @@ -2130,10 +2142,6 @@ Transactions - - apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 70 - apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html 138 @@ -2170,8 +2178,12 @@ Deposit - apps/client/src/app/components/investment-chart/investment-chart.component.ts - 156 + apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts + 38 + + + apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts + 48 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts @@ -2189,7 +2201,7 @@ Monthly apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 41 + 44 @@ -2242,7 +2254,7 @@ Filter by account, currency, symbol or type... libs/ui/src/lib/activities-table/activities-table.component.ts - 319 + 321 @@ -2358,7 +2370,7 @@ Total Amount apps/client/src/app/components/investment-chart/investment-chart.component.ts - 177 + 178 @@ -2372,42 +2384,42 @@ Savings Rate apps/client/src/app/components/investment-chart/investment-chart.component.ts - 226 + 230 Precious Metal libs/ui/src/lib/i18n.ts - 23 + 24 Tag libs/ui/src/lib/i18n.ts - 9 + 10 Equity libs/ui/src/lib/i18n.ts - 14 + 15 Real Estate libs/ui/src/lib/i18n.ts - 16 + 17 Cryptocurrency libs/ui/src/lib/i18n.ts - 20 + 21 @@ -2421,14 +2433,14 @@ Stock libs/ui/src/lib/i18n.ts - 25 + 26 Private Equity libs/ui/src/lib/i18n.ts - 24 + 25 @@ -2442,49 +2454,49 @@ Mutual Fund libs/ui/src/lib/i18n.ts - 22 + 23 Cash libs/ui/src/lib/i18n.ts - 12 + 13 Symbol libs/ui/src/lib/i18n.ts - 8 + 9 Commodity libs/ui/src/lib/i18n.ts - 13 + 14 Bond libs/ui/src/lib/i18n.ts - 19 + 20 ETF libs/ui/src/lib/i18n.ts - 21 + 22 Fixed Income libs/ui/src/lib/i18n.ts - 15 + 16 @@ -2502,14 +2514,14 @@ Emergency Fund libs/ui/src/lib/i18n.ts - 6 + 7 Other libs/ui/src/lib/i18n.ts - 7 + 8 libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts @@ -2520,42 +2532,42 @@ North America libs/ui/src/lib/i18n.ts - 31 + 32 Africa libs/ui/src/lib/i18n.ts - 28 + 29 Oceania libs/ui/src/lib/i18n.ts - 32 + 33 Asia libs/ui/src/lib/i18n.ts - 29 + 30 South America libs/ui/src/lib/i18n.ts - 33 + 34 Europe libs/ui/src/lib/i18n.ts - 30 + 31 @@ -2615,6 +2627,34 @@ 22 + + Dividend Timeline + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 180 + + + + Asset Sub Class + + libs/ui/src/lib/i18n.ts + 6 + + + + Dividend + + apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts + 34 + + + + User Signup + + apps/client/src/app/components/admin-overview/admin-overview.html + 86 + + diff --git a/libs/common/src/lib/config.ts b/libs/common/src/lib/config.ts index 1389200a6..7b34aaf33 100644 --- a/libs/common/src/lib/config.ts +++ b/libs/common/src/lib/config.ts @@ -74,6 +74,7 @@ export const PROPERTY_BENCHMARKS = 'BENCHMARKS'; export const PROPERTY_COUPONS = 'COUPONS'; export const PROPERTY_CURRENCIES = 'CURRENCIES'; export const PROPERTY_IS_READ_ONLY_MODE = 'IS_READ_ONLY_MODE'; +export const PROPERTY_IS_USER_SIGNUP_ENABLED = 'IS_USER_SIGNUP_ENABLED'; export const PROPERTY_SLACK_COMMUNITY_USERS = 'SLACK_COMMUNITY_USERS'; export const PROPERTY_STRIPE_CONFIG = 'STRIPE_CONFIG'; export const PROPERTY_SYSTEM_MESSAGE = 'SYSTEM_MESSAGE'; diff --git a/libs/common/src/lib/interfaces/enhanced-symbol-profile.interface.ts b/libs/common/src/lib/interfaces/enhanced-symbol-profile.interface.ts index 499e638a4..d2053bb7c 100644 --- a/libs/common/src/lib/interfaces/enhanced-symbol-profile.interface.ts +++ b/libs/common/src/lib/interfaces/enhanced-symbol-profile.interface.ts @@ -13,6 +13,7 @@ export interface EnhancedSymbolProfile { createdAt: Date; currency: string | null; dataSource: DataSource; + dateOfFirstActivity?: Date; id: string; name: string | null; scraperConfiguration?: ScraperConfiguration | null; diff --git a/libs/common/src/lib/interfaces/index.ts b/libs/common/src/lib/interfaces/index.ts index ef93845c5..a8ff96e0f 100644 --- a/libs/common/src/lib/interfaces/index.ts +++ b/libs/common/src/lib/interfaces/index.ts @@ -19,6 +19,7 @@ import { InfoItem } from './info-item.interface'; import { LineChartItem } from './line-chart-item.interface'; import { PortfolioChart } from './portfolio-chart.interface'; import { PortfolioDetails } from './portfolio-details.interface'; +import { PortfolioDividends } from './portfolio-dividends.interface'; import { PortfolioInvestments } from './portfolio-investments.interface'; import { PortfolioItem } from './portfolio-item.interface'; import { PortfolioOverview } from './portfolio-overview.interface'; @@ -31,6 +32,7 @@ import { PortfolioSummary } from './portfolio-summary.interface'; import { Position } from './position.interface'; import { BenchmarkResponse } from './responses/benchmark-response.interface'; import { ResponseError } from './responses/errors.interface'; +import { ImportResponse } from './responses/import-response.interface'; import { OAuthResponse } from './responses/oauth-response.interface'; import { PortfolioPerformanceResponse } from './responses/portfolio-performance-response.interface'; import { ScraperConfiguration } from './scraper-configuration.interface'; @@ -57,11 +59,13 @@ export { Filter, FilterGroup, HistoricalDataItem, + ImportResponse, InfoItem, LineChartItem, OAuthResponse, PortfolioChart, PortfolioDetails, + PortfolioDividends, PortfolioInvestments, PortfolioItem, PortfolioOverview, diff --git a/libs/common/src/lib/interfaces/portfolio-dividends.interface.ts b/libs/common/src/lib/interfaces/portfolio-dividends.interface.ts new file mode 100644 index 000000000..585c46bb7 --- /dev/null +++ b/libs/common/src/lib/interfaces/portfolio-dividends.interface.ts @@ -0,0 +1,5 @@ +import { InvestmentItem } from './investment-item.interface'; + +export interface PortfolioDividends { + dividends: InvestmentItem[]; +} diff --git a/libs/common/src/lib/interfaces/portfolio-position.interface.ts b/libs/common/src/lib/interfaces/portfolio-position.interface.ts index 703d6a6a4..c0a4288d5 100644 --- a/libs/common/src/lib/interfaces/portfolio-position.interface.ts +++ b/libs/common/src/lib/interfaces/portfolio-position.interface.ts @@ -12,6 +12,7 @@ export interface PortfolioPosition { countries: Country[]; currency: string; dataSource: DataSource; + dateOfFirstActivity: Date; exchange?: string; grossPerformance: number; grossPerformancePercent: number; diff --git a/libs/common/src/lib/interfaces/portfolio-public-details.interface.ts b/libs/common/src/lib/interfaces/portfolio-public-details.interface.ts index 6ecb1469a..52dddae3c 100644 --- a/libs/common/src/lib/interfaces/portfolio-public-details.interface.ts +++ b/libs/common/src/lib/interfaces/portfolio-public-details.interface.ts @@ -9,6 +9,8 @@ export interface PortfolioPublicDetails { | 'allocationCurrent' | 'countries' | 'currency' + | 'dataSource' + | 'dateOfFirstActivity' | 'markets' | 'name' | 'netPerformancePercent' diff --git a/libs/common/src/lib/interfaces/responses/import-response.interface.ts b/libs/common/src/lib/interfaces/responses/import-response.interface.ts new file mode 100644 index 000000000..be2da9837 --- /dev/null +++ b/libs/common/src/lib/interfaces/responses/import-response.interface.ts @@ -0,0 +1,5 @@ +import { Activity } from '@ghostfolio/api/app/order/interfaces/activities.interface'; + +export interface ImportResponse { + activities: Activity[]; +} diff --git a/libs/ui/src/lib/activities-table/activities-table.component.html b/libs/ui/src/lib/activities-table/activities-table.component.html index e79096dff..0cab5d85c 100644 --- a/libs/ui/src/lib/activities-table/activities-table.component.html +++ b/libs/ui/src/lib/activities-table/activities-table.component.html @@ -101,26 +101,31 @@ - + - Symbol + Name
- - {{ element.SymbolProfile.name }} - - - {{ element.SymbolProfile.symbol | gfSymbol }} - - Draft +
+ {{ element.SymbolProfile.name }} + Draft +
+
+
+ {{ + element.SymbolProfile.symbol | gfSymbol + }}
diff --git a/libs/ui/src/lib/activities-table/activities-table.component.ts b/libs/ui/src/lib/activities-table/activities-table.component.ts index 41f8d9381..b30bc078a 100644 --- a/libs/ui/src/lib/activities-table/activities-table.component.ts +++ b/libs/ui/src/lib/activities-table/activities-table.component.ts @@ -44,7 +44,7 @@ export class ActivitiesTableComponent implements OnChanges, OnDestroy { @Input() multiselect = false; @Input() pageSize = DEFAULT_PAGE_SIZE; @Input() showActions: boolean; - @Input() showSymbolColumn = true; + @Input() showNameColumn = true; @Output() activityDeleted = new EventEmitter(); @Output() activityToClone = new EventEmitter(); @@ -107,7 +107,7 @@ export class ActivitiesTableComponent implements OnChanges, OnDestroy { 'count', 'date', 'type', - 'symbol', + 'nameWithSymbol', 'quantity', 'unitPrice', 'fee', @@ -119,9 +119,9 @@ export class ActivitiesTableComponent implements OnChanges, OnDestroy { 'actions' ]; - if (!this.showSymbolColumn) { + if (!this.showNameColumn) { this.displayedColumns = this.displayedColumns.filter((column) => { - return column !== 'symbol'; + return column !== 'nameWithSymbol'; }); } diff --git a/libs/ui/src/lib/holdings-table/holdings-table.component.html b/libs/ui/src/lib/holdings-table/holdings-table.component.html new file mode 100644 index 000000000..cc76cd687 --- /dev/null +++ b/libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -0,0 +1,184 @@ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + Name + +
+ {{ element.name }} +
+
+ {{ element.symbol }} +
+
+ First Activity + +
+ +
+
+ Value + +
+ +
+
+ Allocation + +
+ +
+
+ Performance + +
+ +
+
+
+ + + + + +
+ +
+ +
+ +
diff --git a/libs/ui/src/lib/holdings-table/holdings-table.component.scss b/libs/ui/src/lib/holdings-table/holdings-table.component.scss new file mode 100644 index 000000000..f0da6525f --- /dev/null +++ b/libs/ui/src/lib/holdings-table/holdings-table.component.scss @@ -0,0 +1,25 @@ +@import '~apps/client/src/styles/ghostfolio-style'; + +:host { + display: block; + + .holdings { + overflow-x: auto; + + .mat-table { + th { + ::ng-deep { + .mat-sort-header-container { + justify-content: inherit; + } + } + } + + .mat-row { + &.cursor-pointer { + cursor: pointer; + } + } + } + } +} diff --git a/apps/client/src/app/components/positions-table/positions-table.component.ts b/libs/ui/src/lib/holdings-table/holdings-table.component.ts similarity index 89% rename from apps/client/src/app/components/positions-table/positions-table.component.ts rename to libs/ui/src/lib/holdings-table/holdings-table.component.ts index acd76ef11..6a56a9565 100644 --- a/apps/client/src/app/components/positions-table/positions-table.component.ts +++ b/libs/ui/src/lib/holdings-table/holdings-table.component.ts @@ -19,12 +19,12 @@ import { AssetClass, Order as OrderModel } from '@prisma/client'; import { Subject, Subscription } from 'rxjs'; @Component({ - selector: 'gf-positions-table', changeDetection: ChangeDetectionStrategy.OnPush, - templateUrl: './positions-table.component.html', - styleUrls: ['./positions-table.component.scss'] + selector: 'gf-holdings-table', + styleUrls: ['./holdings-table.component.scss'], + templateUrl: './holdings-table.component.html' }) -export class PositionsTableComponent implements OnChanges, OnDestroy, OnInit { +export class HoldingsTableComponent implements OnChanges, OnDestroy, OnInit { @Input() baseCurrency: string; @Input() deviceType: string; @Input() hasPermissionToCreateActivity: boolean; @@ -56,7 +56,7 @@ export class PositionsTableComponent implements OnChanges, OnDestroy, OnInit { public ngOnInit() {} public ngOnChanges() { - this.displayedColumns = ['icon', 'symbol', 'name']; + this.displayedColumns = ['icon', 'nameWithSymbol', 'dateOfFirstActivity']; if (this.hasPermissionToShowValues) { this.displayedColumns.push('value'); diff --git a/apps/client/src/app/components/positions-table/positions-table.module.ts b/libs/ui/src/lib/holdings-table/holdings-table.module.ts similarity index 82% rename from apps/client/src/app/components/positions-table/positions-table.module.ts rename to libs/ui/src/lib/holdings-table/holdings-table.module.ts index e9be0932e..0986bd1d0 100644 --- a/apps/client/src/app/components/positions-table/positions-table.module.ts +++ b/libs/ui/src/lib/holdings-table/holdings-table.module.ts @@ -8,17 +8,17 @@ import { MatSortModule } from '@angular/material/sort'; import { MatTableModule } from '@angular/material/table'; import { RouterModule } from '@angular/router'; import { GfPositionDetailDialogModule } from '@ghostfolio/client/components/position/position-detail-dialog/position-detail-dialog.module'; +import { GfSymbolIconModule } from '@ghostfolio/client/components/symbol-icon/symbol-icon.module'; import { GfSymbolModule } from '@ghostfolio/client/pipes/symbol/symbol.module'; import { GfNoTransactionsInfoModule } from '@ghostfolio/ui/no-transactions-info'; import { GfValueModule } from '@ghostfolio/ui/value'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; -import { GfSymbolIconModule } from '../symbol-icon/symbol-icon.module'; -import { PositionsTableComponent } from './positions-table.component'; +import { HoldingsTableComponent } from './holdings-table.component'; @NgModule({ - declarations: [PositionsTableComponent], - exports: [PositionsTableComponent], + declarations: [HoldingsTableComponent], + exports: [HoldingsTableComponent], imports: [ CommonModule, GfNoTransactionsInfoModule, @@ -37,4 +37,4 @@ import { PositionsTableComponent } from './positions-table.component'; ], schemas: [CUSTOM_ELEMENTS_SCHEMA] }) -export class GfPositionsTableModule {} +export class GfHoldingsTableModule {} diff --git a/libs/ui/src/lib/i18n.ts b/libs/ui/src/lib/i18n.ts index e08fe1bc0..2c3dca8f9 100644 --- a/libs/ui/src/lib/i18n.ts +++ b/libs/ui/src/lib/i18n.ts @@ -3,6 +3,7 @@ import '@angular/localize/init'; const locales = { ACCOUNT: $localize`Account`, ASSET_CLASS: $localize`Asset Class`, + ASSET_SUB_CLASS: $localize`Asset Sub Class`, EMERGENCY_FUND: $localize`Emergency Fund`, OTHER: $localize`Other`, SYMBOL: $localize`Symbol`, diff --git a/libs/ui/src/lib/line-chart/line-chart.component.ts b/libs/ui/src/lib/line-chart/line-chart.component.ts index dc984314d..4fdeddbc7 100644 --- a/libs/ui/src/lib/line-chart/line-chart.component.ts +++ b/libs/ui/src/lib/line-chart/line-chart.component.ts @@ -212,9 +212,11 @@ export class LineChartComponent implements AfterViewInit, OnChanges, OnDestroy { }, scales: { x: { + border: { + color: `rgba(${getTextColor(this.colorScheme)}, 0.1)` + }, display: this.showXAxis, grid: { - borderColor: `rgba(${getTextColor(this.colorScheme)}, 0.1)`, color: `rgba(${getTextColor(this.colorScheme)}, 0.8)`, display: false }, @@ -225,9 +227,11 @@ export class LineChartComponent implements AfterViewInit, OnChanges, OnDestroy { type: 'time' }, y: { + border: { + color: `rgba(${getTextColor(this.colorScheme)}, 0.1)` + }, display: this.showYAxis, grid: { - borderColor: `rgba(${getTextColor(this.colorScheme)}, 0.1)`, color: `rgba(${getTextColor(this.colorScheme)}, 0.8)`, display: false }, diff --git a/package.json b/package.json index 33dc6e6ec..6d50de960 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "1.216.0", + "version": "1.220.0", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "scripts": { @@ -94,14 +94,14 @@ "bull": "4.8.5", "cache-manager": "3.4.3", "cache-manager-redis-store": "2.0.0", - "chart.js": "3.8.0", - "chartjs-adapter-date-fns": "2.0.0", - "chartjs-plugin-annotation": "2.0.0", - "chartjs-plugin-datalabels": "2.0.0", - "cheerio": "1.0.0-rc.6", + "chart.js": "4.0.1", + "chartjs-adapter-date-fns": "2.0.1", + "chartjs-plugin-annotation": "2.1.0", + "chartjs-plugin-datalabels": "2.2.0", + "cheerio": "1.0.0-rc.12", "class-transformer": "0.3.2", "class-validator": "0.13.1", - "color": "4.0.1", + "color": "4.2.3", "countries-list": "2.6.1", "countup.js": "2.0.7", "date-fns": "2.29.3", @@ -160,10 +160,10 @@ "@types/big.js": "6.1.6", "@types/bull": "3.15.9", "@types/cache-manager": "3.4.2", - "@types/color": "3.0.2", + "@types/color": "3.0.3", "@types/google-spreadsheet": "3.1.5", "@types/jest": "28.1.8", - "@types/lodash": "4.14.174", + "@types/lodash": "4.14.191", "@types/node": "18.7.1", "@types/papaparse": "5.2.6", "@types/passport-google-oauth20": "2.0.11", @@ -182,7 +182,7 @@ "jest-environment-jsdom": "28.1.1", "jest-preset-angular": "12.2.2", "nx": "15.0.13", - "prettier": "2.7.1", + "prettier": "2.8.1", "prettier-plugin-organize-attributes": "0.0.5", "replace-in-file": "6.3.5", "rimraf": "3.0.2", diff --git a/yarn.lock b/yarn.lock index 8eeb0b614..b14eecc57 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4749,10 +4749,10 @@ resolved "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz" integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== -"@types/color@3.0.2": - version "3.0.2" - resolved "https://registry.npmjs.org/@types/color/-/color-3.0.2.tgz" - integrity sha512-INiJl6sfNn8iyC5paxVzqiVUEj2boIlFki02uRTAkKwAj++7aAF+ZfEv/XrIeBa0XI/fTZuDHW8rEEcEVnON+Q== +"@types/color@3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/color/-/color-3.0.3.tgz#e6d8d72b7aaef4bb9fe80847c26c7c786191016d" + integrity sha512-X//qzJ3d3Zj82J9sC/C18ZY5f43utPbAJ6PhYt/M7uG6etcF6MRpKdN880KBy43B0BMzSfeT96MzrsNjFI3GbA== dependencies: "@types/color-convert" "*" @@ -4920,10 +4920,10 @@ dependencies: "@types/node" "*" -"@types/lodash@4.14.174": - version "4.14.174" - resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.174.tgz" - integrity sha512-KMBLT6+g9qrGXpDt7ohjWPUD34WA/jasrtjTEHStF0NPdEwJ1N9SZ+4GaMVDeuk/y0+X5j9xFm6mNiXS7UoaLQ== +"@types/lodash@4.14.191": + version "4.14.191" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.191.tgz#09511e7f7cba275acd8b419ddac8da9a6a79e2fa" + integrity sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ== "@types/lodash@^4.14.167": version "4.14.182" @@ -7338,53 +7338,55 @@ chardet@^0.7.0: resolved "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz" integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== -chart.js@3.8.0: - version "3.8.0" - resolved "https://registry.npmjs.org/chart.js/-/chart.js-3.8.0.tgz" - integrity sha512-cr8xhrXjLIXVLOBZPkBZVF6NDeiVIrPLHcMhnON7UufudL+CNeRrD+wpYanswlm8NpudMdrt3CHoLMQMxJhHRg== +chart.js@4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-4.0.1.tgz#93d5d50ac222a5b3b6ac7488e82e1553ac031592" + integrity sha512-5/8/9eBivwBZK81mKvmIwTb2Pmw4D/5h1RK9fBWZLLZ8mCJ+kfYNmV9rMrGoa5Hgy2/wVDBMLSUDudul2/9ihA== -chartjs-adapter-date-fns@2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/chartjs-adapter-date-fns/-/chartjs-adapter-date-fns-2.0.0.tgz" - integrity sha512-rmZINGLe+9IiiEB0kb57vH3UugAtYw33anRiw5kS2Tu87agpetDDoouquycWc9pRsKtQo5j+vLsYHyr8etAvFw== +chartjs-adapter-date-fns@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/chartjs-adapter-date-fns/-/chartjs-adapter-date-fns-2.0.1.tgz#3d007d4985391362fb15c96310fff8376a434bae" + integrity sha512-v3WV9rdnQ05ce3A0ZCjzUekJCAbfm6+3HqSoeY2BIkdMYZoYr/4T+ril1tZyDl869lz6xdNVMXejUFT9YKpw4A== -chartjs-plugin-annotation@2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/chartjs-plugin-annotation/-/chartjs-plugin-annotation-2.0.0.tgz" - integrity sha512-Gd8X+uaWuD63qHSf4R9SvFIdHbxmP1RBsKfdlQt7oFgsyDYjqP2y0WrbEs1UoE7OXJDm8lfZes2tQQNhEL/EZw== +chartjs-plugin-annotation@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/chartjs-plugin-annotation/-/chartjs-plugin-annotation-2.1.0.tgz#c43172d26ec8e7e3bc104932d1a1807bf0c46db7" + integrity sha512-wHxP6mBWrgdldAEbHM5nMaMJ3PuunXgiotVh8natosuZsEqpjU0ZeyvMTBwIkKXLSDncb3faLunl4BI89Vmj/g== -chartjs-plugin-datalabels@2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/chartjs-plugin-datalabels/-/chartjs-plugin-datalabels-2.0.0.tgz" - integrity sha512-WBsWihphzM0Y8fmQVm89+iy99mmgejmj5/jcsYqwxSioLRL/zqJ4Scv/eXq5ZqvG3TpojlGzZLeaOaSvDm7fwA== +chartjs-plugin-datalabels@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/chartjs-plugin-datalabels/-/chartjs-plugin-datalabels-2.2.0.tgz#369578e131d743c2e34b5fbe2d3f9335f6639b8f" + integrity sha512-14ZU30lH7n89oq+A4bWaJPnAG8a7ZTk7dKf48YAzMvJjQtjrgg5Dpk9f+LbjCF6bpx3RAGTeL13IXpKQYyRvlw== check-more-types@^2.24.0: version "2.24.0" resolved "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz" integrity sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA== -cheerio-select@^1.3.0: - version "1.6.0" - resolved "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.6.0.tgz" - integrity sha512-eq0GdBvxVFbqWgmCm7M3XGs1I8oLy/nExUnh6oLqmBditPO9AqQJrkslDpMun/hZ0yyTs8L0m85OHp4ho6Qm9g== - dependencies: - css-select "^4.3.0" - css-what "^6.0.1" - domelementtype "^2.2.0" - domhandler "^4.3.1" - domutils "^2.8.0" - -cheerio@1.0.0-rc.6: - version "1.0.0-rc.6" - resolved "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.6.tgz" - integrity sha512-hjx1XE1M/D5pAtMgvWwE21QClmAEeGHOIDfycgmndisdNgI6PE1cGRQkMGBcsbUbmEQyWu5PJLUcAOjtQS8DWw== +cheerio-select@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cheerio-select/-/cheerio-select-2.1.0.tgz#4d8673286b8126ca2a8e42740d5e3c4884ae21b4" + integrity sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g== dependencies: - cheerio-select "^1.3.0" - dom-serializer "^1.3.1" - domhandler "^4.1.0" - htmlparser2 "^6.1.0" - parse5 "^6.0.1" - parse5-htmlparser2-tree-adapter "^6.0.1" + boolbase "^1.0.0" + css-select "^5.1.0" + css-what "^6.1.0" + domelementtype "^2.3.0" + domhandler "^5.0.3" + domutils "^3.0.1" + +cheerio@1.0.0-rc.12: + version "1.0.0-rc.12" + resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.12.tgz#788bf7466506b1c6bf5fae51d24a2c4d62e47683" + integrity sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q== + dependencies: + cheerio-select "^2.1.0" + dom-serializer "^2.0.0" + domhandler "^5.0.3" + domutils "^3.0.1" + htmlparser2 "^8.0.1" + parse5 "^7.0.0" + parse5-htmlparser2-tree-adapter "^7.0.0" "chokidar@>=3.0.0 <4.0.0", chokidar@^3.0.0, chokidar@^3.4.1, chokidar@^3.4.2, chokidar@^3.5.1, chokidar@^3.5.3: version "3.5.3" @@ -7686,9 +7688,9 @@ color-name@^1.0.0, color-name@~1.1.4: resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -color-string@^1.6.0: +color-string@^1.9.0: version "1.9.1" - resolved "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4" integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg== dependencies: color-name "^1.0.0" @@ -7699,13 +7701,13 @@ color-support@^1.1.2, color-support@^1.1.3: resolved "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz" integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== -color@4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/color/-/color-4.0.1.tgz" - integrity sha512-rpZjOKN5O7naJxkH2Rx1sZzzBgaiWECc6BYXjeCE6kF0kcASJYbUq02u7JqIHwCb/j3NhV+QhRL2683aICeGZA== +color@4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/color/-/color-4.2.3.tgz#d781ecb5e57224ee43ea9627560107c0e0c6463a" + integrity sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A== dependencies: color-convert "^2.0.1" - color-string "^1.6.0" + color-string "^1.9.0" colord@^2.9.1: version "2.9.2" @@ -8220,7 +8222,7 @@ css-prefers-color-scheme@^6.0.3: resolved "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.3.tgz" integrity sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA== -css-select@^4.1.3, css-select@^4.2.0, css-select@^4.3.0: +css-select@^4.1.3, css-select@^4.2.0: version "4.3.0" resolved "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz" integrity sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ== @@ -8231,6 +8233,17 @@ css-select@^4.1.3, css-select@^4.2.0, css-select@^4.3.0: domutils "^2.8.0" nth-check "^2.0.1" +css-select@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-5.1.0.tgz#b8ebd6554c3637ccc76688804ad3f6a6fdaea8a6" + integrity sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg== + dependencies: + boolbase "^1.0.0" + css-what "^6.1.0" + domhandler "^5.0.2" + domutils "^3.0.1" + nth-check "^2.0.1" + css-selector-tokenizer@^0.7.1: version "0.7.3" resolved "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz" @@ -8247,7 +8260,7 @@ css-tree@^1.1.2, css-tree@^1.1.3: mdn-data "2.0.14" source-map "^0.6.1" -css-what@^6.0.1: +css-what@^6.0.1, css-what@^6.1.0: version "6.1.0" resolved "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz" integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw== @@ -9237,7 +9250,7 @@ dom-converter@^0.2.0: dependencies: utila "~0.4" -dom-serializer@^1.0.1, dom-serializer@^1.3.1: +dom-serializer@^1.0.1: version "1.4.1" resolved "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz" integrity sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag== @@ -9246,6 +9259,15 @@ dom-serializer@^1.0.1, dom-serializer@^1.3.1: domhandler "^4.2.0" entities "^2.0.0" +dom-serializer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-2.0.0.tgz#e41b802e1eedf9f6cae183ce5e622d789d7d8e53" + integrity sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg== + dependencies: + domelementtype "^2.3.0" + domhandler "^5.0.2" + entities "^4.2.0" + dom-walk@^0.1.0: version "0.1.2" resolved "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz" @@ -9256,7 +9278,7 @@ domain-browser@^1.1.1: resolved "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz" integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== -domelementtype@^2.0.1, domelementtype@^2.2.0: +domelementtype@^2.0.1, domelementtype@^2.2.0, domelementtype@^2.3.0: version "2.3.0" resolved "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz" integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== @@ -9268,13 +9290,20 @@ domexception@^4.0.0: dependencies: webidl-conversions "^7.0.0" -domhandler@^4.0.0, domhandler@^4.1.0, domhandler@^4.2.0, domhandler@^4.3.1: +domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.1: version "4.3.1" resolved "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz" integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ== dependencies: domelementtype "^2.2.0" +domhandler@^5.0.1, domhandler@^5.0.2, domhandler@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-5.0.3.tgz#cc385f7f751f1d1fc650c21374804254538c7d31" + integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w== + dependencies: + domelementtype "^2.3.0" + dompurify@2.3.8: version "2.3.8" resolved "https://registry.npmjs.org/dompurify/-/dompurify-2.3.8.tgz" @@ -9289,6 +9318,15 @@ domutils@^2.5.2, domutils@^2.8.0: domelementtype "^2.2.0" domhandler "^4.2.0" +domutils@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.0.1.tgz#696b3875238338cb186b6c0612bd4901c89a4f1c" + integrity sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q== + dependencies: + dom-serializer "^2.0.0" + domelementtype "^2.3.0" + domhandler "^5.0.1" + dot-case@^3.0.4: version "3.0.4" resolved "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz" @@ -9478,6 +9516,11 @@ entities@^2.0.0: resolved "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz" integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== +entities@^4.2.0, entities@^4.3.0, entities@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-4.4.0.tgz#97bdaba170339446495e653cfd2db78962900174" + integrity sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA== + env-paths@^2.2.0: version "2.2.1" resolved "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz" @@ -11591,6 +11634,16 @@ htmlparser2@^6.1.0: domutils "^2.5.2" entities "^2.0.0" +htmlparser2@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-8.0.1.tgz#abaa985474fcefe269bc761a779b544d7196d010" + integrity sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA== + dependencies: + domelementtype "^2.3.0" + domhandler "^5.0.2" + domutils "^3.0.1" + entities "^4.3.0" + http-cache-semantics@^4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz" @@ -15409,6 +15462,14 @@ parse5-htmlparser2-tree-adapter@^6.0.1: dependencies: parse5 "^6.0.1" +parse5-htmlparser2-tree-adapter@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz#23c2cc233bcf09bb7beba8b8a69d46b08c62c2f1" + integrity sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g== + dependencies: + domhandler "^5.0.2" + parse5 "^7.0.0" + parse5-sax-parser@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-6.0.1.tgz" @@ -15431,6 +15492,13 @@ parse5@^5.0.0: resolved "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz" integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug== +parse5@^7.0.0: + version "7.1.2" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.1.2.tgz#0736bebbfd77793823240a23b7fc5e010b7f8e32" + integrity sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw== + dependencies: + entities "^4.4.0" + parseurl@~1.3.2, parseurl@~1.3.3: version "1.3.3" resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz" @@ -16331,10 +16399,10 @@ prettier-plugin-organize-attributes@0.0.5: resolved "https://registry.npmjs.org/prettier-plugin-organize-attributes/-/prettier-plugin-organize-attributes-0.0.5.tgz" integrity sha512-dSts16q8wd+oq8Zwk5mwmYXo1aN3B+ZkEJqx/ar5fedNHdOvx7S4XDMH/pNK7rmBW0bPXkp/kJX5gAANsWzh3A== -prettier@2.7.1: - version "2.7.1" - resolved "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz" - integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== +prettier@2.8.1: + version "2.8.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.1.tgz#4e1fd11c34e2421bc1da9aea9bd8127cd0a35efc" + integrity sha512-lqGoSJBQNJidqCHE80vqZJHWHRFoNYsSpP9AjFhlhi9ODCJA541svILes/+/1GM3VaL/abZi7cpFzOpdR9UPKg== "prettier@>=2.2.1 <=2.3.0": version "2.3.0"