diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c9164e0a..2280752d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Moved the indicator for active filters from experimental to general availability + +## 2.89.0 - 2024-06-14 + +### Added + +- Extended the historical market data table with currencies preset by date and activities count in the admin control panel + +### Changed + +- Improved the date validation in the create, import and update activities endpoints - Improved the language localization for German (`de`) ## 2.88.0 - 2024-06-11 diff --git a/apps/api/src/app/admin/admin.service.ts b/apps/api/src/app/admin/admin.service.ts index 3323e775d..c061c996c 100644 --- a/apps/api/src/app/admin/admin.service.ts +++ b/apps/api/src/app/admin/admin.service.ts @@ -409,30 +409,49 @@ export class AdminService { by: ['dataSource', 'symbol'] }); - const marketData: AdminMarketDataItem[] = this.exchangeRateDataService - .getCurrencyPairs() - .map(({ dataSource, symbol }) => { - const marketDataItemCount = - marketDataItems.find((marketDataItem) => { - return ( - marketDataItem.dataSource === dataSource && - marketDataItem.symbol === symbol - ); - })?._count ?? 0; + const marketDataPromise: Promise[] = + this.exchangeRateDataService + .getCurrencyPairs() + .map(async ({ dataSource, symbol }) => { + const currency = symbol.replace(DEFAULT_CURRENCY, ''); + + const { _count, _min } = await this.prismaService.order.aggregate({ + _count: true, + _min: { + date: true + }, + where: { + SymbolProfile: { + currency + } + } + }); - return { - dataSource, - marketDataItemCount, - symbol, - assetClass: AssetClass.LIQUIDITY, - countriesCount: 0, - currency: symbol.replace(DEFAULT_CURRENCY, ''), - id: undefined, - name: symbol, - sectorsCount: 0 - }; - }); + const marketDataItemCount = + marketDataItems.find((marketDataItem) => { + return ( + marketDataItem.dataSource === dataSource && + marketDataItem.symbol === symbol + ); + })?._count ?? 0; + + return { + currency, + dataSource, + marketDataItemCount, + symbol, + activitiesCount: _count as number, + assetClass: AssetClass.LIQUIDITY, + assetSubClass: AssetSubClass.CASH, + countriesCount: 0, + date: _min.date, + id: undefined, + name: symbol, + sectorsCount: 0 + }; + }); + const marketData = await Promise.all(marketDataPromise); return { marketData, count: marketData.length }; } diff --git a/apps/api/src/app/order/create-order.dto.ts b/apps/api/src/app/order/create-order.dto.ts index 6d36f036a..72aba3a3b 100644 --- a/apps/api/src/app/order/create-order.dto.ts +++ b/apps/api/src/app/order/create-order.dto.ts @@ -1,3 +1,5 @@ +import { IsAfter1970Constraint } from '@ghostfolio/common/validator-constraints/is-after-1970'; + import { AssetClass, AssetSubClass, @@ -15,7 +17,8 @@ import { IsNumber, IsOptional, IsString, - Min + Min, + Validate } from 'class-validator'; import { isString } from 'lodash'; @@ -51,6 +54,7 @@ export class CreateOrderDto { dataSource?: DataSource; @IsISO8601() + @Validate(IsAfter1970Constraint) date: string; @IsNumber() diff --git a/apps/api/src/app/order/update-order.dto.ts b/apps/api/src/app/order/update-order.dto.ts index be3c2b6e5..2fd33b743 100644 --- a/apps/api/src/app/order/update-order.dto.ts +++ b/apps/api/src/app/order/update-order.dto.ts @@ -1,3 +1,5 @@ +import { IsAfter1970Constraint } from '@ghostfolio/common/validator-constraints/is-after-1970'; + import { AssetClass, AssetSubClass, @@ -14,7 +16,8 @@ import { IsNumber, IsOptional, IsString, - Min + Min, + Validate } from 'class-validator'; import { isString } from 'lodash'; @@ -49,6 +52,7 @@ export class UpdateOrderDto { dataSource: DataSource; @IsISO8601() + @Validate(IsAfter1970Constraint) date: string; @IsNumber() diff --git a/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts b/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts index 9d3bcc6c9..8ebf936a2 100644 --- a/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts +++ b/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts @@ -21,7 +21,7 @@ import { DateAdapter, MAT_DATE_LOCALE } from '@angular/material/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { AssetClass, AssetSubClass, Tag, Type } from '@prisma/client'; import { isUUID } from 'class-validator'; -import { isToday } from 'date-fns'; +import { isAfter, isToday } from 'date-fns'; import { EMPTY, Observable, Subject, lastValueFrom, of } from 'rxjs'; import { catchError, delay, map, startWith, takeUntil } from 'rxjs/operators'; @@ -426,6 +426,14 @@ export class CreateOrUpdateActivityDialog implements OnDestroy { }); } + public dateFilter(aDate: Date) { + if (!aDate) { + return true; + } + + return isAfter(aDate, new Date(0)); + } + public onAddTag(event: MatAutocompleteSelectedEvent) { this.activityForm.get('tags').setValue([ ...(this.activityForm.get('tags').value ?? []), diff --git a/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html b/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html index f57d63559..a3b960d82 100644 --- a/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html +++ b/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -157,7 +157,12 @@
Date - + - +
Discover Open Source Alternatives for Personal Finance Tools - Discover Open Source Alternatives for Personal Finance Tools + Descubra alternativas de software libre para herramientas de finanzas personales apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.html 4 @@ -4348,7 +4348,7 @@ Founded - Founded + Fundada apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 72 @@ -4356,7 +4356,7 @@ Origin - Origin + Origen apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 77 @@ -4364,7 +4364,7 @@ Region - Region + Región apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 82 @@ -4372,7 +4372,7 @@ Available in - Available in + Disponible en apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 87 @@ -4464,7 +4464,7 @@ Use anonymously - Use anonymously + Uso anónimo apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 148 @@ -4472,7 +4472,7 @@ Free Plan - Free Plan + Plan gratuito apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 167 @@ -4480,7 +4480,7 @@ Notes - Notes + Notas apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 201 @@ -4488,7 +4488,7 @@ Effortlessly track, analyze, and visualize your wealth with Ghostfolio. - Effortlessly track, analyze, and visualize your wealth with Ghostfolio. + Siga, analice y visualice su patrimonio sin esfuerzo con Ghostfolio. apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 227 @@ -4888,7 +4888,7 @@ Get Started - Get Started + Empezar apps/client/src/app/pages/landing/landing-page.html 41 @@ -5644,7 +5644,7 @@ Ready to take your investments to the next level? - Ready to take your investments to the next level? + ¿Listo para llevar sus inversiones al siguiente nivel? apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 223 @@ -5984,7 +5984,7 @@ Ghostfolio vs comparison table - Ghostfolio vs comparison table + Ghostfolio vs tabla comparativa apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 49 diff --git a/apps/client/src/locales/messages.fr.xlf b/apps/client/src/locales/messages.fr.xlf index 4921caeb1..53df9ea28 100644 --- a/apps/client/src/locales/messages.fr.xlf +++ b/apps/client/src/locales/messages.fr.xlf @@ -3687,7 +3687,7 @@ Get Started - Débuter + Démarrer apps/client/src/app/pages/landing/landing-page.html 438 @@ -4339,7 +4339,7 @@ Discover Open Source Alternatives for Personal Finance Tools - Discover Open Source Alternatives for Personal Finance Tools + Découvrez les alternatives Open Source pour les outils de finance personnelle apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.html 4 @@ -4347,7 +4347,7 @@ Founded - Founded + Fondée apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 72 @@ -4355,7 +4355,7 @@ Origin - Origin + L’origine apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 77 @@ -4363,7 +4363,7 @@ Region - Region + La région apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 82 @@ -4371,7 +4371,7 @@ Available in - Available in + Disponible en apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 87 @@ -4463,7 +4463,7 @@ Use anonymously - Use anonymously + Utilisation anonyme apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 148 @@ -4471,7 +4471,7 @@ Free Plan - Free Plan + Plan gratuit apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 167 @@ -4479,7 +4479,7 @@ Notes - Notes + Notes apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 201 @@ -4887,7 +4887,7 @@ Get Started - Get Started + Démarrer apps/client/src/app/pages/landing/landing-page.html 41 @@ -5651,7 +5651,7 @@ Get Started - Get Started + Démarrer apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 232 @@ -5983,7 +5983,7 @@ Ghostfolio vs comparison table - Ghostfolio vs comparison table + Ghostfolio vs tableau comparatif apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 49 diff --git a/apps/client/src/locales/messages.it.xlf b/apps/client/src/locales/messages.it.xlf index ce5e92498..dc0c7854b 100644 --- a/apps/client/src/locales/messages.it.xlf +++ b/apps/client/src/locales/messages.it.xlf @@ -5984,7 +5984,7 @@ Ghostfolio vs comparison table - Ghostfolio vs comparison table + Ghostfolio vs tabella di comparazione apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 49 diff --git a/apps/client/src/locales/messages.pt.xlf b/apps/client/src/locales/messages.pt.xlf index 02cfeca2d..fa981c351 100644 --- a/apps/client/src/locales/messages.pt.xlf +++ b/apps/client/src/locales/messages.pt.xlf @@ -4339,7 +4339,7 @@ Discover Open Source Alternatives for Personal Finance Tools - Discover Open Source Alternatives for Personal Finance Tools + Descubra alternativas de software livre para ferramentas de finanças pessoais apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.html 4 @@ -4347,7 +4347,7 @@ Founded - Founded + Fundada apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 72 @@ -4355,7 +4355,7 @@ Origin - Origin + Origem apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 77 @@ -4363,7 +4363,7 @@ Region - Region + Região apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 82 @@ -4371,7 +4371,7 @@ Available in - Available in + Disponível em apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 87 @@ -4463,7 +4463,7 @@ Use anonymously - Use anonymously + Utilizar anonimamente apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 148 @@ -4471,7 +4471,7 @@ Free Plan - Free Plan + Plano gratuito apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 167 @@ -4479,7 +4479,7 @@ Notes - Notes + Notas apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 201 @@ -4887,7 +4887,7 @@ Get Started - Get Started + Começar apps/client/src/app/pages/landing/landing-page.html 41 @@ -5651,7 +5651,7 @@ Get Started - Get Started + Começar apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 232 @@ -5983,7 +5983,7 @@ Ghostfolio vs comparison table - Ghostfolio vs comparison table + Ghostfolio vs tabela de comparação apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 49 diff --git a/apps/client/src/locales/messages.tr.xlf b/apps/client/src/locales/messages.tr.xlf index dcac786fe..1871686f4 100644 --- a/apps/client/src/locales/messages.tr.xlf +++ b/apps/client/src/locales/messages.tr.xlf @@ -4547,7 +4547,7 @@ Open Source Alternative to - için Açık Kaynak Alternatifi + Open Source Alternative to apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.html 42 @@ -4563,7 +4563,7 @@ Are you looking for an open source alternative to ? Ghostfolio is a powerful portfolio management tool that provides individuals with a comprehensive platform to track, analyze, and optimize their investments. Whether you are an experienced investor or just starting out, Ghostfolio offers an intuitive user interface and a wide range of functionalities to help you make informed decisions and take control of your financial future. - ? yerine Açık Kaynak Kodlu bir alternatif mi arıyorsunuz? Ghostfolio,kullanıcılara yatırımlarını izlemek, analiz ve optimize etmek için kapsamlı bir platform sunan güçlü bir portföy yönetim aracıdır. Deneyimli bir yatırımcı da olsanuz henüz başlamış da olsanız, Ghostfolio sezgileri güçlü bir kullanıcı arayüzü ile geniş spektrumlu bir fonksiyon seti sunarak bilgiye dayalı kararlar vermenizi ve finansal geleceğinizin kontrolünü elinize almanızı sağlar. + Are you looking for an open source alternative to ? Ghostfolio is a powerful portfolio management tool that provides individuals with a comprehensive platform to track, analyze, and optimize their investments. Whether you are an experienced investor or just starting out, Ghostfolio offers an intuitive user interface and a wide range of functionalities to help you make informed decisions and take control of your financial future. apps/client/src/app/pages/resources/personal-finance-tools/product-page.html 13 diff --git a/libs/common/src/lib/interfaces/admin-market-data.interface.ts b/libs/common/src/lib/interfaces/admin-market-data.interface.ts index 6f3a82a0b..d52ac03b9 100644 --- a/libs/common/src/lib/interfaces/admin-market-data.interface.ts +++ b/libs/common/src/lib/interfaces/admin-market-data.interface.ts @@ -6,13 +6,13 @@ export interface AdminMarketData { } export interface AdminMarketDataItem { - activitiesCount?: number; + activitiesCount: number; assetClass?: AssetClass; assetSubClass?: AssetSubClass; countriesCount: number; currency: string; dataSource: DataSource; - date?: Date; + date: Date; id: string; isBenchmark?: boolean; marketDataItemCount: number; diff --git a/libs/common/src/lib/validator-constraints/is-after-1970.ts b/libs/common/src/lib/validator-constraints/is-after-1970.ts new file mode 100644 index 000000000..3f5b7db0d --- /dev/null +++ b/libs/common/src/lib/validator-constraints/is-after-1970.ts @@ -0,0 +1,16 @@ +import { + ValidatorConstraint, + ValidatorConstraintInterface +} from 'class-validator'; +import { format, isAfter, parseISO } from 'date-fns'; + +@ValidatorConstraint({ name: 'isAfter1970' }) +export class IsAfter1970Constraint implements ValidatorConstraintInterface { + public defaultMessage() { + return `date must be after ${format(new Date(0), 'yyyy')}`; + } + + public validate(aDateString: string) { + return isAfter(parseISO(aDateString), new Date(0)); + } +} diff --git a/package.json b/package.json index 21621f3df..9e3fa7b73 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "2.88.0", + "version": "2.89.0", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "repository": "https://github.com/ghostfolio/ghostfolio", diff --git a/test/import/invalid-date-before-min.json b/test/import/invalid-date-before-min.json new file mode 100644 index 000000000..3040581b2 --- /dev/null +++ b/test/import/invalid-date-before-min.json @@ -0,0 +1,18 @@ +{ + "meta": { + "date": "2021-01-01T00:00:00.000Z", + "version": "dev" + }, + "activities": [ + { + "currency": "USD", + "dataSource": "YAHOO", + "date": "1960-01-01T00:00:00.000Z", + "fee": 0, + "quantity": 20, + "symbol": "AAPL", + "type": "BUY", + "unitPrice": 100.0 + } + ] +}