Browse Source

apply feedback

- Move gatherSymbol logic from admin-market-data component to create-asset-profile-dialog onSubmit method
  - Replace hardcoded 'USD' with DEFAULT_CURRENCY constant for better maintainability
  - Extend AdminData interface to include useForExchangeRates flag in dataProviders array
  - Update server-side admin service to populate useForExchangeRates based on exchange rate data source
  - Use proper exchange rate data source instead of hardcoded 'MANUAL' for currency operations
  - Improve currency handling by automatically calling gatherSymbol after currency addition
  - Clean up unused imports and fix TypeScript types
pull/5434/head
Sven Günther 4 months ago
parent
commit
ec032f3a61
  1. 5
      apps/api/src/app/admin/admin.service.ts
  2. 14
      apps/client/src/app/components/admin-market-data/admin-market-data.component.ts
  3. 46
      apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.component.ts
  4. 5
      libs/common/src/lib/interfaces/admin-data.interface.ts

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

@ -159,7 +159,10 @@ export class AdminService {
return { return {
...dataProviderInfo, ...dataProviderInfo,
assetProfileCount assetProfileCount,
useForExchangeRates:
dataSource ===
this.dataProviderService.getDataSourceForExchangeRates()
}; };
} }

14
apps/client/src/app/components/admin-market-data/admin-market-data.component.ts

@ -63,7 +63,7 @@ import {
} from 'ionicons/icons'; } from 'ionicons/icons';
import { DeviceDetectorService } from 'ngx-device-detector'; import { DeviceDetectorService } from 'ngx-device-detector';
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
import { Subject, of } from 'rxjs'; import { Subject } from 'rxjs';
import { distinctUntilChanged, switchMap, takeUntil } from 'rxjs/operators'; import { distinctUntilChanged, switchMap, takeUntil } from 'rxjs/operators';
import { AdminMarketDataService } from './admin-market-data.service'; import { AdminMarketDataService } from './admin-market-data.service';
@ -480,21 +480,11 @@ export class GfAdminMarketDataComponent
dialogRef dialogRef
.afterClosed() .afterClosed()
.pipe(takeUntil(this.unsubscribeSubject)) .pipe(takeUntil(this.unsubscribeSubject))
.subscribe(({ dataSource, symbol, isCurrency } = {}) => { .subscribe(({ dataSource, symbol } = {}) => {
if (dataSource && symbol) { if (dataSource && symbol) {
this.adminService this.adminService
.addAssetProfile({ dataSource, symbol }) .addAssetProfile({ dataSource, symbol })
.pipe( .pipe(
switchMap(() => {
// Call gatherSymbol for currencies to collect historical data
if (isCurrency) {
return this.adminService.gatherSymbol({
dataSource,
symbol
});
}
return of(null);
}),
switchMap(() => { switchMap(() => {
this.isLoading = true; this.isLoading = true;
this.changeDetectorRef.markForCheck(); this.changeDetectorRef.markForCheck();

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

@ -1,6 +1,7 @@
import { AdminService } from '@ghostfolio/client/services/admin.service'; import { AdminService } from '@ghostfolio/client/services/admin.service';
import { DataService } from '@ghostfolio/client/services/data.service'; import { DataService } from '@ghostfolio/client/services/data.service';
import { import {
DEFAULT_CURRENCY,
ghostfolioPrefix, ghostfolioPrefix,
PROPERTY_CURRENCIES PROPERTY_CURRENCIES
} from '@ghostfolio/common/config'; } from '@ghostfolio/common/config';
@ -29,8 +30,9 @@ import { MatDialogModule, MatDialogRef } from '@angular/material/dialog';
import { MatFormFieldModule } from '@angular/material/form-field'; import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
import { MatRadioModule } from '@angular/material/radio'; import { MatRadioModule } from '@angular/material/radio';
import { DataSource } from '@prisma/client';
import { isISO4217CurrencyCode } from 'class-validator'; import { isISO4217CurrencyCode } from 'class-validator';
import { Subject, takeUntil } from 'rxjs'; import { Subject, switchMap, takeUntil } from 'rxjs';
import { CreateAssetProfileDialogMode } from './interfaces/interfaces'; import { CreateAssetProfileDialogMode } from './interfaces/interfaces';
@ -56,6 +58,7 @@ export class GfCreateAssetProfileDialogComponent implements OnInit, OnDestroy {
public mode: CreateAssetProfileDialogMode; public mode: CreateAssetProfileDialogMode;
private customCurrencies: string[]; private customCurrencies: string[];
private exchangeRateDataSource: DataSource;
private unsubscribeSubject = new Subject<void>(); private unsubscribeSubject = new Subject<void>();
public constructor( public constructor(
@ -68,6 +71,7 @@ export class GfCreateAssetProfileDialogComponent implements OnInit, OnDestroy {
public ngOnInit() { public ngOnInit() {
this.initializeCustomCurrencies(); this.initializeCustomCurrencies();
this.initializeExchangeRateDataSource();
this.createAssetProfileForm = this.formBuilder.group( this.createAssetProfileForm = this.formBuilder.group(
{ {
@ -115,13 +119,25 @@ export class GfCreateAssetProfileDialogComponent implements OnInit, OnDestroy {
.putAdminSetting(PROPERTY_CURRENCIES, { .putAdminSetting(PROPERTY_CURRENCIES, {
value: JSON.stringify(currencies) value: JSON.stringify(currencies)
}) })
.pipe(takeUntil(this.unsubscribeSubject)) .pipe(
switchMap(() => {
// Add the currency asset profile first
return this.adminService.addAssetProfile({
dataSource: this.exchangeRateDataSource,
symbol: `${currency}${DEFAULT_CURRENCY}`
});
}),
switchMap(() => {
// Then gather historical data for the currency
return this.adminService.gatherSymbol({
dataSource: this.exchangeRateDataSource,
symbol: `${currency}${DEFAULT_CURRENCY}`
});
}),
takeUntil(this.unsubscribeSubject)
)
.subscribe(() => { .subscribe(() => {
this.dialogRef.close({ this.dialogRef.close();
dataSource: 'MANUAL',
symbol: `${currency}USD`,
isCurrency: true
});
}); });
} else if (this.mode === 'manual') { } else if (this.mode === 'manual') {
this.dialogRef.close({ this.dialogRef.close({
@ -185,6 +201,22 @@ export class GfCreateAssetProfileDialogComponent implements OnInit, OnDestroy {
}); });
} }
private initializeExchangeRateDataSource() {
this.adminService
.fetchAdminData()
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(({ dataProviders }) => {
const exchangeRateProvider = dataProviders.find(
(provider) => provider.useForExchangeRates
);
this.exchangeRateDataSource =
exchangeRateProvider?.dataSource || DataSource.MANUAL;
this.changeDetectorRef.markForCheck();
});
}
private iso4217CurrencyCodeValidator(): ValidatorFn { private iso4217CurrencyCodeValidator(): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => { return (control: AbstractControl): ValidationErrors | null => {
if (!isISO4217CurrencyCode(control.value?.toUpperCase())) { if (!isISO4217CurrencyCode(control.value?.toUpperCase())) {

5
libs/common/src/lib/interfaces/admin-data.interface.ts

@ -1,7 +1,10 @@
import { DataProviderInfo } from './data-provider-info.interface'; import { DataProviderInfo } from './data-provider-info.interface';
export interface AdminData { export interface AdminData {
dataProviders: (DataProviderInfo & { assetProfileCount: number })[]; dataProviders: (DataProviderInfo & {
assetProfileCount: number;
useForExchangeRates: boolean;
})[];
settings: { [key: string]: boolean | object | string | string[] }; settings: { [key: string]: boolean | object | string | string[] };
transactionCount: number; transactionCount: number;
userCount: number; userCount: number;

Loading…
Cancel
Save