Browse Source

Merge branch 'main' into feature/move-active-filters-indicator-to-general-availability

pull/3485/head
Thomas Kaul 1 year ago
committed by GitHub
parent
commit
dc16a2d6b5
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 10
      CHANGELOG.md
  2. 25
      apps/api/src/app/admin/admin.service.ts
  3. 6
      apps/api/src/app/order/create-order.dto.ts
  4. 6
      apps/api/src/app/order/update-order.dto.ts
  5. 10
      apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts
  6. 7
      apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html
  7. 4
      apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.html
  8. 6
      apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.scss
  9. 24
      apps/client/src/locales/messages.es.xlf
  10. 24
      apps/client/src/locales/messages.fr.xlf
  11. 2
      apps/client/src/locales/messages.it.xlf
  12. 22
      apps/client/src/locales/messages.pt.xlf
  13. 4
      apps/client/src/locales/messages.tr.xlf
  14. 4
      libs/common/src/lib/interfaces/admin-market-data.interface.ts
  15. 16
      libs/common/src/lib/validator-constraints/is-after-1970.ts
  16. 2
      package.json
  17. 18
      test/import/invalid-date-before-min.json

10
CHANGELOG.md

@ -10,6 +10,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed ### Changed
- Moved the indicator for active filters from experimental to general availability - 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`) - Improved the language localization for German (`de`)
## 2.88.0 - 2024-06-11 ## 2.88.0 - 2024-06-11

25
apps/api/src/app/admin/admin.service.ts

@ -409,9 +409,24 @@ export class AdminService {
by: ['dataSource', 'symbol'] by: ['dataSource', 'symbol']
}); });
const marketData: AdminMarketDataItem[] = this.exchangeRateDataService const marketDataPromise: Promise<AdminMarketDataItem>[] =
this.exchangeRateDataService
.getCurrencyPairs() .getCurrencyPairs()
.map(({ dataSource, symbol }) => { .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
}
}
});
const marketDataItemCount = const marketDataItemCount =
marketDataItems.find((marketDataItem) => { marketDataItems.find((marketDataItem) => {
return ( return (
@ -421,18 +436,22 @@ export class AdminService {
})?._count ?? 0; })?._count ?? 0;
return { return {
currency,
dataSource, dataSource,
marketDataItemCount, marketDataItemCount,
symbol, symbol,
activitiesCount: _count as number,
assetClass: AssetClass.LIQUIDITY, assetClass: AssetClass.LIQUIDITY,
assetSubClass: AssetSubClass.CASH,
countriesCount: 0, countriesCount: 0,
currency: symbol.replace(DEFAULT_CURRENCY, ''), date: _min.date,
id: undefined, id: undefined,
name: symbol, name: symbol,
sectorsCount: 0 sectorsCount: 0
}; };
}); });
const marketData = await Promise.all(marketDataPromise);
return { marketData, count: marketData.length }; return { marketData, count: marketData.length };
} }

6
apps/api/src/app/order/create-order.dto.ts

@ -1,3 +1,5 @@
import { IsAfter1970Constraint } from '@ghostfolio/common/validator-constraints/is-after-1970';
import { import {
AssetClass, AssetClass,
AssetSubClass, AssetSubClass,
@ -15,7 +17,8 @@ import {
IsNumber, IsNumber,
IsOptional, IsOptional,
IsString, IsString,
Min Min,
Validate
} from 'class-validator'; } from 'class-validator';
import { isString } from 'lodash'; import { isString } from 'lodash';
@ -51,6 +54,7 @@ export class CreateOrderDto {
dataSource?: DataSource; dataSource?: DataSource;
@IsISO8601() @IsISO8601()
@Validate(IsAfter1970Constraint)
date: string; date: string;
@IsNumber() @IsNumber()

6
apps/api/src/app/order/update-order.dto.ts

@ -1,3 +1,5 @@
import { IsAfter1970Constraint } from '@ghostfolio/common/validator-constraints/is-after-1970';
import { import {
AssetClass, AssetClass,
AssetSubClass, AssetSubClass,
@ -14,7 +16,8 @@ import {
IsNumber, IsNumber,
IsOptional, IsOptional,
IsString, IsString,
Min Min,
Validate
} from 'class-validator'; } from 'class-validator';
import { isString } from 'lodash'; import { isString } from 'lodash';
@ -49,6 +52,7 @@ export class UpdateOrderDto {
dataSource: DataSource; dataSource: DataSource;
@IsISO8601() @IsISO8601()
@Validate(IsAfter1970Constraint)
date: string; date: string;
@IsNumber() @IsNumber()

10
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 { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { AssetClass, AssetSubClass, Tag, Type } from '@prisma/client'; import { AssetClass, AssetSubClass, Tag, Type } from '@prisma/client';
import { isUUID } from 'class-validator'; 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 { EMPTY, Observable, Subject, lastValueFrom, of } from 'rxjs';
import { catchError, delay, map, startWith, takeUntil } from 'rxjs/operators'; 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) { public onAddTag(event: MatAutocompleteSelectedEvent) {
this.activityForm.get('tags').setValue([ this.activityForm.get('tags').setValue([
...(this.activityForm.get('tags').value ?? []), ...(this.activityForm.get('tags').value ?? []),

7
apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html

@ -157,7 +157,12 @@
<div class="mb-3"> <div class="mb-3">
<mat-form-field appearance="outline" class="w-100"> <mat-form-field appearance="outline" class="w-100">
<mat-label i18n>Date</mat-label> <mat-label i18n>Date</mat-label>
<input formControlName="date" matInput [matDatepicker]="date" /> <input
formControlName="date"
matInput
[matDatepicker]="date"
[matDatepickerFilter]="dateFilter"
/>
<mat-datepicker-toggle class="mr-2" matSuffix [for]="date"> <mat-datepicker-toggle class="mr-2" matSuffix [for]="date">
<ion-icon <ion-icon
class="text-muted" class="text-muted"

4
apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.html

@ -23,11 +23,11 @@
track personalFinanceTool track personalFinanceTool
) { ) {
<mat-card appearance="outlined" class="mb-3"> <mat-card appearance="outlined" class="mb-3">
<mat-card-content> <mat-card-content class="p-0">
<div class="container p-0"> <div class="container p-0">
<div class="flex-nowrap no-gutters row"> <div class="flex-nowrap no-gutters row">
<a <a
class="d-flex overflow-hidden w-100" class="d-flex overflow-hidden p-3 w-100"
title="Compare Ghostfolio to {{ title="Compare Ghostfolio to {{
personalFinanceTool.name personalFinanceTool.name
}} - {{ personalFinanceTool.slogan }}" }} - {{ personalFinanceTool.slogan }}"

6
apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.scss

@ -12,6 +12,12 @@
} }
} }
} }
.mat-mdc-card {
&:hover {
border-color: var(--gf-theme-primary-500);
}
}
} }
:host-context(.is-dark-theme) { :host-context(.is-dark-theme) {

24
apps/client/src/locales/messages.es.xlf

@ -4340,7 +4340,7 @@
</trans-unit> </trans-unit>
<trans-unit id="d1db8b2ae4504dc216afb401317392fa0fca7d63" datatype="html"> <trans-unit id="d1db8b2ae4504dc216afb401317392fa0fca7d63" datatype="html">
<source> Discover Open Source Alternatives for Personal Finance Tools </source> <source> Discover Open Source Alternatives for Personal Finance Tools </source>
<target state="new"> Discover Open Source Alternatives for Personal Finance Tools </target> <target state="translated"> Descubra alternativas de software libre para herramientas de finanzas personales </target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.html</context>
<context context-type="linenumber">4</context> <context context-type="linenumber">4</context>
@ -4348,7 +4348,7 @@
</trans-unit> </trans-unit>
<trans-unit id="e174910a7abd2793d04bba1c3971a0c7fafd7b79" datatype="html"> <trans-unit id="e174910a7abd2793d04bba1c3971a0c7fafd7b79" datatype="html">
<source>Founded</source> <source>Founded</source>
<target state="new">Founded</target> <target state="translated">Fundada</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">72</context> <context context-type="linenumber">72</context>
@ -4356,7 +4356,7 @@
</trans-unit> </trans-unit>
<trans-unit id="950b5f04a2efd3f11c0f76418d5a4212381e792e" datatype="html"> <trans-unit id="950b5f04a2efd3f11c0f76418d5a4212381e792e" datatype="html">
<source>Origin</source> <source>Origin</source>
<target state="new">Origin</target> <target state="translated">Origen</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">77</context> <context context-type="linenumber">77</context>
@ -4364,7 +4364,7 @@
</trans-unit> </trans-unit>
<trans-unit id="2ae797460f17fe72086256ec5e2da35ddc6e1614" datatype="html"> <trans-unit id="2ae797460f17fe72086256ec5e2da35ddc6e1614" datatype="html">
<source>Region</source> <source>Region</source>
<target state="new">Region</target> <target state="translated">Región</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">82</context> <context context-type="linenumber">82</context>
@ -4372,7 +4372,7 @@
</trans-unit> </trans-unit>
<trans-unit id="c5a2349fd1775501aa7a16c423816a734b959db4" datatype="html"> <trans-unit id="c5a2349fd1775501aa7a16c423816a734b959db4" datatype="html">
<source> Available in </source> <source> Available in </source>
<target state="new"> Available in </target> <target state="translated"> Disponible en </target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">87</context> <context context-type="linenumber">87</context>
@ -4464,7 +4464,7 @@
</trans-unit> </trans-unit>
<trans-unit id="fbce449c2e3719c495e4e3ba0107df816b039ebe" datatype="html"> <trans-unit id="fbce449c2e3719c495e4e3ba0107df816b039ebe" datatype="html">
<source> Use anonymously </source> <source> Use anonymously </source>
<target state="new"> Use anonymously </target> <target state="translated"> Uso anónimo </target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">148</context> <context context-type="linenumber">148</context>
@ -4472,7 +4472,7 @@
</trans-unit> </trans-unit>
<trans-unit id="f37bf6923c7cffbb879c67fcb782950e28c431d0" datatype="html"> <trans-unit id="f37bf6923c7cffbb879c67fcb782950e28c431d0" datatype="html">
<source> Free Plan </source> <source> Free Plan </source>
<target state="new"> Free Plan </target> <target state="translated"> Plan gratuito </target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">167</context> <context context-type="linenumber">167</context>
@ -4480,7 +4480,7 @@
</trans-unit> </trans-unit>
<trans-unit id="fcde58253a4cfd52c228eebdae74e1be7a1ab714" datatype="html"> <trans-unit id="fcde58253a4cfd52c228eebdae74e1be7a1ab714" datatype="html">
<source>Notes</source> <source>Notes</source>
<target state="new">Notes</target> <target state="translated">Notas</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">201</context> <context context-type="linenumber">201</context>
@ -4488,7 +4488,7 @@
</trans-unit> </trans-unit>
<trans-unit id="47e58765787443fe08ef8ccc25a1419310e43b2a" datatype="html"> <trans-unit id="47e58765787443fe08ef8ccc25a1419310e43b2a" datatype="html">
<source> Effortlessly track, analyze, and visualize your wealth with Ghostfolio. </source> <source> Effortlessly track, analyze, and visualize your wealth with Ghostfolio. </source>
<target state="new"> Effortlessly track, analyze, and visualize your wealth with Ghostfolio. </target> <target state="translated"> Siga, analice y visualice su patrimonio sin esfuerzo con Ghostfolio. </target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">227</context> <context context-type="linenumber">227</context>
@ -4888,7 +4888,7 @@
</trans-unit> </trans-unit>
<trans-unit id="50fefcca3f8b7dd5a34141329118014a8c4b7d1b" datatype="html"> <trans-unit id="50fefcca3f8b7dd5a34141329118014a8c4b7d1b" datatype="html">
<source> Get Started </source> <source> Get Started </source>
<target state="new"> Get Started </target> <target state="translated"> Empezar </target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/landing/landing-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/landing/landing-page.html</context>
<context context-type="linenumber">41</context> <context context-type="linenumber">41</context>
@ -5644,7 +5644,7 @@
</trans-unit> </trans-unit>
<trans-unit id="c02f31906b9a50d3d126db14c2cbc2079d4ab499" datatype="html"> <trans-unit id="c02f31906b9a50d3d126db14c2cbc2079d4ab499" datatype="html">
<source> Ready to take your <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>investments<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/> to the <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>next level<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/>? </source> <source> Ready to take your <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>investments<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/> to the <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>next level<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/>? </source>
<target state="new"> Ready to take your <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>investments<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/> to the <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>next level<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/>? </target> <target state="translated"> ¿Listo para llevar sus <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>inversiones<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/> al <x id="START_TAG_STRONG" ctype="x-strong" equiv-text="&lt;strong&gt;"/>siguiente nivel<x id="CLOSE_TAG_STRONG" ctype="x-strong" equiv-text="&lt;/strong&gt;"/>? </target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">223</context> <context context-type="linenumber">223</context>
@ -5984,7 +5984,7 @@
</trans-unit> </trans-unit>
<trans-unit id="567d4a9cafe9790b401ebf3a5d74f7c51b46a7b5" datatype="html"> <trans-unit id="567d4a9cafe9790b401ebf3a5d74f7c51b46a7b5" datatype="html">
<source> Ghostfolio vs <x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> comparison table </source> <source> Ghostfolio vs <x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> comparison table </source>
<target state="new"> Ghostfolio vs <x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> comparison table </target> <target state="translated"> Ghostfolio vs <x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> tabla comparativa </target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">49</context> <context context-type="linenumber">49</context>

24
apps/client/src/locales/messages.fr.xlf

@ -3687,7 +3687,7 @@
</trans-unit> </trans-unit>
<trans-unit id="8491ac1eac9be4c3b013f8cc51fe7b801a3c4d7b" datatype="html"> <trans-unit id="8491ac1eac9be4c3b013f8cc51fe7b801a3c4d7b" datatype="html">
<source> Get Started </source> <source> Get Started </source>
<target state="translated"> Débuter </target> <target state="translated"> Démarrer </target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/landing/landing-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/landing/landing-page.html</context>
<context context-type="linenumber">438</context> <context context-type="linenumber">438</context>
@ -4339,7 +4339,7 @@
</trans-unit> </trans-unit>
<trans-unit id="d1db8b2ae4504dc216afb401317392fa0fca7d63" datatype="html"> <trans-unit id="d1db8b2ae4504dc216afb401317392fa0fca7d63" datatype="html">
<source> Discover Open Source Alternatives for Personal Finance Tools </source> <source> Discover Open Source Alternatives for Personal Finance Tools </source>
<target state="new"> Discover Open Source Alternatives for Personal Finance Tools </target> <target state="translated"> Découvrez les alternatives Open Source pour les outils de finance personnelle </target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.html</context>
<context context-type="linenumber">4</context> <context context-type="linenumber">4</context>
@ -4347,7 +4347,7 @@
</trans-unit> </trans-unit>
<trans-unit id="e174910a7abd2793d04bba1c3971a0c7fafd7b79" datatype="html"> <trans-unit id="e174910a7abd2793d04bba1c3971a0c7fafd7b79" datatype="html">
<source>Founded</source> <source>Founded</source>
<target state="new">Founded</target> <target state="translated">Fondée</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">72</context> <context context-type="linenumber">72</context>
@ -4355,7 +4355,7 @@
</trans-unit> </trans-unit>
<trans-unit id="950b5f04a2efd3f11c0f76418d5a4212381e792e" datatype="html"> <trans-unit id="950b5f04a2efd3f11c0f76418d5a4212381e792e" datatype="html">
<source>Origin</source> <source>Origin</source>
<target state="new">Origin</target> <target state="translated">L’origine</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">77</context> <context context-type="linenumber">77</context>
@ -4363,7 +4363,7 @@
</trans-unit> </trans-unit>
<trans-unit id="2ae797460f17fe72086256ec5e2da35ddc6e1614" datatype="html"> <trans-unit id="2ae797460f17fe72086256ec5e2da35ddc6e1614" datatype="html">
<source>Region</source> <source>Region</source>
<target state="new">Region</target> <target state="translated">La région</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">82</context> <context context-type="linenumber">82</context>
@ -4371,7 +4371,7 @@
</trans-unit> </trans-unit>
<trans-unit id="c5a2349fd1775501aa7a16c423816a734b959db4" datatype="html"> <trans-unit id="c5a2349fd1775501aa7a16c423816a734b959db4" datatype="html">
<source> Available in </source> <source> Available in </source>
<target state="new"> Available in </target> <target state="translated"> Disponible en </target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">87</context> <context context-type="linenumber">87</context>
@ -4463,7 +4463,7 @@
</trans-unit> </trans-unit>
<trans-unit id="fbce449c2e3719c495e4e3ba0107df816b039ebe" datatype="html"> <trans-unit id="fbce449c2e3719c495e4e3ba0107df816b039ebe" datatype="html">
<source> Use anonymously </source> <source> Use anonymously </source>
<target state="new"> Use anonymously </target> <target state="translated"> Utilisation anonyme </target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">148</context> <context context-type="linenumber">148</context>
@ -4471,7 +4471,7 @@
</trans-unit> </trans-unit>
<trans-unit id="f37bf6923c7cffbb879c67fcb782950e28c431d0" datatype="html"> <trans-unit id="f37bf6923c7cffbb879c67fcb782950e28c431d0" datatype="html">
<source> Free Plan </source> <source> Free Plan </source>
<target state="new"> Free Plan </target> <target state="translated"> Plan gratuit </target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">167</context> <context context-type="linenumber">167</context>
@ -4479,7 +4479,7 @@
</trans-unit> </trans-unit>
<trans-unit id="fcde58253a4cfd52c228eebdae74e1be7a1ab714" datatype="html"> <trans-unit id="fcde58253a4cfd52c228eebdae74e1be7a1ab714" datatype="html">
<source>Notes</source> <source>Notes</source>
<target state="new">Notes</target> <target state="translated">Notes</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">201</context> <context context-type="linenumber">201</context>
@ -4887,7 +4887,7 @@
</trans-unit> </trans-unit>
<trans-unit id="50fefcca3f8b7dd5a34141329118014a8c4b7d1b" datatype="html"> <trans-unit id="50fefcca3f8b7dd5a34141329118014a8c4b7d1b" datatype="html">
<source> Get Started </source> <source> Get Started </source>
<target state="new"> Get Started </target> <target state="translated"> Démarrer </target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/landing/landing-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/landing/landing-page.html</context>
<context context-type="linenumber">41</context> <context context-type="linenumber">41</context>
@ -5651,7 +5651,7 @@
</trans-unit> </trans-unit>
<trans-unit id="968ab39db7fbb2621ba4536940768e6b6ee9c71f" datatype="html"> <trans-unit id="968ab39db7fbb2621ba4536940768e6b6ee9c71f" datatype="html">
<source> Get Started </source> <source> Get Started </source>
<target state="new"> Get Started </target> <target state="translated"> Démarrer </target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">232</context> <context context-type="linenumber">232</context>
@ -5983,7 +5983,7 @@
</trans-unit> </trans-unit>
<trans-unit id="567d4a9cafe9790b401ebf3a5d74f7c51b46a7b5" datatype="html"> <trans-unit id="567d4a9cafe9790b401ebf3a5d74f7c51b46a7b5" datatype="html">
<source> Ghostfolio vs <x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> comparison table </source> <source> Ghostfolio vs <x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> comparison table </source>
<target state="new"> Ghostfolio vs <x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> comparison table </target> <target state="translated"> Ghostfolio vs <x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> tableau comparatif </target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">49</context> <context context-type="linenumber">49</context>

2
apps/client/src/locales/messages.it.xlf

@ -5984,7 +5984,7 @@
</trans-unit> </trans-unit>
<trans-unit id="567d4a9cafe9790b401ebf3a5d74f7c51b46a7b5" datatype="html"> <trans-unit id="567d4a9cafe9790b401ebf3a5d74f7c51b46a7b5" datatype="html">
<source> Ghostfolio vs <x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> comparison table </source> <source> Ghostfolio vs <x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> comparison table </source>
<target state="new"> Ghostfolio vs <x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> comparison table </target> <target state="translated"> Ghostfolio vs <x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> tabella di comparazione </target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">49</context> <context context-type="linenumber">49</context>

22
apps/client/src/locales/messages.pt.xlf

@ -4339,7 +4339,7 @@
</trans-unit> </trans-unit>
<trans-unit id="d1db8b2ae4504dc216afb401317392fa0fca7d63" datatype="html"> <trans-unit id="d1db8b2ae4504dc216afb401317392fa0fca7d63" datatype="html">
<source> Discover Open Source Alternatives for Personal Finance Tools </source> <source> Discover Open Source Alternatives for Personal Finance Tools </source>
<target state="new"> Discover Open Source Alternatives for Personal Finance Tools </target> <target state="translated"> Descubra alternativas de software livre para ferramentas de finanças pessoais </target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.html</context>
<context context-type="linenumber">4</context> <context context-type="linenumber">4</context>
@ -4347,7 +4347,7 @@
</trans-unit> </trans-unit>
<trans-unit id="e174910a7abd2793d04bba1c3971a0c7fafd7b79" datatype="html"> <trans-unit id="e174910a7abd2793d04bba1c3971a0c7fafd7b79" datatype="html">
<source>Founded</source> <source>Founded</source>
<target state="new">Founded</target> <target state="translated">Fundada</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">72</context> <context context-type="linenumber">72</context>
@ -4355,7 +4355,7 @@
</trans-unit> </trans-unit>
<trans-unit id="950b5f04a2efd3f11c0f76418d5a4212381e792e" datatype="html"> <trans-unit id="950b5f04a2efd3f11c0f76418d5a4212381e792e" datatype="html">
<source>Origin</source> <source>Origin</source>
<target state="new">Origin</target> <target state="translated">Origem</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">77</context> <context context-type="linenumber">77</context>
@ -4363,7 +4363,7 @@
</trans-unit> </trans-unit>
<trans-unit id="2ae797460f17fe72086256ec5e2da35ddc6e1614" datatype="html"> <trans-unit id="2ae797460f17fe72086256ec5e2da35ddc6e1614" datatype="html">
<source>Region</source> <source>Region</source>
<target state="new">Region</target> <target state="translated">Região</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">82</context> <context context-type="linenumber">82</context>
@ -4371,7 +4371,7 @@
</trans-unit> </trans-unit>
<trans-unit id="c5a2349fd1775501aa7a16c423816a734b959db4" datatype="html"> <trans-unit id="c5a2349fd1775501aa7a16c423816a734b959db4" datatype="html">
<source> Available in </source> <source> Available in </source>
<target state="new"> Available in </target> <target state="translated"> Disponível em </target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">87</context> <context context-type="linenumber">87</context>
@ -4463,7 +4463,7 @@
</trans-unit> </trans-unit>
<trans-unit id="fbce449c2e3719c495e4e3ba0107df816b039ebe" datatype="html"> <trans-unit id="fbce449c2e3719c495e4e3ba0107df816b039ebe" datatype="html">
<source> Use anonymously </source> <source> Use anonymously </source>
<target state="new"> Use anonymously </target> <target state="translated"> Utilizar anonimamente </target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">148</context> <context context-type="linenumber">148</context>
@ -4471,7 +4471,7 @@
</trans-unit> </trans-unit>
<trans-unit id="f37bf6923c7cffbb879c67fcb782950e28c431d0" datatype="html"> <trans-unit id="f37bf6923c7cffbb879c67fcb782950e28c431d0" datatype="html">
<source> Free Plan </source> <source> Free Plan </source>
<target state="new"> Free Plan </target> <target state="translated"> Plano gratuito </target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">167</context> <context context-type="linenumber">167</context>
@ -4479,7 +4479,7 @@
</trans-unit> </trans-unit>
<trans-unit id="fcde58253a4cfd52c228eebdae74e1be7a1ab714" datatype="html"> <trans-unit id="fcde58253a4cfd52c228eebdae74e1be7a1ab714" datatype="html">
<source>Notes</source> <source>Notes</source>
<target state="new">Notes</target> <target state="translated">Notas</target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">201</context> <context context-type="linenumber">201</context>
@ -4887,7 +4887,7 @@
</trans-unit> </trans-unit>
<trans-unit id="50fefcca3f8b7dd5a34141329118014a8c4b7d1b" datatype="html"> <trans-unit id="50fefcca3f8b7dd5a34141329118014a8c4b7d1b" datatype="html">
<source> Get Started </source> <source> Get Started </source>
<target state="new"> Get Started </target> <target state="translated"> Começar </target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/landing/landing-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/landing/landing-page.html</context>
<context context-type="linenumber">41</context> <context context-type="linenumber">41</context>
@ -5651,7 +5651,7 @@
</trans-unit> </trans-unit>
<trans-unit id="968ab39db7fbb2621ba4536940768e6b6ee9c71f" datatype="html"> <trans-unit id="968ab39db7fbb2621ba4536940768e6b6ee9c71f" datatype="html">
<source> Get Started </source> <source> Get Started </source>
<target state="new"> Get Started </target> <target state="translated"> Começar </target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">232</context> <context context-type="linenumber">232</context>
@ -5983,7 +5983,7 @@
</trans-unit> </trans-unit>
<trans-unit id="567d4a9cafe9790b401ebf3a5d74f7c51b46a7b5" datatype="html"> <trans-unit id="567d4a9cafe9790b401ebf3a5d74f7c51b46a7b5" datatype="html">
<source> Ghostfolio vs <x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> comparison table </source> <source> Ghostfolio vs <x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> comparison table </source>
<target state="new"> Ghostfolio vs <x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> comparison table </target> <target state="translated"> Ghostfolio vs <x id="INTERPOLATION" equiv-text="{{ product2.name }}"/> tabela de comparação </target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">49</context> <context context-type="linenumber">49</context>

4
apps/client/src/locales/messages.tr.xlf

@ -4547,7 +4547,7 @@
</trans-unit> </trans-unit>
<trans-unit id="6264b47d8cbc74a3a411c1910964285bb0c8cc5e" datatype="html"> <trans-unit id="6264b47d8cbc74a3a411c1910964285bb0c8cc5e" datatype="html">
<source> Open Source Alternative to <x id="INTERPOLATION" equiv-text="{{ personalFinanceTool.name }}"/> </source> <source> Open Source Alternative to <x id="INTERPOLATION" equiv-text="{{ personalFinanceTool.name }}"/> </source>
<target state="new"><x id="INTERPOLATION" equiv-text="{{ product.name }}"/> için Açık Kaynak Alternatifi</target> <target state="new"> Open Source Alternative to <x id="INTERPOLATION" equiv-text="{{ personalFinanceTool.name }}"/> </target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.html</context>
<context context-type="linenumber">42</context> <context context-type="linenumber">42</context>
@ -4563,7 +4563,7 @@
</trans-unit> </trans-unit>
<trans-unit id="1800c29bad68f121c80fc8581f6b1f07b5a5a2ca" datatype="html"> <trans-unit id="1800c29bad68f121c80fc8581f6b1f07b5a5a2ca" datatype="html">
<source> Are you looking for an open source alternative to <x id="INTERPOLATION" equiv-text="{{ product2.name }}"/>? <x id="START_LINK" ctype="x-a" equiv-text="&lt;a [routerLink]=&quot;routerLinkAbout&quot;&gt;"/>Ghostfolio<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/> 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 <x id="START_LINK_1" equiv-text="&lt;a [routerLink]=&quot;routerLinkFeatures&quot; &gt;"/>wide range of functionalities<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/> to help you make informed decisions and take control of your financial future. </source> <source> Are you looking for an open source alternative to <x id="INTERPOLATION" equiv-text="{{ product2.name }}"/>? <x id="START_LINK" ctype="x-a" equiv-text="&lt;a [routerLink]=&quot;routerLinkAbout&quot;&gt;"/>Ghostfolio<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/> 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 <x id="START_LINK_1" equiv-text="&lt;a [routerLink]=&quot;routerLinkFeatures&quot; &gt;"/>wide range of functionalities<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/> to help you make informed decisions and take control of your financial future. </source>
<target state="translated"> <x id="INTERPOLATION" equiv-text="{{ product2.name }}"/>? <x id="START_LINK" ctype="x-a" equiv-text="&lt;a [routerLink]=&quot;routerLinkAbout&quot;&gt;"/> yerine Açık Kaynak Kodlu bir alternatif mi arıyorsunuz? Ghostfolio<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/>,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 <x id="START_LINK_1" equiv-text="&lt;a [routerLink]=&quot;routerLinkFeatures&quot; &gt;"/> geniş spektrumlu bir fonksiyon seti<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/> sunarak bilgiye dayalı kararlar vermenizi ve finansal geleceğinizin kontrolünü elinize almanızı sağlar.</target> <target state="new"> Are you looking for an open source alternative to <x id="INTERPOLATION" equiv-text="{{ product2.name }}"/>? <x id="START_LINK" ctype="x-a" equiv-text="&lt;a [routerLink]=&quot;routerLinkAbout&quot;&gt;"/>Ghostfolio<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/> 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 <x id="START_LINK_1" equiv-text="&lt;a [routerLink]=&quot;routerLinkFeatures&quot; &gt;"/>wide range of functionalities<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a &gt;"/> to help you make informed decisions and take control of your financial future. </target>
<context-group purpose="location"> <context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context> <context context-type="sourcefile">apps/client/src/app/pages/resources/personal-finance-tools/product-page.html</context>
<context context-type="linenumber">13</context> <context context-type="linenumber">13</context>

4
libs/common/src/lib/interfaces/admin-market-data.interface.ts

@ -6,13 +6,13 @@ export interface AdminMarketData {
} }
export interface AdminMarketDataItem { export interface AdminMarketDataItem {
activitiesCount?: number; activitiesCount: number;
assetClass?: AssetClass; assetClass?: AssetClass;
assetSubClass?: AssetSubClass; assetSubClass?: AssetSubClass;
countriesCount: number; countriesCount: number;
currency: string; currency: string;
dataSource: DataSource; dataSource: DataSource;
date?: Date; date: Date;
id: string; id: string;
isBenchmark?: boolean; isBenchmark?: boolean;
marketDataItemCount: number; marketDataItemCount: number;

16
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));
}
}

2
package.json

@ -1,6 +1,6 @@
{ {
"name": "ghostfolio", "name": "ghostfolio",
"version": "2.88.0", "version": "2.89.0",
"homepage": "https://ghostfol.io", "homepage": "https://ghostfol.io",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"repository": "https://github.com/ghostfolio/ghostfolio", "repository": "https://github.com/ghostfolio/ghostfolio",

18
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
}
]
}
Loading…
Cancel
Save