Browse Source

Merge branch 'main' into feature/upgrade-prisma-to-version-5.17.0

pull/3597/head
Thomas Kaul 1 year ago
committed by GitHub
parent
commit
ae371ccdcd
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 3
      CHANGELOG.md
  2. 7
      apps/client/src/app/components/admin-overview/admin-overview.html
  3. 40
      apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts
  4. 88
      apps/client/src/app/pages/resources/personal-finance-tools/product-page.html
  5. 2
      libs/common/src/lib/interfaces/product.ts
  6. 14
      libs/common/src/lib/personal-finance-tools.ts
  7. 24
      libs/ui/src/lib/i18n.ts
  8. 29
      libs/ui/src/lib/value/value.component.ts
  9. 70
      package.json
  10. 3059
      yarn.lock

3
CHANGELOG.md

@ -13,6 +13,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed ### Changed
- Improved the handling of the numerical precision in the value component
- Upgraded `angular` from version `18.0.4` to `18.1.1`
- Upgraded `Nx` from version `19.4.3` to `19.5.1`
- Upgraded `prisma` from version `5.16.1` to `5.17.0` - Upgraded `prisma` from version `5.16.1` to `5.17.0`
## 2.97.0 - 2024-07-20 ## 2.97.0 - 2024-07-20

7
apps/client/src/app/components/admin-overview/admin-overview.html

@ -12,11 +12,7 @@
<div class="d-flex my-3"> <div class="d-flex my-3">
<div class="w-50" i18n>User Count</div> <div class="w-50" i18n>User Count</div>
<div class="w-50"> <div class="w-50">
<gf-value <gf-value [locale]="user?.settings?.locale" [value]="userCount" />
[locale]="user?.settings?.locale"
[precision]="0"
[value]="userCount"
/>
</div> </div>
</div> </div>
<div class="d-flex my-3"> <div class="d-flex my-3">
@ -24,7 +20,6 @@
<div class="w-50"> <div class="w-50">
<gf-value <gf-value
[locale]="user?.settings?.locale" [locale]="user?.settings?.locale"
[precision]="0"
[value]="transactionCount" [value]="transactionCount"
/> />
@if (transactionCount && userCount) { @if (transactionCount && userCount) {

40
apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts

@ -1,6 +1,7 @@
import { DataService } from '@ghostfolio/client/services/data.service'; import { DataService } from '@ghostfolio/client/services/data.service';
import { Product } from '@ghostfolio/common/interfaces'; import { Product } from '@ghostfolio/common/interfaces';
import { personalFinanceTools } from '@ghostfolio/common/personal-finance-tools'; import { personalFinanceTools } from '@ghostfolio/common/personal-finance-tools';
import { translate } from '@ghostfolio/ui/i18n';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
@ -26,6 +27,7 @@ export class GfProductPageComponent implements OnInit {
'/' + $localize`resources`, '/' + $localize`resources`,
'personal-finance-tools' 'personal-finance-tools'
]; ];
public tags: string[];
public constructor( public constructor(
private dataService: DataService, private dataService: DataService,
@ -56,7 +58,7 @@ export class GfProductPageComponent implements OnInit {
], ],
name: 'Ghostfolio', name: 'Ghostfolio',
origin: $localize`Switzerland`, origin: $localize`Switzerland`,
region: $localize`Global`, regions: [$localize`Global`],
slogan: 'Open Source Wealth Management', slogan: 'Open Source Wealth Management',
useAnonymously: true useAnonymously: true
}; };
@ -64,5 +66,41 @@ export class GfProductPageComponent implements OnInit {
this.product2 = personalFinanceTools.find(({ key }) => { this.product2 = personalFinanceTools.find(({ key }) => {
return key === this.route.snapshot.data['key']; return key === this.route.snapshot.data['key'];
}); });
if (this.product2.origin) {
this.product2.origin = translate(this.product2.origin);
}
if (this.product2.regions) {
this.product2.regions = this.product2.regions.map((region) => {
return translate(region);
});
}
this.tags = [
this.product1.name,
this.product2.name,
$localize`Alternative`,
$localize`App`,
$localize`Budgeting`,
$localize`Community`,
$localize`Family Office`,
`Fintech`,
$localize`Investment`,
$localize`Investor`,
$localize`Open Source`,
`OSS`,
$localize`Personal Finance`,
$localize`Privacy`,
$localize`Portfolio`,
$localize`Software`,
$localize`Tool`,
$localize`User Experience`,
$localize`Wealth`,
$localize`Wealth Management`,
`WealthTech`
].sort((a, b) => {
return a.localeCompare(b, undefined, { sensitivity: 'base' });
});
} }
} }

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

@ -80,8 +80,24 @@
</tr> </tr>
<tr class="mat-mdc-row"> <tr class="mat-mdc-row">
<td class="mat-mdc-cell px-3 py-2 text-right" i18n>Region</td> <td class="mat-mdc-cell px-3 py-2 text-right" i18n>Region</td>
<td class="mat-mdc-cell px-1 py-2">{{ product1.region }}</td> <td class="mat-mdc-cell px-1 py-2">
<td class="mat-mdc-cell px-1 py-2">{{ product2.region }}</td> @for (
region of product1.regions;
track region;
let isLast = $last
) {
{{ region }}{{ isLast ? '' : ', ' }}
}
</td>
<td class="mat-mdc-cell px-1 py-2">
@for (
region of product2.regions;
track region;
let isLast = $last
) {
{{ region }}{{ isLast ? '' : ', ' }}
}
</td>
</tr> </tr>
<tr class="mat-mdc-row"> <tr class="mat-mdc-row">
<td class="mat-mdc-cell px-3 py-2 text-right" i18n> <td class="mat-mdc-cell px-3 py-2 text-right" i18n>
@ -236,69 +252,11 @@
</section> </section>
<section class="mb-4"> <section class="mb-4">
<ul class="list-inline"> <ul class="list-inline">
<li class="list-inline-item"> @for (tag of tags; track tag) {
<span class="badge badge-light">Alternative</span> <li class="list-inline-item">
</li> <span class="badge badge-light">{{ tag }}</span>
<li class="list-inline-item"> </li>
<span class="badge badge-light">App</span> }
</li>
<li class="list-inline-item">
<span class="badge badge-light">Budgeting</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Community</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Family Office</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Fintech</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">{{ product1.name }}</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Investment</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Investor</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Open Source</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">OSS</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Personal Finance</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Privacy</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Portfolio</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Software</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Tool</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">User Experience</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Wealth</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">WealthTech</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Wealth Management</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">{{ product2.name }}</span>
</li>
</ul> </ul>
</section> </section>
<nav aria-label="breadcrumb"> <nav aria-label="breadcrumb">

2
libs/common/src/lib/interfaces/product.ts

@ -10,7 +10,7 @@ export interface Product {
note?: string; note?: string;
origin?: string; origin?: string;
pricingPerYear?: string; pricingPerYear?: string;
region?: string; regions?: string[];
slogan?: string; slogan?: string;
useAnonymously?: boolean; useAnonymously?: boolean;
} }

14
libs/common/src/lib/personal-finance-tools.ts

@ -277,7 +277,7 @@ export const personalFinanceTools: Product[] = [
name: 'markets.sh', name: 'markets.sh',
origin: `Germany`, origin: `Germany`,
pricingPerYear: '€168', pricingPerYear: '€168',
region: `Global`, regions: [`Global`],
slogan: 'Track your investments' slogan: 'Track your investments'
}, },
{ {
@ -289,7 +289,7 @@ export const personalFinanceTools: Product[] = [
note: 'Maybe Finance has discontinued in 2023', note: 'Maybe Finance has discontinued in 2023',
origin: `United States`, origin: `United States`,
pricingPerYear: '$145', pricingPerYear: '$145',
region: `United States`, regions: [`United States`],
slogan: 'Your financial future, in your control' slogan: 'Your financial future, in your control'
}, },
{ {
@ -300,7 +300,7 @@ export const personalFinanceTools: Product[] = [
name: 'Merlin', name: 'Merlin',
origin: `United States`, origin: `United States`,
pricingPerYear: '$204', pricingPerYear: '$204',
region: 'Canada, United States', regions: ['Canada', 'United States'],
slogan: 'The smartest way to track your crypto' slogan: 'The smartest way to track your crypto'
}, },
{ {
@ -340,7 +340,7 @@ export const personalFinanceTools: Product[] = [
note: 'Originally named as Tresor One', note: 'Originally named as Tresor One',
origin: `Germany`, origin: `Germany`,
pricingPerYear: '€88', pricingPerYear: '€88',
region: 'Austria, Germany, Switzerland', regions: ['Austria', 'Germany', 'Switzerland'],
slogan: 'Dein Vermögen immer im Blick' slogan: 'Dein Vermögen immer im Blick'
}, },
{ {
@ -360,7 +360,7 @@ export const personalFinanceTools: Product[] = [
name: 'PocketSmith', name: 'PocketSmith',
origin: `New Zealand`, origin: `New Zealand`,
pricingPerYear: '$120', pricingPerYear: '$120',
region: `Global`, regions: [`Global`],
slogan: 'Know where your money is going' slogan: 'Know where your money is going'
}, },
{ {
@ -444,7 +444,7 @@ export const personalFinanceTools: Product[] = [
name: 'Sharesight', name: 'Sharesight',
origin: `New Zealand`, origin: `New Zealand`,
pricingPerYear: '$135', pricingPerYear: '$135',
region: `Global`, regions: [`Global`],
slogan: 'Stock Portfolio Tracker' slogan: 'Stock Portfolio Tracker'
}, },
{ {
@ -594,7 +594,7 @@ export const personalFinanceTools: Product[] = [
languages: ['Deutsch', 'English', 'Español', 'Français', 'Italiano'], languages: ['Deutsch', 'English', 'Español', 'Français', 'Italiano'],
name: 'yeekatee', name: 'yeekatee',
origin: `Switzerland`, origin: `Switzerland`,
region: `Global`, regions: [`Global`],
slogan: 'Connect. Share. Invest.' slogan: 'Connect. Share. Invest.'
}, },
{ {

24
libs/ui/src/lib/i18n.ts

@ -11,10 +11,10 @@ const locales = {
DATA_IMPORT_AND_EXPORT_TOOLTIP_OSS: $localize`Switch to Ghostfolio Premium easily`, DATA_IMPORT_AND_EXPORT_TOOLTIP_OSS: $localize`Switch to Ghostfolio Premium easily`,
DATA_IMPORT_AND_EXPORT_TOOLTIP_PREMIUM: $localize`Switch to Ghostfolio Open Source or Ghostfolio Basic easily`, DATA_IMPORT_AND_EXPORT_TOOLTIP_PREMIUM: $localize`Switch to Ghostfolio Open Source or Ghostfolio Basic easily`,
EMERGENCY_FUND: $localize`Emergency Fund`, EMERGENCY_FUND: $localize`Emergency Fund`,
Global: $localize`Global`,
GRANT: $localize`Grant`, GRANT: $localize`Grant`,
HIGHER_RISK: $localize`Higher Risk`, HIGHER_RISK: $localize`Higher Risk`,
IMPORT_ACTIVITY_ERROR_IS_DUPLICATE: $localize`This activity already exists.`, IMPORT_ACTIVITY_ERROR_IS_DUPLICATE: $localize`This activity already exists.`,
Japan: $localize`Japan`,
LOWER_RISK: $localize`Lower Risk`, LOWER_RISK: $localize`Lower Risk`,
MONTH: $localize`Month`, MONTH: $localize`Month`,
MONTHS: $localize`Months`, MONTHS: $localize`Months`,
@ -65,6 +65,28 @@ const locales = {
Oceania: $localize`Oceania`, Oceania: $localize`Oceania`,
'South America': $localize`South America`, 'South America': $localize`South America`,
// Countries
Australia: $localize`Australia`,
Austria: $localize`Austria`,
Belgium: $localize`Belgium`,
Bulgaria: $localize`Bulgaria`,
Canada: $localize`Canada`,
'Czech Republic': $localize`Czech Republic`,
Finland: $localize`Finland`,
France: $localize`France`,
Germany: $localize`Germany`,
India: $localize`India`,
Italy: $localize`Italy`,
Japan: $localize`Japan`,
Netherlands: $localize`Netherlands`,
'New Zealand': $localize`New Zealand`,
Poland: $localize`Poland`,
Romania: $localize`Romania`,
'South Africa': $localize`South Africa`,
Switzerland: $localize`Switzerland`,
Thailand: $localize`Thailand`,
'United States': $localize`United States`,
// Fear and Greed Index // Fear and Greed Index
EXTREME_FEAR: $localize`Extreme Fear`, EXTREME_FEAR: $localize`Extreme Fear`,
EXTREME_GREED: $localize`Extreme Greed`, EXTREME_GREED: $localize`Extreme Greed`,

29
libs/ui/src/lib/value/value.component.ts

@ -58,8 +58,10 @@ export class GfValueComponent implements OnChanges {
this.formattedValue = this.absoluteValue.toLocaleString( this.formattedValue = this.absoluteValue.toLocaleString(
this.locale, this.locale,
{ {
maximumFractionDigits: this.precision, maximumFractionDigits:
minimumFractionDigits: this.precision this.precision >= 0 ? this.precision : 2,
minimumFractionDigits:
this.precision >= 0 ? this.precision : 2
} }
); );
} catch {} } catch {}
@ -68,8 +70,10 @@ export class GfValueComponent implements OnChanges {
this.formattedValue = (this.absoluteValue * 100).toLocaleString( this.formattedValue = (this.absoluteValue * 100).toLocaleString(
this.locale, this.locale,
{ {
maximumFractionDigits: this.precision, maximumFractionDigits:
minimumFractionDigits: this.precision this.precision >= 0 ? this.precision : 2,
minimumFractionDigits:
this.precision >= 0 ? this.precision : 2
} }
); );
} catch {} } catch {}
@ -77,8 +81,8 @@ export class GfValueComponent implements OnChanges {
} else if (this.isCurrency) { } else if (this.isCurrency) {
try { try {
this.formattedValue = this.value?.toLocaleString(this.locale, { this.formattedValue = this.value?.toLocaleString(this.locale, {
maximumFractionDigits: this.precision, maximumFractionDigits: this.precision >= 0 ? this.precision : 2,
minimumFractionDigits: this.precision minimumFractionDigits: this.precision >= 0 ? this.precision : 2
}); });
} catch {} } catch {}
} else if (this.isPercent) { } else if (this.isPercent) {
@ -86,11 +90,18 @@ export class GfValueComponent implements OnChanges {
this.formattedValue = (this.value * 100).toLocaleString( this.formattedValue = (this.value * 100).toLocaleString(
this.locale, this.locale,
{ {
maximumFractionDigits: this.precision, maximumFractionDigits: this.precision >= 0 ? this.precision : 2,
minimumFractionDigits: this.precision minimumFractionDigits: this.precision >= 0 ? this.precision : 2
} }
); );
} catch {} } catch {}
} else if (this.precision >= 0) {
try {
this.formattedValue = this.value?.toLocaleString(this.locale, {
maximumFractionDigits: this.precision,
minimumFractionDigits: this.precision
});
} catch {}
} else { } else {
this.formattedValue = this.value?.toLocaleString(this.locale); this.formattedValue = this.value?.toLocaleString(this.locale);
} }
@ -129,7 +140,7 @@ export class GfValueComponent implements OnChanges {
this.isNumber = false; this.isNumber = false;
this.isString = false; this.isString = false;
this.locale = this.locale || getLocale(); this.locale = this.locale || getLocale();
this.precision = this.precision >= 0 ? this.precision : 2; this.precision = this.precision >= 0 ? this.precision : undefined;
this.useAbsoluteValue = false; this.useAbsoluteValue = false;
} }
} }

70
package.json

@ -54,17 +54,17 @@
"workspace-generator": "nx workspace-generator" "workspace-generator": "nx workspace-generator"
}, },
"dependencies": { "dependencies": {
"@angular/animations": "18.0.4", "@angular/animations": "18.1.1",
"@angular/cdk": "18.0.4", "@angular/cdk": "18.1.1",
"@angular/common": "18.0.4", "@angular/common": "18.1.1",
"@angular/compiler": "18.0.4", "@angular/compiler": "18.1.1",
"@angular/core": "18.0.4", "@angular/core": "18.1.1",
"@angular/forms": "18.0.4", "@angular/forms": "18.1.1",
"@angular/material": "18.0.4", "@angular/material": "18.1.1",
"@angular/platform-browser": "18.0.4", "@angular/platform-browser": "18.1.1",
"@angular/platform-browser-dynamic": "18.0.4", "@angular/platform-browser-dynamic": "18.1.1",
"@angular/router": "18.0.4", "@angular/router": "18.1.1",
"@angular/service-worker": "18.0.4", "@angular/service-worker": "18.1.1",
"@codewithdan/observable-store": "2.2.15", "@codewithdan/observable-store": "2.2.15",
"@dfinity/agent": "0.15.7", "@dfinity/agent": "0.15.7",
"@dfinity/auth-client": "0.15.7", "@dfinity/auth-client": "0.15.7",
@ -139,30 +139,30 @@
"zone.js": "0.14.7" "zone.js": "0.14.7"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "18.0.5", "@angular-devkit/build-angular": "18.1.1",
"@angular-devkit/core": "18.0.5", "@angular-devkit/core": "18.1.1",
"@angular-devkit/schematics": "18.0.5", "@angular-devkit/schematics": "18.1.1",
"@angular-eslint/eslint-plugin": "18.0.1", "@angular-eslint/eslint-plugin": "18.1.0",
"@angular-eslint/eslint-plugin-template": "18.0.1", "@angular-eslint/eslint-plugin-template": "18.1.0",
"@angular-eslint/template-parser": "18.0.1", "@angular-eslint/template-parser": "18.1.0",
"@angular/cli": "18.0.5", "@angular/cli": "18.1.1",
"@angular/compiler-cli": "18.0.4", "@angular/compiler-cli": "18.1.1",
"@angular/language-service": "18.0.4", "@angular/language-service": "18.1.1",
"@angular/localize": "18.0.4", "@angular/localize": "18.1.1",
"@angular/pwa": "18.0.5", "@angular/pwa": "18.1.1",
"@nestjs/schematics": "10.0.1", "@nestjs/schematics": "10.0.1",
"@nestjs/testing": "10.1.3", "@nestjs/testing": "10.1.3",
"@nx/angular": "19.4.3", "@nx/angular": "19.5.1",
"@nx/cypress": "19.4.3", "@nx/cypress": "19.5.1",
"@nx/eslint-plugin": "19.4.3", "@nx/eslint-plugin": "19.5.1",
"@nx/jest": "19.4.3", "@nx/jest": "19.5.1",
"@nx/js": "19.4.3", "@nx/js": "19.5.1",
"@nx/nest": "19.4.3", "@nx/nest": "19.5.1",
"@nx/node": "19.4.3", "@nx/node": "19.5.1",
"@nx/storybook": "19.4.3", "@nx/storybook": "19.5.1",
"@nx/web": "19.4.3", "@nx/web": "19.5.1",
"@nx/workspace": "19.4.3", "@nx/workspace": "19.5.1",
"@schematics/angular": "18.0.3", "@schematics/angular": "18.1.1",
"@simplewebauthn/types": "9.0.1", "@simplewebauthn/types": "9.0.1",
"@storybook/addon-essentials": "7.6.5", "@storybook/addon-essentials": "7.6.5",
"@storybook/angular": "7.6.5", "@storybook/angular": "7.6.5",
@ -190,7 +190,7 @@
"jest": "29.4.3", "jest": "29.4.3",
"jest-environment-jsdom": "29.4.3", "jest-environment-jsdom": "29.4.3",
"jest-preset-angular": "14.1.0", "jest-preset-angular": "14.1.0",
"nx": "19.4.3", "nx": "19.5.1",
"prettier": "3.3.3", "prettier": "3.3.3",
"prettier-plugin-organize-attributes": "1.0.0", "prettier-plugin-organize-attributes": "1.0.0",
"react": "18.2.0", "react": "18.2.0",
@ -201,7 +201,7 @@
"ts-jest": "29.1.0", "ts-jest": "29.1.0",
"ts-node": "10.9.2", "ts-node": "10.9.2",
"tslib": "2.6.0", "tslib": "2.6.0",
"typescript": "5.4.4", "typescript": "5.5.3",
"webpack-bundle-analyzer": "4.10.1" "webpack-bundle-analyzer": "4.10.1"
}, },
"engines": { "engines": {

3059
yarn.lock

File diff suppressed because it is too large
Loading…
Cancel
Save