Browse Source

Merge remote-tracking branch 'upstream/main' into feature/top-holdings-with-parents

pull/4044/head
JoryHogeveen 9 months ago
parent
commit
588f592ff3
  1. 18
      CHANGELOG.md
  2. 10
      apps/api/src/app/admin/admin.controller.ts
  3. 23
      apps/api/src/app/admin/admin.service.ts
  4. 4
      apps/api/src/assets/sitemap.xml
  5. 4
      apps/api/src/middlewares/html-template.middleware.ts
  6. 30
      apps/client/src/app/components/home-holdings/home-holdings.html
  7. 188
      apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
  8. 3
      apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.scss
  9. 17
      apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.component.ts
  10. 180
      apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.html
  11. 27
      apps/client/src/app/pages/blog/blog-page-routing.module.ts
  12. 26
      apps/client/src/app/pages/blog/blog-page.html
  13. 6
      apps/client/src/app/services/admin.service.ts
  14. BIN
      apps/client/src/assets/images/blog/black-weeks-2024.jpg
  15. 322
      apps/client/src/locales/messages.ca.xlf
  16. 326
      apps/client/src/locales/messages.de.xlf
  17. 322
      apps/client/src/locales/messages.es.xlf
  18. 322
      apps/client/src/locales/messages.fr.xlf
  19. 342
      apps/client/src/locales/messages.it.xlf
  20. 322
      apps/client/src/locales/messages.nl.xlf
  21. 322
      apps/client/src/locales/messages.pl.xlf
  22. 322
      apps/client/src/locales/messages.pt.xlf
  23. 322
      apps/client/src/locales/messages.tr.xlf
  24. 316
      apps/client/src/locales/messages.xlf
  25. 322
      apps/client/src/locales/messages.zh.xlf
  26. 704
      package-lock.json
  27. 28
      package.json

18
CHANGELOG.md

@ -7,12 +7,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased
### Added
- Added pagination parameters (`skip`, `take`) to the endpoint `GET api/v1/admin/user`
### Changed
- Upgraded `Nx` from version `20.0.6` to `20.1.2`
## 2.123.0 - 2024-11-16
### Added
- Added a blog post: _Black Weeks 2024_
### Changed
- Moved the chart of the holdings tab on the home page from experimental to general availability
- Extended the assistant by a holding selector
- Separated the _FIRE_ / _X-ray_ page
- Improved the usability to customize the rule thresholds in the _X-ray_ page by introducing range sliders (experimental)
- Improved the language localization for German (`de`)
- Improved the language localization for Italian (`it`)
- Upgraded `ngx-skeleton-loader` from version `7.0.0` to `9.0.0`
- Upgraded `prisma` from version `5.21.1` to `5.22.0`
- Upgraded `uuid` from version `9.0.1` to `11.0.2`
## 2.122.0 - 2024-11-07

10
apps/api/src/app/admin/admin.controller.ts

@ -352,7 +352,13 @@ export class AdminController {
@Get('user')
@HasPermission(permissions.accessAdminControl)
@UseGuards(AuthGuard('jwt'), HasPermissionGuard)
public async getUsers(): Promise<AdminUsers> {
return this.adminService.getUsers();
public async getUsers(
@Query('skip') skip?: number,
@Query('take') take?: number
): Promise<AdminUsers> {
return this.adminService.getUsers({
skip: isNaN(skip) ? undefined : skip,
take: isNaN(take) ? undefined : take
});
}
}

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

@ -429,8 +429,14 @@ export class AdminService {
};
}
public async getUsers(): Promise<AdminUsers> {
return { users: await this.getUsersWithAnalytics() };
public async getUsers({
skip,
take = Number.MAX_SAFE_INTEGER
}: {
skip?: number;
take?: number;
}): Promise<AdminUsers> {
return { users: await this.getUsersWithAnalytics({ skip, take }) };
}
public async patchAssetProfileData({
@ -640,7 +646,13 @@ export class AdminService {
return { marketData, count: marketData.length };
}
private async getUsersWithAnalytics(): Promise<AdminUsers['users']> {
private async getUsersWithAnalytics({
skip,
take
}: {
skip?: number;
take?: number;
}): Promise<AdminUsers['users']> {
let orderBy: Prisma.UserOrderByWithRelationInput = {
createdAt: 'desc'
};
@ -661,6 +673,8 @@ export class AdminService {
const usersWithAnalytics = await this.prismaService.user.findMany({
orderBy,
skip,
take,
where,
select: {
_count: {
@ -677,8 +691,7 @@ export class AdminService {
id: true,
role: true,
Subscription: true
},
take: 30
}
});
return usersWithAnalytics.map(

4
apps/api/src/assets/sitemap.xml

@ -188,6 +188,10 @@
<loc>https://ghostfol.io/en/blog/2024/09/hacktoberfest-2024</loc>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/blog/2024/11/black-weeks-2024</loc>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/faq</loc>
<lastmod>${currentDate}T00:00:00+00:00</lastmod>

4
apps/api/src/middlewares/html-template.middleware.ts

@ -87,6 +87,10 @@ const locales = {
'/en/blog/2024/09/hacktoberfest-2024': {
featureGraphicPath: 'assets/images/blog/hacktoberfest-2024.png',
title: `Hacktoberfest 2024 - ${title}`
},
'/en/blog/2024/11/black-weeks-2024': {
featureGraphicPath: 'assets/images/blog/black-weeks-2024.jpg',
title: `Black Weeks 2024 - ${title}`
}
};

30
apps/client/src/app/components/home-holdings/home-holdings.html

@ -7,23 +7,21 @@
<div class="row">
<div class="col-lg">
<div class="d-flex">
@if (user?.settings?.isExperimentalFeatures) {
<div class="d-flex">
<div class="d-none d-lg-block">
<mat-button-toggle-group
[formControl]="viewModeFormControl"
[hideSingleSelectionIndicator]="true"
>
<mat-button-toggle i18n-title title="Table" value="TABLE">
<ion-icon name="reorder-four-outline" />
</mat-button-toggle>
<mat-button-toggle i18n-title title="Chart" value="CHART">
<ion-icon name="grid-outline" />
</mat-button-toggle>
</mat-button-toggle-group>
</div>
<div class="d-flex">
<div class="d-none d-lg-block">
<mat-button-toggle-group
[formControl]="viewModeFormControl"
[hideSingleSelectionIndicator]="true"
>
<mat-button-toggle i18n-title title="Table" value="TABLE">
<ion-icon name="reorder-four-outline" />
</mat-button-toggle>
<mat-button-toggle i18n-title title="Chart" value="CHART">
<ion-icon name="grid-outline" />
</mat-button-toggle>
</mat-button-toggle-group>
</div>
}
</div>
<div class="align-items-center d-flex flex-grow-1 justify-content-end">
<gf-toggle
class="d-none d-lg-block"

188
apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html

@ -1,76 +1,128 @@
<div mat-dialog-title>{{ data.rule.name }}</div>
<div class="py-3" mat-dialog-content>
<div
class="w-100"
[ngClass]="{ 'd-none': !data.rule.configuration.thresholdMin }"
>
<h6 class="mb-0">
<ng-container i18n>Threshold Min</ng-container>:
@if (data.rule.configuration.threshold.unit === '%') {
{{ data.settings.thresholdMin | percent: '1.2-2' }}
} @else {
{{ data.settings.thresholdMin }}
}
</h6>
@if (data.rule.configuration.threshold.unit === '%') {
<label>{{
data.rule.configuration.threshold.min | percent: '1.2-2'
}}</label>
} @else {
<label>{{ data.rule.configuration.threshold.min }}</label>
}
<mat-slider
name="thresholdMin"
[max]="data.rule.configuration.threshold.max"
[min]="data.rule.configuration.threshold.min"
[step]="data.rule.configuration.threshold.step"
@if (
data.rule.configuration.thresholdMin && data.rule.configuration.thresholdMax
) {
<div class="w-100">
<h6 class="mb-0">
<ng-container i18n>Threshold range</ng-container>:
@if (data.rule.configuration.threshold.unit === '%') {
{{ data.settings.thresholdMin | percent: '1.2-2' }}
} @else {
{{ data.settings.thresholdMin }}
}
-
@if (data.rule.configuration.threshold.unit === '%') {
{{ data.settings.thresholdMax | percent: '1.2-2' }}
} @else {
{{ data.settings.thresholdMax }}
}
</h6>
<div class="align-items-center d-flex w-100">
@if (data.rule.configuration.threshold.unit === '%') {
<label>{{
data.rule.configuration.threshold.min | percent: '1.2-2'
}}</label>
} @else {
<label>{{ data.rule.configuration.threshold.min }}</label>
}
<mat-slider
class="flex-grow-1"
[max]="data.rule.configuration.threshold.max"
[min]="data.rule.configuration.threshold.min"
[step]="data.rule.configuration.threshold.step"
>
<input matSliderStartThumb [(ngModel)]="data.settings.thresholdMin" />
<input matSliderEndThumb [(ngModel)]="data.settings.thresholdMax" />
</mat-slider>
@if (data.rule.configuration.threshold.unit === '%') {
<label>{{
data.rule.configuration.threshold.max | percent: '1.2-2'
}}</label>
} @else {
<label>{{ data.rule.configuration.threshold.max }}</label>
}
</div>
</div>
} @else {
<div
class="w-100"
[ngClass]="{ 'd-none': !data.rule.configuration.thresholdMin }"
>
<input matSliderThumb [(ngModel)]="data.settings.thresholdMin" />
</mat-slider>
@if (data.rule.configuration.threshold.unit === '%') {
<label>{{
data.rule.configuration.threshold.max | percent: '1.2-2'
}}</label>
} @else {
<label>{{ data.rule.configuration.threshold.max }}</label>
}
</div>
<div
class="w-100"
[ngClass]="{ 'd-none': !data.rule.configuration.thresholdMax }"
>
<h6 class="mb-0">
<ng-container i18n>Threshold Max</ng-container>:
@if (data.rule.configuration.threshold.unit === '%') {
{{ data.settings.thresholdMax | percent: '1.2-2' }}
} @else {
{{ data.settings.thresholdMax }}
}
</h6>
@if (data.rule.configuration.threshold.unit === '%') {
<label>{{
data.rule.configuration.threshold.min | percent: '1.2-2'
}}</label>
} @else {
<label>{{ data.rule.configuration.threshold.min }}</label>
}
<mat-slider
name="thresholdMax"
[max]="data.rule.configuration.threshold.max"
[min]="data.rule.configuration.threshold.min"
[step]="data.rule.configuration.threshold.step"
<h6 class="mb-0">
<ng-container i18n>Threshold Min</ng-container>:
@if (data.rule.configuration.threshold.unit === '%') {
{{ data.settings.thresholdMin | percent: '1.2-2' }}
} @else {
{{ data.settings.thresholdMin }}
}
</h6>
<div class="align-items-center d-flex w-100">
@if (data.rule.configuration.threshold.unit === '%') {
<label>{{
data.rule.configuration.threshold.min | percent: '1.2-2'
}}</label>
} @else {
<label>{{ data.rule.configuration.threshold.min }}</label>
}
<mat-slider
class="flex-grow-1"
name="thresholdMin"
[max]="data.rule.configuration.threshold.max"
[min]="data.rule.configuration.threshold.min"
[step]="data.rule.configuration.threshold.step"
>
<input matSliderThumb [(ngModel)]="data.settings.thresholdMin" />
</mat-slider>
@if (data.rule.configuration.threshold.unit === '%') {
<label>{{
data.rule.configuration.threshold.max | percent: '1.2-2'
}}</label>
} @else {
<label>{{ data.rule.configuration.threshold.max }}</label>
}
</div>
</div>
<div
class="w-100"
[ngClass]="{ 'd-none': !data.rule.configuration.thresholdMax }"
>
<input matSliderThumb [(ngModel)]="data.settings.thresholdMax" />
</mat-slider>
@if (data.rule.configuration.threshold.unit === '%') {
<label>{{
data.rule.configuration.threshold.max | percent: '1.2-2'
}}</label>
} @else {
<label>{{ data.rule.configuration.threshold.max }}</label>
}
</div>
<h6 class="mb-0">
<ng-container i18n>Threshold Max</ng-container>:
@if (data.rule.configuration.threshold.unit === '%') {
{{ data.settings.thresholdMax | percent: '1.2-2' }}
} @else {
{{ data.settings.thresholdMax }}
}
</h6>
<div class="align-items-center d-flex w-100">
@if (data.rule.configuration.threshold.unit === '%') {
<label>{{
data.rule.configuration.threshold.min | percent: '1.2-2'
}}</label>
} @else {
<label>{{ data.rule.configuration.threshold.min }}</label>
}
<mat-slider
class="flex-grow-1"
name="thresholdMax"
[max]="data.rule.configuration.threshold.max"
[min]="data.rule.configuration.threshold.min"
[step]="data.rule.configuration.threshold.step"
>
<input matSliderThumb [(ngModel)]="data.settings.thresholdMax" />
</mat-slider>
@if (data.rule.configuration.threshold.unit === '%') {
<label>{{
data.rule.configuration.threshold.max | percent: '1.2-2'
}}</label>
} @else {
<label>{{ data.rule.configuration.threshold.max }}</label>
}
</div>
</div>
}
</div>
<div align="end" mat-dialog-actions>

3
apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.scss

@ -1,2 +1,5 @@
:host {
label {
margin-bottom: 0;
}
}

17
apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.component.ts

@ -0,0 +1,17 @@
import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator';
import { Component } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { RouterModule } from '@angular/router';
@Component({
host: { class: 'page' },
imports: [GfPremiumIndicatorComponent, MatButtonModule, RouterModule],
selector: 'gf-black-weeks-2024-page',
standalone: true,
templateUrl: './black-weeks-2024-page.html'
})
export class BlackWeeks2024PageComponent {
public routerLinkFeatures = ['/' + $localize`:snake-case:features`];
public routerLinkPricing = ['/' + $localize`:snake-case:pricing`];
}

180
apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.html

@ -0,0 +1,180 @@
<div class="blog container">
<div class="row">
<div class="col-md-8 offset-md-2">
<article>
<div class="mb-4 text-center">
<h1 class="mb-1">Black Weeks 2024</h1>
<div class="mb-3 text-muted"><small>2024-11-16</small></div>
<img
alt="Black Week 2024 Teaser"
class="rounded w-100"
src="../assets/images/blog/black-weeks-2024.jpg"
title="Black Weeks 2024"
/>
</div>
<section class="mb-4">
<p>
Take advantage of our exclusive <strong>Black Weeks</strong> offer
and save <strong>25%</strong> on your annual
<span class="align-items-center d-inline-flex"
>Ghostfolio Premium
<gf-premium-indicator
class="d-inline-block ml-1"
[enableLink]="false"
/>
</span>
subscription, plus get <strong>3 months extra</strong> for free!
</p>
</section>
<section class="mb-4">
<p>
<a
href="https://ghostfol.io"
title="Open Source Wealth Management Software"
>Ghostfolio</a
>
is a powerful personal finance dashboard, designed to simplify your
investment journey. With this Open Source Software (OSS) platform,
you can:
</p>
<ul class="list-unstyled">
<li>
<strong>Unify your assets</strong>: Track your financial
portfolio, including stocks, ETFs, cryptocurrencies, etc.
</li>
<li>
<strong>Gain deeper insights</strong>: Access real-time analytics
and data-driven insights.
</li>
<li>
<strong>Make informed decisions</strong>: Empower yourself with
actionable information.
</li>
</ul>
</section>
<section class="mb-4">
<p>
Don’t miss this limited-time offer to optimize your financial
future.
</p>
<p class="text-center">
<a color="primary" mat-flat-button [routerLink]="routerLinkPricing"
>Get the Deal</a
>
</p>
<p class="mt-5">
For more information, visit our
<a [routerLink]="routerLinkPricing">pricing page</a>.
</p>
</section>
<section class="mb-4">
<ul class="list-inline">
<li class="list-inline-item">
<span class="badge badge-light">2024</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Black Friday</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Black Weeks</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Cryptocurrency</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Dashboard</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Deal</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">DeFi</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">ETF</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Finance</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">Ghostfolio</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Ghostfolio Premium</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Hosting</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">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">Portfolio</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Portfolio Tracker</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Pricing</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Promotion</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">SaaS</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Sale</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">Stock</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Subscription</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">Wealth Management</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Web3</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Web 3.0</span>
</li>
</ul>
</section>
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a i18n [routerLink]="['/blog']">Blog</a>
</li>
<li
aria-current="page"
class="active breadcrumb-item text-truncate"
>
Black Weeks 2024
</li>
</ol>
</nav>
</article>
</div>
</div>
</div>

27
apps/client/src/app/pages/blog/blog-page-routing.module.ts

@ -165,15 +165,6 @@ const routes: Routes = [
).then((c) => c.Hacktoberfest2023PageComponent),
title: 'Hacktoberfest 2023'
},
{
canActivate: [AuthGuard],
path: '2023/11/hacktoberfest-2023-debriefing',
loadComponent: () =>
import(
'./2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.component'
).then((c) => c.Hacktoberfest2023DebriefingPageComponent),
title: 'Hacktoberfest 2023 Debriefing'
},
{
canActivate: [AuthGuard],
path: '2023/11/black-week-2023',
@ -183,6 +174,15 @@ const routes: Routes = [
),
title: 'Black Week 2023'
},
{
canActivate: [AuthGuard],
path: '2023/11/hacktoberfest-2023-debriefing',
loadComponent: () =>
import(
'./2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.component'
).then((c) => c.Hacktoberfest2023DebriefingPageComponent),
title: 'Hacktoberfest 2023 Debriefing'
},
{
canActivate: [AuthGuard],
path: '2024/09/hacktoberfest-2024',
@ -191,6 +191,15 @@ const routes: Routes = [
'./2024/09/hacktoberfest-2024/hacktoberfest-2024-page.component'
).then((c) => c.Hacktoberfest2024PageComponent),
title: 'Hacktoberfest 2024'
},
{
canActivate: [AuthGuard],
path: '2024/11/black-weeks-2024',
loadComponent: () =>
import('./2024/11/black-weeks-2024/black-weeks-2024-page.component').then(
(c) => c.BlackWeeks2024PageComponent
),
title: 'Black Weeks 2024'
}
];

26
apps/client/src/app/pages/blog/blog-page.html

@ -8,6 +8,32 @@
finance</small
>
</h1>
@if (hasPermissionForSubscription) {
<mat-card appearance="outlined" class="mb-3">
<mat-card-content class="p-0">
<div class="container p-0">
<div class="flex-nowrap no-gutters row">
<a
class="d-flex overflow-hidden p-3 w-100"
href="../en/blog/2024/11/black-weeks-2024"
>
<div class="flex-grow-1 overflow-hidden">
<div class="h6 m-0 text-truncate">Black Weeks 2024</div>
<div class="d-flex text-muted">2024-11-16</div>
</div>
<div class="align-items-center d-flex">
<ion-icon
class="chevron text-muted"
name="chevron-forward-outline"
size="small"
/>
</div>
</a>
</div>
</div>
</mat-card-content>
</mat-card>
}
<mat-card appearance="outlined" class="mb-3">
<mat-card-content class="p-0">
<div class="container p-0">

6
apps/client/src/app/services/admin.service.ts

@ -157,7 +157,11 @@ export class AdminService {
}
public fetchUsers() {
return this.http.get<AdminUsers>('/api/v1/admin/user');
let params = new HttpParams();
params = params.append('take', 100);
return this.http.get<AdminUsers>('/api/v1/admin/user', { params });
}
public gather7Days() {

BIN
apps/client/src/assets/images/blog/black-weeks-2024.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 KiB

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

File diff suppressed because it is too large

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

File diff suppressed because it is too large

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

File diff suppressed because it is too large

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

File diff suppressed because it is too large

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

File diff suppressed because it is too large

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

File diff suppressed because it is too large

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

File diff suppressed because it is too large

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

File diff suppressed because it is too large

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

File diff suppressed because it is too large

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

File diff suppressed because it is too large

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

File diff suppressed because it is too large

704
package-lock.json

File diff suppressed because it is too large

28
package.json

@ -1,6 +1,6 @@
{
"name": "ghostfolio",
"version": "2.122.0",
"version": "2.123.0",
"homepage": "https://ghostfol.io",
"license": "AGPL-3.0",
"repository": "https://github.com/ghostfolio/ghostfolio",
@ -86,7 +86,7 @@
"@nestjs/platform-express": "10.1.3",
"@nestjs/schedule": "3.0.2",
"@nestjs/serve-static": "4.0.0",
"@prisma/client": "5.21.1",
"@prisma/client": "5.22.0",
"@simplewebauthn/browser": "9.0.1",
"@simplewebauthn/server": "9.0.3",
"@stripe/stripe-js": "4.9.0",
@ -153,16 +153,16 @@
"@angular/pwa": "18.2.9",
"@nestjs/schematics": "10.0.1",
"@nestjs/testing": "10.1.3",
"@nx/angular": "20.0.6",
"@nx/cypress": "20.0.6",
"@nx/eslint-plugin": "20.0.6",
"@nx/jest": "20.0.6",
"@nx/js": "20.0.6",
"@nx/nest": "20.0.6",
"@nx/node": "20.0.6",
"@nx/storybook": "20.0.6",
"@nx/web": "20.0.6",
"@nx/workspace": "20.0.6",
"@nx/angular": "20.1.2",
"@nx/cypress": "20.1.2",
"@nx/eslint-plugin": "20.1.2",
"@nx/jest": "20.1.2",
"@nx/js": "20.1.2",
"@nx/nest": "20.1.2",
"@nx/node": "20.1.2",
"@nx/storybook": "20.1.2",
"@nx/web": "20.1.2",
"@nx/workspace": "20.1.2",
"@schematics/angular": "18.2.9",
"@simplewebauthn/types": "9.0.1",
"@storybook/addon-essentials": "8.3.6",
@ -193,10 +193,10 @@
"jest": "29.7.0",
"jest-environment-jsdom": "29.7.0",
"jest-preset-angular": "14.1.0",
"nx": "20.0.6",
"nx": "20.1.2",
"prettier": "3.3.3",
"prettier-plugin-organize-attributes": "1.0.0",
"prisma": "5.21.1",
"prisma": "5.22.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"replace-in-file": "7.0.1",

Loading…
Cancel
Save