From 7e8593e27fa2232764f8426d17857bc7ba117ac9 Mon Sep 17 00:00:00 2001 From: Kenrick Tandrian <60643640+KenTandrian@users.noreply.github.com> Date: Sat, 23 May 2026 02:44:04 +0700 Subject: [PATCH 1/2] Task/improve type safety for home market component (#6921) * feat(client): resolve error * feat(client): enforce encapsulation * feat(client): enforce immutability * feat(client): replace constructor based DI with inject function * feat(client): replace deprecated getDeviceInfo * feat(client): convert benchmarks to signal * feat(client): convert historicalDataItems to signal * feat(client): convert fearAndGreedIndex to signal --- .../home-market/home-market.component.ts | 60 ++++++++++--------- .../components/home-market/home-market.html | 10 ++-- 2 files changed, 37 insertions(+), 33 deletions(-) diff --git a/apps/client/src/app/components/home-market/home-market.component.ts b/apps/client/src/app/components/home-market/home-market.component.ts index cb645f2ef..dd0c38cea 100644 --- a/apps/client/src/app/components/home-market/home-market.component.ts +++ b/apps/client/src/app/components/home-market/home-market.component.ts @@ -16,9 +16,12 @@ import { DataService } from '@ghostfolio/ui/services'; import { ChangeDetectorRef, Component, + computed, CUSTOM_ELEMENTS_SCHEMA, DestroyRef, - OnInit + inject, + OnInit, + signal } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { DeviceDetectorService } from 'ngx-device-detector'; @@ -35,25 +38,27 @@ import { DeviceDetectorService } from 'ngx-device-detector'; templateUrl: './home-market.html' }) export class GfHomeMarketComponent implements OnInit { - public benchmarks: Benchmark[]; - public deviceType: string; - public fearAndGreedIndex: number; - public fearLabel = $localize`Fear`; - public greedLabel = $localize`Greed`; - public hasPermissionToAccessFearAndGreedIndex: boolean; - public historicalDataItems: HistoricalDataItem[]; - public info: InfoItem; - public readonly numberOfDays = 365; - public user: User; + protected readonly benchmarks = signal([]); + protected readonly deviceType = computed( + () => this.deviceDetectorService.deviceInfo().deviceType + ); + protected readonly fearAndGreedIndex = signal(undefined); + protected readonly fearLabel = $localize`Fear`; + protected readonly greedLabel = $localize`Greed`; + protected hasPermissionToAccessFearAndGreedIndex: boolean; + protected readonly historicalDataItems = signal([]); + protected readonly numberOfDays = 365; + protected user: User; - public constructor( - private changeDetectorRef: ChangeDetectorRef, - private dataService: DataService, - private destroyRef: DestroyRef, - private deviceDetectorService: DeviceDetectorService, - private userService: UserService - ) { - this.deviceType = this.deviceDetectorService.getDeviceInfo().deviceType; + private readonly info: InfoItem; + + private readonly changeDetectorRef = inject(ChangeDetectorRef); + private readonly dataService = inject(DataService); + private readonly destroyRef = inject(DestroyRef); + private readonly deviceDetectorService = inject(DeviceDetectorService); + private readonly userService = inject(UserService); + + public constructor() { this.info = this.dataService.fetchInfo(); this.userService.stateChanged @@ -73,7 +78,10 @@ export class GfHomeMarketComponent implements OnInit { permissions.enableFearAndGreedIndex ); - if (this.hasPermissionToAccessFearAndGreedIndex) { + if ( + this.hasPermissionToAccessFearAndGreedIndex && + this.info.fearAndGreedDataSource + ) { this.dataService .fetchSymbolItem({ dataSource: this.info.fearAndGreedDataSource, @@ -82,16 +90,14 @@ export class GfHomeMarketComponent implements OnInit { }) .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ historicalData, marketPrice }) => { - this.fearAndGreedIndex = marketPrice; - this.historicalDataItems = [ + this.fearAndGreedIndex.set(marketPrice); + this.historicalDataItems.set([ ...historicalData, { date: resetHours(new Date()).toISOString(), value: marketPrice } - ]; - - this.changeDetectorRef.markForCheck(); + ]); }); } @@ -99,9 +105,7 @@ export class GfHomeMarketComponent implements OnInit { .fetchBenchmarks() .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ benchmarks }) => { - this.benchmarks = benchmarks; - - this.changeDetectorRef.markForCheck(); + this.benchmarks.set(benchmarks); }); } } diff --git a/apps/client/src/app/components/home-market/home-market.html b/apps/client/src/app/components/home-market/home-market.html index fc7230d35..a782526ee 100644 --- a/apps/client/src/app/components/home-market/home-market.html +++ b/apps/client/src/app/components/home-market/home-market.html @@ -10,7 +10,7 @@ class="mb-3" label="Fear & Greed Index" [colorScheme]="user?.settings?.colorScheme" - [historicalDataItems]="historicalDataItems" + [historicalDataItems]="historicalDataItems()" [isAnimated]="true" [locale]="user?.settings?.locale || undefined" [showXAxis]="true" @@ -22,7 +22,7 @@ /> @@ -31,13 +31,13 @@
- @if (benchmarks?.length > 0) { + @if (benchmarks()?.length > 0) {
From 229ff5947841eeb797672565fa39de040041ee06 Mon Sep 17 00:00:00 2001 From: Dmytro Shatokhin <111596676+Trillianti@users.noreply.github.com> Date: Fri, 22 May 2026 22:59:46 +0300 Subject: [PATCH 2/2] Task/upgrade @keyv/redis to v5 (#6917) * Upgrade @keyv/redis to v5 * Update changelog --- CHANGELOG.md | 6 ++++++ package-lock.json | 51 ++++++++++++++++++++++++----------------------- package.json | 2 +- 3 files changed, 33 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 233f02bbc..7cee9179d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Changed + +- Upgraded `@keyv/redis` from version `4.4.0` to `5.1.6` + ## 3.4.0 - 2026-05-21 ### Added diff --git a/package-lock.json b/package-lock.json index 34f63f0b0..9034b3eb6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "@date-fns/utc": "2.1.1", "@internationalized/number": "3.6.6", "@ionic/angular": "8.8.5", - "@keyv/redis": "4.4.0", + "@keyv/redis": "5.1.6", "@nestjs/bull": "11.0.4", "@nestjs/cache-manager": "3.1.0", "@nestjs/common": "11.1.19", @@ -7144,19 +7144,20 @@ } }, "node_modules/@keyv/redis": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@keyv/redis/-/redis-4.4.0.tgz", - "integrity": "sha512-n/KEj3S7crVkoykggqsMUtcjNGvjagGPlJYgO/r6m9hhGZfhp1txJElHxcdJ1ANi/LJoBuOSILj15g6HD2ucqQ==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/@keyv/redis/-/redis-5.1.6.tgz", + "integrity": "sha512-eKvW6pspvVaU5dxigaIDZr635/Uw6urTXL3gNbY9WTR8d3QigZQT+r8gxYSEOsw4+1cCBsC4s7T2ptR0WC9LfQ==", "license": "MIT", "dependencies": { - "@redis/client": "^1.6.0", - "cluster-key-slot": "^1.1.2" + "@redis/client": "^5.10.0", + "cluster-key-slot": "^1.1.2", + "hookified": "^1.13.0" }, "engines": { "node": ">= 18" }, "peerDependencies": { - "keyv": "^5.3.3" + "keyv": "^5.6.0" } }, "node_modules/@keyv/serialize": { @@ -11664,17 +11665,27 @@ } }, "node_modules/@redis/client": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.6.1.tgz", - "integrity": "sha512-/KCsg3xSlR+nCK8/8ZYSknYxvXHwubJrU82F3Lm1Fp6789VQ0/3RJKfsmRXjqfaTA++23CvC3hqmqe/2GEt6Kw==", + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-5.12.1.tgz", + "integrity": "sha512-7aPGWeqA3uFm43o19umzdl16CEjK/JQGtSXVPevplTaOU3VJA/rseBC1QvYUz9lLDIMBimc4SW/zrW4S89BaCA==", "license": "MIT", "dependencies": { - "cluster-key-slot": "1.1.2", - "generic-pool": "3.9.0", - "yallist": "4.0.0" + "cluster-key-slot": "1.1.2" }, "engines": { - "node": ">=14" + "node": ">= 18.19.0" + }, + "peerDependencies": { + "@node-rs/xxhash": "^1.1.0", + "@opentelemetry/api": ">=1 <2" + }, + "peerDependenciesMeta": { + "@node-rs/xxhash": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + } } }, "node_modules/@rolldown/binding-android-arm64": { @@ -23191,15 +23202,6 @@ "node": ">= 0.4" } }, - "node_modules/generic-pool": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", - "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==", - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -23818,8 +23820,7 @@ "version": "1.15.1", "resolved": "https://registry.npmjs.org/hookified/-/hookified-1.15.1.tgz", "integrity": "sha512-MvG/clsADq1GPM2KGo2nyfaWVyn9naPiXrqIe4jYjXNZQt238kWyOGrsyc/DmRAQ+Re6yeo6yX/yoNCG5KAEVg==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/hosted-git-info": { "version": "9.0.2", diff --git a/package.json b/package.json index 0578cd7de..5bc9e7971 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ "@date-fns/utc": "2.1.1", "@internationalized/number": "3.6.6", "@ionic/angular": "8.8.5", - "@keyv/redis": "4.4.0", + "@keyv/redis": "5.1.6", "@nestjs/bull": "11.0.4", "@nestjs/cache-manager": "3.1.0", "@nestjs/common": "11.1.19",