Feature/add support to edit currency of asset profile with data source manual (#2789)
* Add support to edit currency * Update changelog
This commit is contained in:
parent
01b6c14bcc
commit
e465f1b791
@ -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…
x
Reference in New Issue
Block a user