Browse Source

Merge branch 'ghostfolio:main' into feature/move-accounts-table-to-ui

pull/5278/head
David Requeno 3 weeks ago
committed by GitHub
parent
commit
9b754d4b9a
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 19
      CHANGELOG.md
  2. 6
      apps/api/src/app/portfolio/portfolio.controller.ts
  3. 8
      apps/api/src/app/portfolio/portfolio.service.ts
  4. 3
      apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts
  5. 2
      apps/client/src/app/components/admin-users/admin-users.component.ts
  6. 17
      apps/client/src/app/components/admin-users/admin-users.html
  7. 14
      apps/client/src/app/pages/landing/landing-page.html
  8. 25
      apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts
  9. 10
      apps/client/src/app/pages/portfolio/analysis/analysis-page.html
  10. 6
      apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.ts
  11. 3246
      apps/client/src/locales/messages.ca.xlf
  12. 3244
      apps/client/src/locales/messages.de.xlf
  13. 3318
      apps/client/src/locales/messages.es.xlf
  14. 3058
      apps/client/src/locales/messages.fr.xlf
  15. 3248
      apps/client/src/locales/messages.it.xlf
  16. 3254
      apps/client/src/locales/messages.nl.xlf
  17. 3352
      apps/client/src/locales/messages.pl.xlf
  18. 3060
      apps/client/src/locales/messages.pt.xlf
  19. 3384
      apps/client/src/locales/messages.tr.xlf
  20. 3222
      apps/client/src/locales/messages.uk.xlf
  21. 3163
      apps/client/src/locales/messages.xlf
  22. 3334
      apps/client/src/locales/messages.zh.xlf
  23. 2
      apps/client/src/styles.scss
  24. 80
      apps/client/src/styles/bootstrap.scss
  25. 2
      libs/common/src/lib/interfaces/responses/portfolio-report.interface.ts
  26. 50
      libs/ui/src/lib/membership-card/membership-card.component.stories.ts
  27. 33760
      package-lock.json
  28. 70
      package.json

19
CHANGELOG.md

@ -9,20 +9,39 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### Added
- Added a _Storybook_ story for the membership card component
### Changed
- Moved the support for changing the asset profile identifier (`dataSource` and `symbol`) in the asset profile details dialog of the admin control panel from experimental to general availability
- Improved the balance of headings on the landing page
- Improved the language localization for Spanish (`es`)
- Upgraded `angular` from version `20.0.7` to `20.1.3`
- Upgraded `Nx` from version `21.2.4` to `21.3.9`
## 2.186.0 - 2025-07-30
### Added
- Added the allocation column to the accounts table component of the holding detail dialog - Added the allocation column to the accounts table component of the holding detail dialog
### Changed ### Changed
- Improved the _Top 3_ and _Bottom 3_ performers on the analysis page by removing items without performance
- Improved the usability of the toggle component - Improved the usability of the toggle component
- Simplified the users table of the admin control panel
- Restructured the response of the portfolio report endpoint (_X-ray_) - Restructured the response of the portfolio report endpoint (_X-ray_)
- Refreshed the cryptocurrencies list - Refreshed the cryptocurrencies list
- Improved the language localization for Catalan (`ca`) - Improved the language localization for Catalan (`ca`)
- Improved the language localization for Chinese (`zh`) - Improved the language localization for Chinese (`zh`)
- Improved the language localization for Dutch (`nl`) - Improved the language localization for Dutch (`nl`)
- Improved the language localization for German (`de`)
- Improved the language localization for Spanish (`es`) - Improved the language localization for Spanish (`es`)
- Upgraded `ng-extract-i18n-merge` from version `2.15.1` to `3.0.0`
### Fixed ### Fixed
- Fixed the links of the _Top 3_ and _Bottom 3_ performers on the analysis page
- Excluded the holdings originated of `FEE`, `INTEREST` and `LIABILITY` activities from the closed holdings on the portfolio holdings page - Excluded the holdings originated of `FEE`, `INTEREST` and `LIABILITY` activities from the closed holdings on the portfolio holdings page
- Fixed an issue with serving _Storybook_ related to missing styles - Fixed an issue with serving _Storybook_ related to missing styles

6
apps/api/src/app/portfolio/portfolio.controller.ts

@ -655,11 +655,11 @@ export class PortfolioController {
this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') && this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') &&
this.request.user.subscription.type === 'Basic' this.request.user.subscription.type === 'Basic'
) { ) {
for (const rule in report['x-ray'].rules) { for (const rule in report.xRay.rules) {
report['x-ray'].rules[rule] = null; report.xRay.rules[rule] = null;
} }
report['x-ray'].statistics = { report.xRay.statistics = {
rulesActiveCount: 0, rulesActiveCount: 0,
rulesFulfilledCount: 0 rulesFulfilledCount: 0
}; };

8
apps/api/src/app/portfolio/portfolio.service.ts

@ -1157,7 +1157,7 @@ export class PortfolioService {
}) })
).toNumber(); ).toNumber();
const rules: PortfolioReportResponse['x-ray']['rules'] = { const rules: PortfolioReportResponse['xRay']['rules'] = {
accountClusterRisk: accountClusterRisk:
summary.activityCount > 0 summary.activityCount > 0
? await this.rulesService.evaluate( ? await this.rulesService.evaluate(
@ -1313,7 +1313,7 @@ export class PortfolioService {
}; };
return { return {
'x-ray': { xRay: {
rules, rules,
statistics: this.getReportStatistics(rules) statistics: this.getReportStatistics(rules)
} }
@ -1737,8 +1737,8 @@ export class PortfolioService {
} }
private getReportStatistics( private getReportStatistics(
evaluatedRules: PortfolioReportResponse['x-ray']['rules'] evaluatedRules: PortfolioReportResponse['xRay']['rules']
): PortfolioReportResponse['x-ray']['statistics'] { ): PortfolioReportResponse['xRay']['statistics'] {
const rulesActiveCount = Object.values(evaluatedRules) const rulesActiveCount = Object.values(evaluatedRules)
.flat() .flat()
.filter((rule) => { .filter((rule) => {

3
apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts

@ -233,8 +233,7 @@ export class GfAssetProfileDialogComponent implements OnDestroy, OnInit {
public get canEditAssetProfileIdentifier() { public get canEditAssetProfileIdentifier() {
return ( return (
this.assetProfile?.assetClass && this.assetProfile?.assetClass &&
!['MANUAL'].includes(this.assetProfile?.dataSource) && !['MANUAL'].includes(this.assetProfile?.dataSource)
this.user?.settings?.isExperimentalFeatures
); );
} }

2
apps/client/src/app/components/admin-users/admin-users.component.ts

@ -101,7 +101,6 @@ export class GfAdminUsersComponent implements OnDestroy, OnInit {
if (this.hasPermissionForSubscription) { if (this.hasPermissionForSubscription) {
this.displayedColumns = [ this.displayedColumns = [
'index',
'user', 'user',
'country', 'country',
'registration', 'registration',
@ -114,7 +113,6 @@ export class GfAdminUsersComponent implements OnDestroy, OnInit {
]; ];
} else { } else {
this.displayedColumns = [ this.displayedColumns = [
'index',
'user', 'user',
'registration', 'registration',
'accounts', 'accounts',

17
apps/client/src/app/components/admin-users/admin-users.html

@ -3,23 +3,6 @@
<div class="col"> <div class="col">
<div class="overflow-x-auto"> <div class="overflow-x-auto">
<table class="gf-table" mat-table [dataSource]="dataSource"> <table class="gf-table" mat-table [dataSource]="dataSource">
<ng-container matColumnDef="index">
<th
*matHeaderCellDef
class="mat-mdc-header-cell px-1 py-2 text-right"
mat-header-cell
>
#
</th>
<td
*matCellDef="let element; let i = index"
class="mat-mdc-cell px-1 py-2 text-right"
mat-cell
>
{{ i + 1 }}
</td>
</ng-container>
<ng-container matColumnDef="user"> <ng-container matColumnDef="user">
<th <th
*matHeaderCellDef *matHeaderCellDef

14
apps/client/src/app/pages/landing/landing-page.html

@ -2,11 +2,11 @@
<div class="row"> <div class="row">
<div class="col text-center"> <div class="col text-center">
<div> <div>
<h1 class="font-weight-bold intro" i18n> <h1 class="font-weight-bold gf-text-wrap-balance intro" i18n>
Manage your wealth like a boss Manage your wealth like a boss
</h1> </h1>
</div> </div>
<p class="lead mb-4" i18n> <p class="gf-text-wrap-balance lead mb-4" i18n>
Ghostfolio is a privacy-first, open source dashboard for your personal Ghostfolio is a privacy-first, open source dashboard for your personal
finances. Break down your asset allocation, know your net worth and make finances. Break down your asset allocation, know your net worth and make
solid, data-driven investment decisions. solid, data-driven investment decisions.
@ -222,11 +222,11 @@
<div class="pt-3 row"> <div class="pt-3 row">
<div class="col text-center"> <div class="col text-center">
<h2 class="h4 mb-1 text-center" i18n> <h2 class="gf-text-wrap-balance h4 mb-1 text-center" i18n>
Protect your <strong>assets</strong>. Refine your Protect your <strong>assets</strong>. Refine your
<strong>personal investment strategy</strong>. <strong>personal investment strategy</strong>.
</h2> </h2>
<p class="lead m-0" i18n> <p class="gf-text-wrap-balance lead m-0" i18n>
Ghostfolio empowers busy people to keep track of stocks, ETFs or Ghostfolio empowers busy people to keep track of stocks, ETFs or
cryptocurrencies without being tracked. cryptocurrencies without being tracked.
</p> </p>
@ -270,7 +270,7 @@
<div class="row my-5"> <div class="row my-5">
<div class="col-md-6 offset-md-3"> <div class="col-md-6 offset-md-3">
<h2 class="h4 mb-1 text-center" i18n>Why <strong>Ghostfolio</strong>?</h2> <h2 class="h4 mb-1 text-center" i18n>Why <strong>Ghostfolio</strong>?</h2>
<p class="lead mb-3 text-center" i18n> <p class="gf-text-wrap-balance lead mb-3 text-center" i18n>
Ghostfolio is for you if you are... Ghostfolio is for you if you are...
</p> </p>
<ul class="list-unstyled"> <ul class="list-unstyled">
@ -363,7 +363,7 @@
@if (hasPermissionForSubscription) { @if (hasPermissionForSubscription) {
<div class="row my-5"> <div class="row my-5">
<div class="col-12"> <div class="col-12">
<h2 class="h4 text-center" i18n> <h2 class="gf-text-wrap-balance h4 text-center" i18n>
Members from around the globe are using Members from around the globe are using
<a href="pricing"><strong>Ghostfolio Premium</strong></a> <a href="pricing"><strong>Ghostfolio Premium</strong></a>
</h2> </h2>
@ -431,7 +431,7 @@
<h2 class="h4 mb-1 text-center" i18n> <h2 class="h4 mb-1 text-center" i18n>
Are <strong>you</strong> ready? Are <strong>you</strong> ready?
</h2> </h2>
<p class="lead mb-3 text-center" i18n> <p class="gf-text-wrap-balance lead mb-3 text-center" i18n>
Join now Join now
@if (hasPermissionForDemo) { @if (hasPermissionForDemo) {
or check out the example account or check out the example account

25
apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts

@ -32,6 +32,7 @@ import { MatCardModule } from '@angular/material/card';
import { MatMenuModule, MatMenuTrigger } from '@angular/material/menu'; import { MatMenuModule, MatMenuTrigger } from '@angular/material/menu';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatSnackBar } from '@angular/material/snack-bar'; import { MatSnackBar } from '@angular/material/snack-bar';
import { RouterModule } from '@angular/router';
import { IonIcon } from '@ionic/angular/standalone'; import { IonIcon } from '@ionic/angular/standalone';
import { SymbolProfile } from '@prisma/client'; import { SymbolProfile } from '@prisma/client';
import { addIcons } from 'ionicons'; import { addIcons } from 'ionicons';
@ -55,7 +56,8 @@ import { takeUntil } from 'rxjs/operators';
MatCardModule, MatCardModule,
MatMenuModule, MatMenuModule,
MatProgressSpinnerModule, MatProgressSpinnerModule,
NgxSkeletonLoaderModule NgxSkeletonLoaderModule,
RouterModule
], ],
selector: 'gf-analysis-page', selector: 'gf-analysis-page',
styleUrls: ['./analysis-page.scss'], styleUrls: ['./analysis-page.scss'],
@ -342,13 +344,20 @@ export class GfAnalysisPageComponent implements OnDestroy, OnInit {
'netPerformancePercentWithCurrencyEffect' 'netPerformancePercentWithCurrencyEffect'
).reverse(); ).reverse();
this.top3 = holdingsSorted.slice(0, 3); this.top3 = holdingsSorted
.filter(
if (holdings?.length > 3) { ({ netPerformancePercentWithCurrencyEffect }) =>
this.bottom3 = holdingsSorted.slice(-3).reverse(); netPerformancePercentWithCurrencyEffect > 0
} else { )
this.bottom3 = []; .slice(0, 3);
}
this.bottom3 = holdingsSorted
.filter(
({ netPerformancePercentWithCurrencyEffect }) =>
netPerformancePercentWithCurrencyEffect < 0
)
.slice(-3)
.reverse();
this.changeDetectorRef.markForCheck(); this.changeDetectorRef.markForCheck();
}); });

10
apps/client/src/app/pages/portfolio/analysis/analysis-page.html

@ -93,7 +93,7 @@
<div class="mb-5 row"> <div class="mb-5 row">
<div class="col"> <div class="col">
<mat-card appearance="outlined" class="mb-3"> <mat-card appearance="outlined">
<mat-card-content> <mat-card-content>
<div class="d-flex py-1"> <div class="d-flex py-1">
<div <div
@ -232,8 +232,8 @@
</div> </div>
<div class="mb-5 row"> <div class="mb-5 row">
<div class="col-md-6"> <div class="col-md-6 mb-3">
<mat-card appearance="outlined" class="mb-3"> <mat-card appearance="outlined" class="h-100">
<mat-card-header> <mat-card-header>
<mat-card-title class="align-items-center d-flex" i18n <mat-card-title class="align-items-center d-flex" i18n
>Top</mat-card-title >Top</mat-card-title
@ -281,8 +281,8 @@
</mat-card-content> </mat-card-content>
</mat-card> </mat-card>
</div> </div>
<div class="col-md-6"> <div class="col-md-6 mb-3">
<mat-card appearance="outlined" class="mb-3"> <mat-card appearance="outlined" class="h-100">
<mat-card-header> <mat-card-header>
<mat-card-title class="align-items-center d-flex" i18n <mat-card-title class="align-items-center d-flex" i18n
>Bottom</mat-card-title >Bottom</mat-card-title

6
apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.ts

@ -47,7 +47,7 @@ export class GfXRayPageComponent {
public inactiveRules: PortfolioReportRule[]; public inactiveRules: PortfolioReportRule[];
public isLoading = false; public isLoading = false;
public regionalMarketClusterRiskRules: PortfolioReportRule[]; public regionalMarketClusterRiskRules: PortfolioReportRule[];
public statistics: PortfolioReportResponse['x-ray']['statistics']; public statistics: PortfolioReportResponse['xRay']['statistics'];
public user: User; public user: User;
private unsubscribeSubject = new Subject<void>(); private unsubscribeSubject = new Subject<void>();
@ -115,7 +115,7 @@ export class GfXRayPageComponent {
this.dataService this.dataService
.fetchPortfolioReport() .fetchPortfolioReport()
.pipe(takeUntil(this.unsubscribeSubject)) .pipe(takeUntil(this.unsubscribeSubject))
.subscribe(({ 'x-ray': { rules, statistics } }) => { .subscribe(({ xRay: { rules, statistics } }) => {
this.inactiveRules = this.mergeInactiveRules(rules); this.inactiveRules = this.mergeInactiveRules(rules);
this.statistics = statistics; this.statistics = statistics;
@ -161,7 +161,7 @@ export class GfXRayPageComponent {
} }
private mergeInactiveRules( private mergeInactiveRules(
rules: PortfolioReportResponse['x-ray']['rules'] rules: PortfolioReportResponse['xRay']['rules']
): PortfolioReportRule[] { ): PortfolioReportRule[] {
let inactiveRules: PortfolioReportRule[] = []; let inactiveRules: PortfolioReportRule[] = [];

3246
apps/client/src/locales/messages.ca.xlf

File diff suppressed because it is too large

3244
apps/client/src/locales/messages.de.xlf

File diff suppressed because it is too large

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

File diff suppressed because it is too large

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

File diff suppressed because it is too large

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

File diff suppressed because it is too large

3254
apps/client/src/locales/messages.nl.xlf

File diff suppressed because it is too large

3352
apps/client/src/locales/messages.pl.xlf

File diff suppressed because it is too large

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

File diff suppressed because it is too large

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

File diff suppressed because it is too large

3222
apps/client/src/locales/messages.uk.xlf

File diff suppressed because it is too large

3163
apps/client/src/locales/messages.xlf

File diff suppressed because it is too large

3334
apps/client/src/locales/messages.zh.xlf

File diff suppressed because it is too large

2
apps/client/src/styles.scss

@ -1,7 +1,7 @@
@import './styles/bootstrap'; @import './styles/bootstrap';
@import './styles/table'; @import './styles/table';
@import 'node_modules/svgmap/dist/svgMap'; @import 'svgmap/dist/svgMap';
:root { :root {
--dark-background: rgb(25, 25, 25); --dark-background: rgb(25, 25, 25);

80
apps/client/src/styles/bootstrap.scss

@ -1,44 +1,44 @@
/*! /*!
* Bootstrap v4.5.2 (https://getbootstrap.com/) * Bootstrap v4.6.2 (https://getbootstrap.com/)
* Copyright 2011-2020 The Bootstrap Authors * Copyright 2011-2022 The Bootstrap Authors
* Copyright 2011-2020 Twitter, Inc. * Copyright 2011-2022 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/ */
@import 'node_modules/bootstrap/scss/functions'; @import 'bootstrap/scss/functions';
@import 'node_modules/bootstrap/scss/variables'; @import 'bootstrap/scss/variables';
@import 'node_modules/bootstrap/scss/mixins'; @import 'bootstrap/scss/mixins';
@import 'node_modules/bootstrap/scss/root'; @import 'bootstrap/scss/root';
@import 'node_modules/bootstrap/scss/reboot'; @import 'bootstrap/scss/reboot';
@import 'node_modules/bootstrap/scss/type'; @import 'bootstrap/scss/type';
@import 'node_modules/bootstrap/scss/images'; @import 'bootstrap/scss/images';
// @import 'node_modules/bootstrap/scss/code'; // @import 'bootstrap/scss/code';
@import 'node_modules/bootstrap/scss/grid'; @import 'bootstrap/scss/grid';
// @import 'node_modules/bootstrap/scss/tables'; // @import 'bootstrap/scss/tables';
// @import 'node_modules/bootstrap/scss/forms'; // @import 'bootstrap/scss/forms';
// @import 'node_modules/bootstrap/scss/buttons'; // @import 'bootstrap/scss/buttons';
// @import 'node_modules/bootstrap/scss/transitions'; // @import 'bootstrap/scss/transitions';
// @import 'node_modules/bootstrap/scss/dropdown'; // @import 'bootstrap/scss/dropdown';
// @import 'node_modules/bootstrap/scss/button-group'; // @import 'bootstrap/scss/button-group';
// @import 'node_modules/bootstrap/scss/input-group'; // @import 'bootstrap/scss/input-group';
// @import 'node_modules/bootstrap/scss/custom-forms'; // @import 'bootstrap/scss/custom-forms';
// @import 'node_modules/bootstrap/scss/nav'; // @import 'bootstrap/scss/nav';
// @import 'node_modules/bootstrap/scss/navbar'; // @import 'bootstrap/scss/navbar';
// @import 'node_modules/bootstrap/scss/card'; // @import 'bootstrap/scss/card';
@import 'node_modules/bootstrap/scss/breadcrumb'; @import 'bootstrap/scss/breadcrumb';
// @import 'node_modules/bootstrap/scss/pagination'; // @import 'bootstrap/scss/pagination';
@import 'node_modules/bootstrap/scss/badge'; @import 'bootstrap/scss/badge';
// @import 'node_modules/bootstrap/scss/jumbotron'; // @import 'bootstrap/scss/jumbotron';
// @import 'node_modules/bootstrap/scss/alert'; // @import 'bootstrap/scss/alert';
// @import 'node_modules/bootstrap/scss/progress'; // @import 'bootstrap/scss/progress';
// @import 'node_modules/bootstrap/scss/media'; // @import 'bootstrap/scss/media';
// @import 'node_modules/bootstrap/scss/list-group'; // @import 'bootstrap/scss/list-group';
// @import 'node_modules/bootstrap/scss/close'; // @import 'bootstrap/scss/close';
// @import 'node_modules/bootstrap/scss/toasts'; // @import 'bootstrap/scss/toasts';
// @import 'node_modules/bootstrap/scss/modal'; // @import 'bootstrap/scss/modal';
// @import 'node_modules/bootstrap/scss/tooltip'; // @import 'bootstrap/scss/tooltip';
// @import 'node_modules/bootstrap/scss/popover'; // @import 'bootstrap/scss/popover';
// @import 'node_modules/bootstrap/scss/carousel'; // @import 'bootstrap/scss/carousel';
// @import 'node_modules/bootstrap/scss/spinners'; // @import 'bootstrap/scss/spinners';
@import 'node_modules/bootstrap/scss/utilities'; @import 'bootstrap/scss/utilities';
// @import 'node_modules/bootstrap/scss/print'; // @import 'bootstrap/scss/print';

2
libs/common/src/lib/interfaces/responses/portfolio-report.interface.ts

@ -1,7 +1,7 @@
import { PortfolioReportRule } from '../portfolio-report-rule.interface'; import { PortfolioReportRule } from '../portfolio-report-rule.interface';
export interface PortfolioReportResponse { export interface PortfolioReportResponse {
'x-ray': { xRay: {
rules: { [group: string]: PortfolioReportRule[] }; rules: { [group: string]: PortfolioReportRule[] };
statistics: { statistics: {
rulesActiveCount: number; rulesActiveCount: number;

50
libs/ui/src/lib/membership-card/membership-card.component.stories.ts

@ -0,0 +1,50 @@
import { CommonModule } from '@angular/common';
import '@angular/localize/init';
import { MatButtonModule } from '@angular/material/button';
import { ActivatedRoute, RouterModule } from '@angular/router';
import { IonIcon } from '@ionic/angular/standalone';
import { moduleMetadata } from '@storybook/angular';
import type { Meta, StoryObj } from '@storybook/angular';
import { addYears } from 'date-fns';
import { GfLogoComponent } from '../logo';
import { GfMembershipCardComponent } from './membership-card.component';
export default {
title: 'Membership Card',
component: GfMembershipCardComponent,
decorators: [
moduleMetadata({
imports: [
CommonModule,
GfLogoComponent,
IonIcon,
MatButtonModule,
RouterModule.forChild([])
],
providers: [{ provide: ActivatedRoute, useValue: {} }]
})
],
argTypes: {
name: {
control: { type: 'select' },
options: ['Basic', 'Premium']
}
}
} as Meta<GfMembershipCardComponent>;
type Story = StoryObj<GfMembershipCardComponent>;
export const Basic: Story = {
args: {
name: 'Basic'
}
};
export const Premium: Story = {
args: {
expiresAt: addYears(new Date(), 1).toLocaleDateString(),
hasPermissionToCreateApiKey: true,
name: 'Premium'
}
};

33760
package-lock.json

File diff suppressed because it is too large

70
package.json

@ -1,6 +1,6 @@
{ {
"name": "ghostfolio", "name": "ghostfolio",
"version": "2.185.0", "version": "2.186.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",
@ -56,17 +56,17 @@
"workspace-generator": "nx workspace-generator" "workspace-generator": "nx workspace-generator"
}, },
"dependencies": { "dependencies": {
"@angular/animations": "20.0.7", "@angular/animations": "20.1.3",
"@angular/cdk": "20.0.6", "@angular/cdk": "20.1.3",
"@angular/common": "20.0.7", "@angular/common": "20.1.3",
"@angular/compiler": "20.0.7", "@angular/compiler": "20.1.3",
"@angular/core": "20.0.7", "@angular/core": "20.1.3",
"@angular/forms": "20.0.7", "@angular/forms": "20.1.3",
"@angular/material": "20.0.6", "@angular/material": "20.1.3",
"@angular/platform-browser": "20.0.7", "@angular/platform-browser": "20.1.3",
"@angular/platform-browser-dynamic": "20.0.7", "@angular/platform-browser-dynamic": "20.1.3",
"@angular/router": "20.0.7", "@angular/router": "20.1.3",
"@angular/service-worker": "20.0.7", "@angular/service-worker": "20.1.3",
"@codewithdan/observable-store": "2.2.15", "@codewithdan/observable-store": "2.2.15",
"@date-fns/utc": "2.1.0", "@date-fns/utc": "2.1.0",
"@dfinity/agent": "0.15.7", "@dfinity/agent": "0.15.7",
@ -122,7 +122,7 @@
"lodash": "4.17.21", "lodash": "4.17.21",
"marked": "15.0.4", "marked": "15.0.4",
"ms": "3.0.0-canary.1", "ms": "3.0.0-canary.1",
"ng-extract-i18n-merge": "2.15.1", "ng-extract-i18n-merge": "3.0.0",
"ngx-device-detector": "10.0.2", "ngx-device-detector": "10.0.2",
"ngx-markdown": "20.0.0", "ngx-markdown": "20.0.0",
"ngx-skeleton-loader": "11.2.1", "ngx-skeleton-loader": "11.2.1",
@ -143,33 +143,33 @@
"zone.js": "0.15.1" "zone.js": "0.15.1"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "20.0.6", "@angular-devkit/build-angular": "20.1.3",
"@angular-devkit/core": "20.0.6", "@angular-devkit/core": "20.1.3",
"@angular-devkit/schematics": "20.0.6", "@angular-devkit/schematics": "20.1.3",
"@angular-eslint/eslint-plugin": "20.1.1", "@angular-eslint/eslint-plugin": "20.1.1",
"@angular-eslint/eslint-plugin-template": "20.1.1", "@angular-eslint/eslint-plugin-template": "20.1.1",
"@angular-eslint/template-parser": "20.1.1", "@angular-eslint/template-parser": "20.1.1",
"@angular/cli": "20.0.6", "@angular/cli": "20.1.3",
"@angular/compiler-cli": "20.0.7", "@angular/compiler-cli": "20.1.3",
"@angular/language-service": "20.0.7", "@angular/language-service": "20.1.3",
"@angular/localize": "20.0.7", "@angular/localize": "20.1.3",
"@angular/pwa": "20.0.6", "@angular/pwa": "20.1.3",
"@eslint/eslintrc": "3.3.1", "@eslint/eslintrc": "3.3.1",
"@eslint/js": "9.24.0", "@eslint/js": "9.24.0",
"@nestjs/schematics": "11.0.5", "@nestjs/schematics": "11.0.5",
"@nestjs/testing": "11.1.3", "@nestjs/testing": "11.1.3",
"@nx/angular": "21.2.4", "@nx/angular": "21.3.9",
"@nx/cypress": "21.2.4", "@nx/cypress": "21.3.9",
"@nx/eslint-plugin": "21.2.4", "@nx/eslint-plugin": "21.3.9",
"@nx/jest": "21.2.4", "@nx/jest": "21.3.9",
"@nx/js": "21.2.4", "@nx/js": "21.3.9",
"@nx/module-federation": "21.2.4", "@nx/module-federation": "21.3.9",
"@nx/nest": "21.2.4", "@nx/nest": "21.3.9",
"@nx/node": "21.2.4", "@nx/node": "21.3.9",
"@nx/storybook": "21.2.4", "@nx/storybook": "21.3.9",
"@nx/web": "21.2.4", "@nx/web": "21.3.9",
"@nx/workspace": "21.2.4", "@nx/workspace": "21.3.9",
"@schematics/angular": "20.0.6", "@schematics/angular": "20.1.3",
"@storybook/addon-docs": "9.0.17", "@storybook/addon-docs": "9.0.17",
"@storybook/angular": "9.0.17", "@storybook/angular": "9.0.17",
"@trivago/prettier-plugin-sort-imports": "5.2.2", "@trivago/prettier-plugin-sort-imports": "5.2.2",
@ -193,7 +193,7 @@
"jest": "29.7.0", "jest": "29.7.0",
"jest-environment-jsdom": "29.7.0", "jest-environment-jsdom": "29.7.0",
"jest-preset-angular": "14.6.0", "jest-preset-angular": "14.6.0",
"nx": "21.2.4", "nx": "21.3.9",
"prettier": "3.6.2", "prettier": "3.6.2",
"prettier-plugin-organize-attributes": "1.0.0", "prettier-plugin-organize-attributes": "1.0.0",
"prisma": "6.12.0", "prisma": "6.12.0",
@ -202,7 +202,7 @@
"replace-in-file": "8.3.0", "replace-in-file": "8.3.0",
"shx": "0.3.4", "shx": "0.3.4",
"storybook": "9.0.17", "storybook": "9.0.17",
"ts-jest": "29.1.0", "ts-jest": "29.4.0",
"ts-node": "10.9.2", "ts-node": "10.9.2",
"tslib": "2.8.1", "tslib": "2.8.1",
"typescript": "5.8.3", "typescript": "5.8.3",

Loading…
Cancel
Save