Browse Source

Task/migrate services to Angular 22 @Service() (#7671)

* Migrate services to Angular 22 @Service()

* Update changelog

---------

Co-authored-by: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
pull/7675/head
Shubham Raghav 8 hours ago
committed by GitHub
parent
commit
5af0c7f1c0
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 1
      CHANGELOG.md
  2. 3
      apps/client/src/app/adapter/custom-date-adapter.ts
  3. 10
      apps/client/src/app/components/admin-market-data/admin-market-data.service.ts
  4. 4
      apps/client/src/app/core/auth.guard.ts
  5. 4
      apps/client/src/app/core/auth.interceptor.ts
  6. 4
      apps/client/src/app/core/http-response.interceptor.ts
  7. 4
      apps/client/src/app/core/language.service.ts
  8. 18
      apps/client/src/app/core/layout.service.ts
  9. 4
      apps/client/src/app/core/module-preload.service.ts
  10. 8
      apps/client/src/app/services/cache.service.ts
  11. 6
      apps/client/src/app/services/ics/ics.service.ts
  12. 6
      apps/client/src/app/services/impersonation-storage.service.ts
  13. 6
      apps/client/src/app/services/import-activities.service.ts
  14. 8
      apps/client/src/app/services/page-title.strategy.ts
  15. 6
      apps/client/src/app/services/settings-storage.service.ts
  16. 6
      apps/client/src/app/services/token-storage.service.ts
  17. 6
      apps/client/src/app/services/user/user.service.ts
  18. 6
      apps/client/src/app/services/web-authn.service.ts
  19. 8
      apps/client/src/main.ts
  20. 9
      libs/ui/src/lib/entity-logo/entity-logo-image-source.service.ts
  21. 4
      libs/ui/src/lib/fire-calculator/fire-calculator.service.ts
  22. 4
      libs/ui/src/lib/notifications/notification.service.ts
  23. 6
      libs/ui/src/lib/services/admin.service.ts
  24. 6
      libs/ui/src/lib/services/data.service.ts

1
CHANGELOG.md

@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed ### Changed
- Improved the sorting to be case-insensitive in the account selector component - Improved the sorting to be case-insensitive in the account selector component
- Refactored the services to use the `@Service()` decorator of _Angular_
## 3.55.0 - 2026-08-19 ## 3.55.0 - 2026-08-19

3
apps/client/src/app/adapter/custom-date-adapter.ts

@ -1,9 +1,10 @@
import { getDateFormatString } from '@ghostfolio/common/helper'; import { getDateFormatString } from '@ghostfolio/common/helper';
import { inject } from '@angular/core'; import { inject, Service } from '@angular/core';
import { MAT_DATE_LOCALE, NativeDateAdapter } from '@angular/material/core'; import { MAT_DATE_LOCALE, NativeDateAdapter } from '@angular/material/core';
import { addYears, format, getYear, parse } from 'date-fns'; import { addYears, format, getYear, parse } from 'date-fns';
@Service({ autoProvided: false })
export class CustomDateAdapter extends NativeDateAdapter { export class CustomDateAdapter extends NativeDateAdapter {
public override locale = inject<string>(MAT_DATE_LOCALE); public override locale = inject<string>(MAT_DATE_LOCALE);

10
apps/client/src/app/components/admin-market-data/admin-market-data.service.ts

@ -3,15 +3,13 @@ import { AssetProfileIdentifier } from '@ghostfolio/common/interfaces';
import { NotificationService } from '@ghostfolio/ui/notifications'; import { NotificationService } from '@ghostfolio/ui/notifications';
import { AdminService } from '@ghostfolio/ui/services'; import { AdminService } from '@ghostfolio/ui/services';
import { Injectable } from '@angular/core'; import { inject, Service } from '@angular/core';
import { EMPTY, Subject, catchError, finalize, forkJoin } from 'rxjs'; import { EMPTY, Subject, catchError, finalize, forkJoin } from 'rxjs';
@Injectable() @Service({ autoProvided: false })
export class AdminMarketDataService { export class AdminMarketDataService {
public constructor( private readonly adminService = inject(AdminService);
private adminService: AdminService, private readonly notificationService = inject(NotificationService);
private notificationService: NotificationService
) {}
public deleteAssetProfile({ dataSource, symbol }: AssetProfileIdentifier) { public deleteAssetProfile({ dataSource, symbol }: AssetProfileIdentifier) {
const assetProfileDeleted = new Subject<void>(); const assetProfileDeleted = new Subject<void>();

4
apps/client/src/app/core/auth.guard.ts

@ -3,7 +3,7 @@ import { UserService } from '@ghostfolio/client/services/user/user.service';
import { internalRoutes, publicRoutes } from '@ghostfolio/common/routes/routes'; import { internalRoutes, publicRoutes } from '@ghostfolio/common/routes/routes';
import { DataService } from '@ghostfolio/ui/services'; import { DataService } from '@ghostfolio/ui/services';
import { inject, Injectable } from '@angular/core'; import { inject, Service } from '@angular/core';
import { import {
ActivatedRouteSnapshot, ActivatedRouteSnapshot,
Router, Router,
@ -12,7 +12,7 @@ import {
import { EMPTY } from 'rxjs'; import { EMPTY } from 'rxjs';
import { catchError } from 'rxjs/operators'; import { catchError } from 'rxjs/operators';
@Injectable({ providedIn: 'root' }) @Service()
export class AuthGuard { export class AuthGuard {
private readonly dataService = inject(DataService); private readonly dataService = inject(DataService);
private readonly router = inject(Router); private readonly router = inject(Router);

4
apps/client/src/app/core/auth.interceptor.ts

@ -13,10 +13,10 @@ import {
HttpInterceptor, HttpInterceptor,
HttpRequest HttpRequest
} from '@angular/common/http'; } from '@angular/common/http';
import { inject, Injectable } from '@angular/core'; import { inject, Service } from '@angular/core';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
@Injectable() @Service({ autoProvided: false })
export class AuthInterceptor implements HttpInterceptor { export class AuthInterceptor implements HttpInterceptor {
private readonly impersonationStorageService = inject( private readonly impersonationStorageService = inject(
ImpersonationStorageService ImpersonationStorageService

4
apps/client/src/app/core/http-response.interceptor.ts

@ -14,7 +14,7 @@ import {
HttpInterceptor, HttpInterceptor,
HttpRequest HttpRequest
} from '@angular/common/http'; } from '@angular/common/http';
import { inject, Injectable } from '@angular/core'; import { inject, Service } from '@angular/core';
import { import {
MatSnackBar, MatSnackBar,
MatSnackBarRef, MatSnackBarRef,
@ -26,7 +26,7 @@ import ms from 'ms';
import { Observable, throwError } from 'rxjs'; import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators'; import { catchError } from 'rxjs/operators';
@Injectable() @Service({ autoProvided: false })
export class HttpResponseInterceptor implements HttpInterceptor { export class HttpResponseInterceptor implements HttpInterceptor {
private readonly info: InfoItem; private readonly info: InfoItem;
private snackBarRef: MatSnackBarRef<TextOnlySnackBar> | undefined; private snackBarRef: MatSnackBarRef<TextOnlySnackBar> | undefined;

4
apps/client/src/app/core/language.service.ts

@ -1,4 +0,0 @@
import { Injectable } from '@angular/core';
@Injectable()
export class LanguageService {}

18
apps/client/src/app/core/layout.service.ts

@ -1,24 +1,22 @@
import { NotificationService } from '@ghostfolio/ui/notifications'; import { NotificationService } from '@ghostfolio/ui/notifications';
import { Injectable } from '@angular/core'; import { inject, Service } from '@angular/core';
import { DeviceDetectorService } from 'ngx-device-detector'; import { DeviceDetectorService } from 'ngx-device-detector';
import { Observable, Subject } from 'rxjs'; import { Observable, Subject } from 'rxjs';
@Injectable({ @Service()
providedIn: 'root'
})
export class LayoutService { export class LayoutService {
public static readonly DEFAULT_NOTIFICATION_MAX_WIDTH = '50rem'; public static readonly DEFAULT_NOTIFICATION_MAX_WIDTH = '50rem';
public static readonly DEFAULT_NOTIFICATION_WIDTH = '75vw'; public static readonly DEFAULT_NOTIFICATION_WIDTH = '75vw';
public shouldReloadContent$: Observable<void>; public readonly shouldReloadContent$: Observable<void>;
private shouldReloadSubject = new Subject<void>(); private readonly shouldReloadSubject = new Subject<void>();
public constructor( private readonly deviceDetectorService = inject(DeviceDetectorService);
private deviceDetectorService: DeviceDetectorService, private readonly notificationService = inject(NotificationService);
private notificationService: NotificationService
) { public constructor() {
this.shouldReloadContent$ = this.shouldReloadSubject.asObservable(); this.shouldReloadContent$ = this.shouldReloadSubject.asObservable();
const deviceType = this.deviceDetectorService.getDeviceInfo().deviceType; const deviceType = this.deviceDetectorService.getDeviceInfo().deviceType;

4
apps/client/src/app/core/module-preload.service.ts

@ -1,8 +1,8 @@
import { Injectable } from '@angular/core'; import { Service } from '@angular/core';
import { PreloadingStrategy, Route } from '@angular/router'; import { PreloadingStrategy, Route } from '@angular/router';
import { Observable, of } from 'rxjs'; import { Observable, of } from 'rxjs';
@Injectable() @Service({ autoProvided: false })
export class ModulePreloadService implements PreloadingStrategy { export class ModulePreloadService implements PreloadingStrategy {
/** /**
* Preloads all lazy loading modules with the attribute 'preload' set to true * Preloads all lazy loading modules with the attribute 'preload' set to true

8
apps/client/src/app/services/cache.service.ts

@ -1,11 +1,9 @@
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core'; import { inject, Service } from '@angular/core';
@Injectable({ @Service()
providedIn: 'root'
})
export class CacheService { export class CacheService {
public constructor(private http: HttpClient) {} private readonly http = inject(HttpClient);
public flush() { public flush() {
return this.http.post<any>(`/api/v1/cache/flush`, {}); return this.http.post<any>(`/api/v1/cache/flush`, {});

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

@ -1,13 +1,11 @@
import { capitalize } from '@ghostfolio/common/helper'; import { capitalize } from '@ghostfolio/common/helper';
import { ExportResponse } from '@ghostfolio/common/interfaces'; import { ExportResponse } from '@ghostfolio/common/interfaces';
import { Injectable } from '@angular/core'; import { Service } from '@angular/core';
import { Type } from '@prisma/client'; import { Type } from '@prisma/client';
import { format, parseISO } from 'date-fns'; import { format, parseISO } from 'date-fns';
@Injectable({ @Service()
providedIn: 'root'
})
export class IcsService { export class IcsService {
private readonly ICS_DATE_FORMAT = 'yyyyMMdd'; private readonly ICS_DATE_FORMAT = 'yyyyMMdd';
private readonly ICS_LINE_BREAK = '\r\n'; private readonly ICS_LINE_BREAK = '\r\n';

6
apps/client/src/app/services/impersonation-storage.service.ts

@ -1,11 +1,9 @@
import { Injectable } from '@angular/core'; import { Service } from '@angular/core';
import { BehaviorSubject } from 'rxjs'; import { BehaviorSubject } from 'rxjs';
export const IMPERSONATION_KEY = 'impersonationId'; export const IMPERSONATION_KEY = 'impersonationId';
@Injectable({ @Service()
providedIn: 'root'
})
export class ImpersonationStorageService { export class ImpersonationStorageService {
private hasImpersonationChangeSubject = new BehaviorSubject<string | null>( private hasImpersonationChangeSubject = new BehaviorSubject<string | null>(
this.getId() this.getId()

6
apps/client/src/app/services/import-activities.service.ts

@ -13,16 +13,14 @@ import {
import { Activity } from '@ghostfolio/common/interfaces'; import { Activity } from '@ghostfolio/common/interfaces';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { inject, Injectable } from '@angular/core'; import { inject, Service } from '@angular/core';
import { Account, DataSource, Type as ActivityType } from '@prisma/client'; import { Account, DataSource, Type as ActivityType } from '@prisma/client';
import { isFinite, isNumber, isString } from 'lodash'; import { isFinite, isNumber, isString } from 'lodash';
import { parse as csvToJson } from 'papaparse'; import { parse as csvToJson } from 'papaparse';
import { firstValueFrom } from 'rxjs'; import { firstValueFrom } from 'rxjs';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
@Injectable({ @Service()
providedIn: 'root'
})
export class ImportActivitiesService { export class ImportActivitiesService {
private static ACCOUNT_KEYS = ['account', 'accountid']; private static ACCOUNT_KEYS = ['account', 'accountid'];
private static COMMENT_KEYS = ['comment', 'note']; private static COMMENT_KEYS = ['comment', 'note'];

8
apps/client/src/app/services/page-title.strategy.ts

@ -1,16 +1,14 @@
import { Injectable } from '@angular/core'; import { inject, Service } from '@angular/core';
import { Title } from '@angular/platform-browser'; import { Title } from '@angular/platform-browser';
import { RouterStateSnapshot, TitleStrategy } from '@angular/router'; import { RouterStateSnapshot, TitleStrategy } from '@angular/router';
@Injectable() @Service({ autoProvided: false })
export class PageTitleStrategy extends TitleStrategy { export class PageTitleStrategy extends TitleStrategy {
private static readonly DEFAULT_TITLE = private static readonly DEFAULT_TITLE =
'Ghostfolio – Open Source Wealth Management Software'; 'Ghostfolio – Open Source Wealth Management Software';
private static readonly DEFAULT_TITLE_SHORT = 'Ghostfolio'; private static readonly DEFAULT_TITLE_SHORT = 'Ghostfolio';
public constructor(private readonly title: Title) { private readonly title = inject(Title);
super();
}
public override updateTitle(routerState: RouterStateSnapshot) { public override updateTitle(routerState: RouterStateSnapshot) {
const title = this.buildTitle(routerState); const title = this.buildTitle(routerState);

6
apps/client/src/app/services/settings-storage.service.ts

@ -1,12 +1,10 @@
import { Injectable } from '@angular/core'; import { Service } from '@angular/core';
export const KEY_RANGE = 'range'; export const KEY_RANGE = 'range';
export const KEY_STAY_SIGNED_IN = 'staySignedIn'; export const KEY_STAY_SIGNED_IN = 'staySignedIn';
export const KEY_TOKEN = 'auth-token'; export const KEY_TOKEN = 'auth-token';
@Injectable({ @Service()
providedIn: 'root'
})
export class SettingsStorageService { export class SettingsStorageService {
public getSetting(aKey: string): string | null { public getSetting(aKey: string): string | null {
return window.localStorage.getItem(aKey); return window.localStorage.getItem(aKey);

6
apps/client/src/app/services/token-storage.service.ts

@ -1,10 +1,8 @@
import { Injectable } from '@angular/core'; import { Service } from '@angular/core';
import { KEY_TOKEN } from './settings-storage.service'; import { KEY_TOKEN } from './settings-storage.service';
@Injectable({ @Service()
providedIn: 'root'
})
export class TokenStorageService { export class TokenStorageService {
public getToken(): string | null { public getToken(): string | null {
return ( return (

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

@ -3,7 +3,7 @@ import { Filter, User } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { computed, DestroyRef, inject, Injectable } from '@angular/core'; import { computed, DestroyRef, inject, Service } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { ObservableStore } from '@codewithdan/observable-store'; import { ObservableStore } from '@codewithdan/observable-store';
@ -18,9 +18,7 @@ import { GfSubscriptionInterstitialDialogComponent } from '../../components/subs
import { UserStoreActions } from './user-store.actions'; import { UserStoreActions } from './user-store.actions';
import { UserStoreState } from './user-store.state'; import { UserStoreState } from './user-store.state';
@Injectable({ @Service()
providedIn: 'root'
})
export class UserService extends ObservableStore<UserStoreState> { export class UserService extends ObservableStore<UserStoreState> {
private readonly deviceType = computed( private readonly deviceType = computed(
() => this.deviceDetectorService.deviceInfo().deviceType () => this.deviceDetectorService.deviceInfo().deviceType

6
apps/client/src/app/services/web-authn.service.ts

@ -6,7 +6,7 @@ import {
} from '@ghostfolio/common/interfaces'; } from '@ghostfolio/common/interfaces';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { inject, Injectable } from '@angular/core'; import { inject, Service } from '@angular/core';
import { import {
startAuthentication, startAuthentication,
startRegistration startRegistration
@ -14,9 +14,7 @@ import {
import { of } from 'rxjs'; import { of } from 'rxjs';
import { catchError, switchMap, tap } from 'rxjs/operators'; import { catchError, switchMap, tap } from 'rxjs/operators';
@Injectable({ @Service()
providedIn: 'root'
})
export class WebAuthnService { export class WebAuthnService {
private static readonly WEB_AUTH_N_DEVICE_ID = 'WEB_AUTH_N_DEVICE_ID'; private static readonly WEB_AUTH_N_DEVICE_ID = 'WEB_AUTH_N_DEVICE_ID';

8
apps/client/src/main.ts

@ -4,7 +4,6 @@ import { registerChartConfiguration } from '@ghostfolio/ui/chart';
import { GF_ENVIRONMENT } from '@ghostfolio/ui/environment'; import { GF_ENVIRONMENT } from '@ghostfolio/ui/environment';
import { GfNotificationModule } from '@ghostfolio/ui/notifications'; import { GfNotificationModule } from '@ghostfolio/ui/notifications';
import { Platform } from '@angular/cdk/platform';
import { import {
provideHttpClient, provideHttpClient,
withInterceptorsFromDi withInterceptorsFromDi
@ -17,7 +16,6 @@ import {
import { import {
DateAdapter, DateAdapter,
MAT_DATE_FORMATS, MAT_DATE_FORMATS,
MAT_DATE_LOCALE,
MatNativeDateModule MatNativeDateModule
} from '@angular/material/core'; } from '@angular/material/core';
import { MatSnackBarModule } from '@angular/material/snack-bar'; import { MatSnackBarModule } from '@angular/material/snack-bar';
@ -35,7 +33,6 @@ import { GfAppComponent } from './app/app.component';
import { routes } from './app/app.routes'; import { routes } from './app/app.routes';
import { authInterceptorProviders } from './app/core/auth.interceptor'; import { authInterceptorProviders } from './app/core/auth.interceptor';
import { httpResponseInterceptorProviders } from './app/core/http-response.interceptor'; import { httpResponseInterceptorProviders } from './app/core/http-response.interceptor';
import { LanguageService } from './app/core/language.service';
import { ModulePreloadService } from './app/core/module-preload.service'; import { ModulePreloadService } from './app/core/module-preload.service';
import { PageTitleStrategy } from './app/services/page-title.strategy'; import { PageTitleStrategy } from './app/services/page-title.strategy';
import { environment } from './environments/environment'; import { environment } from './environments/environment';
@ -44,8 +41,7 @@ import { environment } from './environments/environment';
const response = await fetch('/api/v1/info'); const response = await fetch('/api/v1/info');
const info: InfoResponse = await response.json(); const info: InfoResponse = await response.json();
const utmSource = window.localStorage.getItem('utm_source') as const utmSource = window.localStorage.getItem('utm_source') as
| 'ios' 'ios' | 'trusted-web-activity';
| 'trusted-web-activity';
info.globalPermissions = filterGlobalPermissions( info.globalPermissions = filterGlobalPermissions(
info.globalPermissions, info.globalPermissions,
@ -79,7 +75,6 @@ import { environment } from './environments/environment';
registrationStrategy: 'registerImmediately' registrationStrategy: 'registerImmediately'
}) })
), ),
LanguageService,
ModulePreloadService, ModulePreloadService,
provideHttpClient(withInterceptorsFromDi()), provideHttpClient(withInterceptorsFromDi()),
provideIonicAngular(), provideIonicAngular(),
@ -87,7 +82,6 @@ import { environment } from './environments/environment';
provideNgxSkeletonLoader(), provideNgxSkeletonLoader(),
provideZoneChangeDetection(), provideZoneChangeDetection(),
{ {
deps: [LanguageService, MAT_DATE_LOCALE, Platform],
provide: DateAdapter, provide: DateAdapter,
useClass: CustomDateAdapter useClass: CustomDateAdapter
}, },

9
libs/ui/src/lib/entity-logo/entity-logo-image-source.service.ts

@ -1,11 +1,10 @@
import { AssetProfileIdentifier } from '@ghostfolio/common/interfaces'; import { AssetProfileIdentifier } from '@ghostfolio/common/interfaces';
import { Injectable } from '@angular/core'; import { Service } from '@angular/core';
@Injectable({ // Must stay auto-provided: several table stories render gf-entity-logo
// Required to allow mocking in Storybook // without providing an override and resolve this from the root injector
providedIn: 'root' @Service()
})
export class EntityLogoImageSourceService { export class EntityLogoImageSourceService {
public getLogoUrlByAssetProfileIdentifier({ public getLogoUrlByAssetProfileIdentifier({
dataSource, dataSource,

4
libs/ui/src/lib/fire-calculator/fire-calculator.service.ts

@ -1,7 +1,7 @@
import { Injectable } from '@angular/core'; import { Service } from '@angular/core';
import { Big } from 'big.js'; import { Big } from 'big.js';
@Injectable() @Service({ autoProvided: false })
export class FireCalculatorService { export class FireCalculatorService {
private readonly COMPOUND_PERIOD = 12; private readonly COMPOUND_PERIOD = 12;

4
libs/ui/src/lib/notifications/notification.service.ts

@ -1,7 +1,7 @@
import { ConfirmationDialogType } from '@ghostfolio/common/enums'; import { ConfirmationDialogType } from '@ghostfolio/common/enums';
import { translate } from '@ghostfolio/ui/i18n'; import { translate } from '@ghostfolio/ui/i18n';
import { inject, Injectable } from '@angular/core'; import { inject, Service } from '@angular/core';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { isFunction } from 'lodash'; import { isFunction } from 'lodash';
@ -14,7 +14,7 @@ import {
} from './interfaces/interfaces'; } from './interfaces/interfaces';
import { GfPromptDialogComponent } from './prompt-dialog/prompt-dialog.component'; import { GfPromptDialogComponent } from './prompt-dialog/prompt-dialog.component';
@Injectable() @Service({ autoProvided: false })
export class NotificationService { export class NotificationService {
private dialogMaxWidth: string; private dialogMaxWidth: string;
private dialogWidth: string; private dialogWidth: string;

6
libs/ui/src/lib/services/admin.service.ts

@ -24,14 +24,12 @@ import { DateRange } from '@ghostfolio/common/types';
import { GF_ENVIRONMENT } from '@ghostfolio/ui/environment'; import { GF_ENVIRONMENT } from '@ghostfolio/ui/environment';
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'; import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
import { Injectable, inject } from '@angular/core'; import { inject, Service } from '@angular/core';
import { AssetProfileSplit, MarketData, Platform } from '@prisma/client'; import { AssetProfileSplit, MarketData, Platform } from '@prisma/client';
import { JobStatus } from 'bull'; import { JobStatus } from 'bull';
import { isNumber } from 'lodash'; import { isNumber } from 'lodash';
@Injectable({ @Service()
providedIn: 'root'
})
export class AdminService { export class AdminService {
private readonly environment = inject(GF_ENVIRONMENT); private readonly environment = inject(GF_ENVIRONMENT);
private readonly http = inject(HttpClient); private readonly http = inject(HttpClient);

6
libs/ui/src/lib/services/data.service.ts

@ -66,7 +66,7 @@ import type {
import { translate } from '@ghostfolio/ui/i18n'; import { translate } from '@ghostfolio/ui/i18n';
import { HttpClient, HttpParams } from '@angular/common/http'; import { HttpClient, HttpParams } from '@angular/common/http';
import { Injectable, inject } from '@angular/core'; import { inject, Service } from '@angular/core';
import { SortDirection } from '@angular/material/sort'; import { SortDirection } from '@angular/material/sort';
import { utc } from '@date-fns/utc'; import { utc } from '@date-fns/utc';
import { import {
@ -85,9 +85,7 @@ import { cloneDeep, groupBy, isNumber } from 'lodash';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { map } from 'rxjs/operators'; import { map } from 'rxjs/operators';
@Injectable({ @Service()
providedIn: 'root'
})
export class DataService { export class DataService {
private readonly http = inject(HttpClient); private readonly http = inject(HttpClient);

Loading…
Cancel
Save