Feature/add support to edit currency of asset profile with data source manual (#2789)

* Add support to edit currency

* Update changelog
pull/2793/head^2
Thomas Kaul 6 months ago committed by GitHub
parent 01b6c14bcc
commit e465f1b791
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased ## Unreleased
### Added
- Added support to edit the currency of asset profiles with `MANUAL` data source in the asset profile details dialog of the admin control panel
### Changed ### Changed
- Changed the performance calculation to a time-weighted approach - Changed the performance calculation to a time-weighted approach

@ -321,6 +321,7 @@ export class AdminService {
assetClass, assetClass,
assetSubClass, assetSubClass,
comment, comment,
currency,
dataSource, dataSource,
name, name,
scraperConfiguration, scraperConfiguration,
@ -331,6 +332,7 @@ export class AdminService {
assetClass, assetClass,
assetSubClass, assetSubClass,
comment, comment,
currency,
dataSource, dataSource,
name, name,
scraperConfiguration, scraperConfiguration,

@ -14,6 +14,10 @@ export class UpdateAssetProfileDto {
@IsOptional() @IsOptional()
comment?: string; comment?: string;
@IsString()
@IsOptional()
currency?: string;
@IsString() @IsString()
@IsOptional() @IsOptional()
name?: string; name?: string;

@ -89,6 +89,7 @@ export class SymbolProfileService {
assetClass, assetClass,
assetSubClass, assetSubClass,
comment, comment,
currency,
dataSource, dataSource,
name, name,
scraperConfiguration, scraperConfiguration,
@ -100,6 +101,7 @@ export class SymbolProfileService {
assetClass, assetClass,
assetSubClass, assetSubClass,
comment, comment,
currency,
name, name,
scraperConfiguration, scraperConfiguration,
symbolMapping symbolMapping

@ -15,6 +15,7 @@ import { DataService } from '@ghostfolio/client/services/data.service';
import { DATE_FORMAT, parseDate } from '@ghostfolio/common/helper'; import { DATE_FORMAT, parseDate } from '@ghostfolio/common/helper';
import { import {
AdminMarketDataDetails, AdminMarketDataDetails,
Currency,
UniqueAsset UniqueAsset
} from '@ghostfolio/common/interfaces'; } from '@ghostfolio/common/interfaces';
import { translate } from '@ghostfolio/ui/i18n'; import { translate } from '@ghostfolio/ui/i18n';
@ -51,6 +52,7 @@ export class AssetProfileDialog implements OnDestroy, OnInit {
assetClass: new FormControl<AssetClass>(undefined), assetClass: new FormControl<AssetClass>(undefined),
assetSubClass: new FormControl<AssetSubClass>(undefined), assetSubClass: new FormControl<AssetSubClass>(undefined),
comment: '', comment: '',
currency: '',
historicalData: this.formBuilder.group({ historicalData: this.formBuilder.group({
csvString: '' csvString: ''
}), }),
@ -63,6 +65,7 @@ export class AssetProfileDialog implements OnDestroy, OnInit {
public countries: { public countries: {
[code: string]: { name: string; value: number }; [code: string]: { name: string; value: number };
}; };
public currencies: Currency[] = [];
public isBenchmark = false; public isBenchmark = false;
public marketDataDetails: MarketData[] = []; public marketDataDetails: MarketData[] = [];
public sectors: { public sectors: {
@ -86,7 +89,13 @@ export class AssetProfileDialog implements OnDestroy, OnInit {
) {} ) {}
public ngOnInit(): void { public ngOnInit(): void {
this.benchmarks = this.dataService.fetchInfo().benchmarks; const { benchmarks, currencies } = this.dataService.fetchInfo();
this.benchmarks = benchmarks;
this.currencies = currencies.map((currency) => ({
label: currency,
value: currency
}));
this.initialize(); this.initialize();
} }
@ -132,6 +141,7 @@ export class AssetProfileDialog implements OnDestroy, OnInit {
assetClass: this.assetProfile.assetClass ?? null, assetClass: this.assetProfile.assetClass ?? null,
assetSubClass: this.assetProfile.assetSubClass ?? null, assetSubClass: this.assetProfile.assetSubClass ?? null,
comment: this.assetProfile?.comment ?? '', comment: this.assetProfile?.comment ?? '',
currency: this.assetProfile?.currency,
historicalData: { historicalData: {
csvString: AssetProfileDialog.HISTORICAL_DATA_TEMPLATE csvString: AssetProfileDialog.HISTORICAL_DATA_TEMPLATE
}, },
@ -245,12 +255,15 @@ export class AssetProfileDialog implements OnDestroy, OnInit {
} catch {} } catch {}
const assetProfileData: UpdateAssetProfileDto = { const assetProfileData: UpdateAssetProfileDto = {
scraperConfiguration,
symbolMapping,
assetClass: this.assetProfileForm.controls['assetClass'].value, assetClass: this.assetProfileForm.controls['assetClass'].value,
assetSubClass: this.assetProfileForm.controls['assetSubClass'].value, assetSubClass: this.assetProfileForm.controls['assetSubClass'].value,
comment: this.assetProfileForm.controls['comment'].value ?? null, comment: this.assetProfileForm.controls['comment'].value ?? null,
name: this.assetProfileForm.controls['name'].value, currency: (<Currency>(
scraperConfiguration, (<unknown>this.assetProfileForm.controls['currency'].value)
symbolMapping ))?.value,
name: this.assetProfileForm.controls['name'].value
}; };
this.adminService this.adminService

@ -183,6 +183,15 @@
<input formControlName="name" matInput type="text" /> <input formControlName="name" matInput type="text" />
</mat-form-field> </mat-form-field>
</div> </div>
<div *ngIf="assetProfile?.dataSource === 'MANUAL'" class="mt-3">
<mat-form-field appearance="outline" class="w-100 without-hint">
<mat-label i18n>Currency</mat-label>
<gf-currency-selector
formControlName="currency"
[currencies]="currencies"
/>
</mat-form-field>
</div>
<div *ngIf="assetProfile?.dataSource === 'MANUAL'" class="mt-3"> <div *ngIf="assetProfile?.dataSource === 'MANUAL'" class="mt-3">
<mat-form-field appearance="outline" class="w-100 without-hint"> <mat-form-field appearance="outline" class="w-100 without-hint">
<mat-label i18n>Asset Class</mat-label> <mat-label i18n>Asset Class</mat-label>

@ -10,6 +10,7 @@ import { MatMenuModule } from '@angular/material/menu';
import { MatSelectModule } from '@angular/material/select'; import { MatSelectModule } from '@angular/material/select';
import { MatSnackBarModule } from '@angular/material/snack-bar'; import { MatSnackBarModule } from '@angular/material/snack-bar';
import { GfAdminMarketDataDetailModule } from '@ghostfolio/client/components/admin-market-data-detail/admin-market-data-detail.module'; import { GfAdminMarketDataDetailModule } from '@ghostfolio/client/components/admin-market-data-detail/admin-market-data-detail.module';
import { GfCurrencySelectorModule } from '@ghostfolio/ui/currency-selector/currency-selector.module';
import { GfPortfolioProportionChartModule } from '@ghostfolio/ui/portfolio-proportion-chart/portfolio-proportion-chart.module'; import { GfPortfolioProportionChartModule } from '@ghostfolio/ui/portfolio-proportion-chart/portfolio-proportion-chart.module';
import { GfValueModule } from '@ghostfolio/ui/value'; import { GfValueModule } from '@ghostfolio/ui/value';
@ -21,6 +22,7 @@ import { AssetProfileDialog } from './asset-profile-dialog.component';
CommonModule, CommonModule,
FormsModule, FormsModule,
GfAdminMarketDataDetailModule, GfAdminMarketDataDetailModule,
GfCurrencySelectorModule,
GfPortfolioProportionChartModule, GfPortfolioProportionChartModule,
GfValueModule, GfValueModule,
MatButtonModule, MatButtonModule,

@ -15,7 +15,7 @@ import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { CreateAccountDto } from '@ghostfolio/api/app/account/create-account.dto'; import { CreateAccountDto } from '@ghostfolio/api/app/account/create-account.dto';
import { UpdateAccountDto } from '@ghostfolio/api/app/account/update-account.dto'; import { UpdateAccountDto } from '@ghostfolio/api/app/account/update-account.dto';
import { DataService } from '@ghostfolio/client/services/data.service'; import { DataService } from '@ghostfolio/client/services/data.service';
import { Currency } from '@ghostfolio/common/interfaces/currency.interface'; import { Currency } from '@ghostfolio/common/interfaces';
import { Platform } from '@prisma/client'; import { Platform } from '@prisma/client';
import { Observable, Subject } from 'rxjs'; import { Observable, Subject } from 'rxjs';
import { map, startWith } from 'rxjs/operators'; import { map, startWith } from 'rxjs/operators';

@ -206,6 +206,7 @@ export class AdminService {
assetClass, assetClass,
assetSubClass, assetSubClass,
comment, comment,
currency,
dataSource, dataSource,
name, name,
scraperConfiguration, scraperConfiguration,
@ -218,6 +219,7 @@ export class AdminService {
assetClass, assetClass,
assetSubClass, assetSubClass,
comment, comment,
currency,
name, name,
scraperConfiguration, scraperConfiguration,
symbolMapping symbolMapping

@ -11,6 +11,7 @@ import type { BenchmarkMarketDataDetails } from './benchmark-market-data-details
import type { BenchmarkProperty } from './benchmark-property.interface'; import type { BenchmarkProperty } from './benchmark-property.interface';
import type { Benchmark } from './benchmark.interface'; import type { Benchmark } from './benchmark.interface';
import type { Coupon } from './coupon.interface'; import type { Coupon } from './coupon.interface';
import type { Currency } from './currency.interface';
import type { DataProviderInfo } from './data-provider-info.interface'; import type { DataProviderInfo } from './data-provider-info.interface';
import type { EnhancedSymbolProfile } from './enhanced-symbol-profile.interface'; import type { EnhancedSymbolProfile } from './enhanced-symbol-profile.interface';
import type { Export } from './export.interface'; import type { Export } from './export.interface';
@ -42,8 +43,8 @@ import type { PortfolioPerformanceResponse } from './responses/portfolio-perform
import type { ScraperConfiguration } from './scraper-configuration.interface'; import type { ScraperConfiguration } from './scraper-configuration.interface';
import type { Statistics } from './statistics.interface'; import type { Statistics } from './statistics.interface';
import type { Subscription } from './subscription.interface'; import type { Subscription } from './subscription.interface';
import { SystemMessage } from './system-message.interface'; import type { SystemMessage } from './system-message.interface';
import { TabConfiguration } from './tab-configuration.interface'; import type { TabConfiguration } from './tab-configuration.interface';
import type { TimelinePosition } from './timeline-position.interface'; import type { TimelinePosition } from './timeline-position.interface';
import type { UniqueAsset } from './unique-asset.interface'; import type { UniqueAsset } from './unique-asset.interface';
import type { UserSettings } from './user-settings.interface'; import type { UserSettings } from './user-settings.interface';
@ -63,6 +64,7 @@ export {
BenchmarkProperty, BenchmarkProperty,
BenchmarkResponse, BenchmarkResponse,
Coupon, Coupon,
Currency,
DataProviderInfo, DataProviderInfo,
EnhancedSymbolProfile, EnhancedSymbolProfile,
Export, Export,

@ -16,7 +16,7 @@ import {
} from '@angular/material/autocomplete'; } from '@angular/material/autocomplete';
import { MatFormFieldControl } from '@angular/material/form-field'; import { MatFormFieldControl } from '@angular/material/form-field';
import { MatInput } from '@angular/material/input'; import { MatInput } from '@angular/material/input';
import { Currency } from '@ghostfolio/common/interfaces/currency.interface'; import { Currency } from '@ghostfolio/common/interfaces';
import { AbstractMatFormField } from '@ghostfolio/ui/shared/abstract-mat-form-field'; import { AbstractMatFormField } from '@ghostfolio/ui/shared/abstract-mat-form-field';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { map, startWith, takeUntil } from 'rxjs/operators'; import { map, startWith, takeUntil } from 'rxjs/operators';

Loading…
Cancel
Save