Feature/add support to override asset (sub) class and url in admin control panel (#3218)

* Add support to override asset (sub) class and url in admin control panel

* Update changelog
This commit is contained in:
Fedron 2024-04-03 19:24:38 +01:00 committed by GitHub
parent 371c999fbc
commit 82fe1de1a7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 47 additions and 20 deletions

View File

@ -10,6 +10,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### Added
- Added the dividend yield to the position detail dialog (experimental) - Added the dividend yield to the position detail dialog (experimental)
- Added support to override the asset class of an asset profile in the asset profile details dialog of the admin control
- Added support to override the asset sub class of an asset profile in the asset profile details dialog of the admin control
- Added support to override the url of an asset profile in the asset profile details dialog of the admin control
## 2.70.0 - 2024-04-02 ## 2.70.0 - 2024-04-02

View File

@ -25,6 +25,7 @@ import { MarketDataPreset } from '@ghostfolio/common/types';
import { BadRequestException, Injectable } from '@nestjs/common'; import { BadRequestException, Injectable } from '@nestjs/common';
import { import {
AssetClass,
AssetSubClass, AssetSubClass,
DataSource, DataSource,
Prisma, Prisma,
@ -332,12 +333,18 @@ export class AdminService {
scraperConfiguration, scraperConfiguration,
sectors, sectors,
symbol, symbol,
symbolMapping symbolMapping,
url
}: Prisma.SymbolProfileUpdateInput & UniqueAsset) { }: Prisma.SymbolProfileUpdateInput & UniqueAsset) {
const symbolProfileOverrides = {
assetClass: assetClass as AssetClass,
assetSubClass: assetSubClass as AssetSubClass,
name: name as string,
url: url as string
};
const updatedSymbolProfile: Prisma.SymbolProfileUpdateInput & UniqueAsset = const updatedSymbolProfile: Prisma.SymbolProfileUpdateInput & UniqueAsset =
{ {
assetClass,
assetSubClass,
comment, comment,
countries, countries,
currency, currency,
@ -347,16 +354,12 @@ export class AdminService {
symbol, symbol,
symbolMapping, symbolMapping,
...(dataSource === 'MANUAL' ...(dataSource === 'MANUAL'
? { name } ? { assetClass, assetSubClass, name, url }
: { : {
SymbolProfileOverrides: { SymbolProfileOverrides: {
upsert: { upsert: {
create: { create: symbolProfileOverrides,
name: name as string update: symbolProfileOverrides
},
update: {
name: name as string
}
} }
} }
}) })

View File

@ -5,7 +5,8 @@ import {
IsISO4217CurrencyCode, IsISO4217CurrencyCode,
IsObject, IsObject,
IsOptional, IsOptional,
IsString IsString,
IsUrl
} from 'class-validator'; } from 'class-validator';
export class UpdateAssetProfileDto { export class UpdateAssetProfileDto {
@ -46,4 +47,11 @@ export class UpdateAssetProfileDto {
symbolMapping?: { symbolMapping?: {
[dataProvider: string]: string; [dataProvider: string]: string;
}; };
@IsOptional()
@IsUrl({
protocols: ['https'],
require_protocol: true
})
url?: string;
} }

View File

@ -98,7 +98,8 @@ export class SymbolProfileService {
sectors, sectors,
symbol, symbol,
symbolMapping, symbolMapping,
SymbolProfileOverrides SymbolProfileOverrides,
url
}: Prisma.SymbolProfileUpdateInput & UniqueAsset) { }: Prisma.SymbolProfileUpdateInput & UniqueAsset) {
return this.prismaService.symbolProfile.update({ return this.prismaService.symbolProfile.update({
data: { data: {
@ -111,7 +112,8 @@ export class SymbolProfileService {
scraperConfiguration, scraperConfiguration,
sectors, sectors,
symbolMapping, symbolMapping,
SymbolProfileOverrides SymbolProfileOverrides,
url
}, },
where: { dataSource_symbol: { dataSource, symbol } } where: { dataSource_symbol: { dataSource, symbol } }
}); });

View File

@ -64,7 +64,8 @@ export class AssetProfileDialog implements OnDestroy, OnInit {
name: ['', Validators.required], name: ['', Validators.required],
scraperConfiguration: '', scraperConfiguration: '',
sectors: '', sectors: '',
symbolMapping: '' symbolMapping: '',
url: ''
}); });
public assetProfileSubClass: string; public assetProfileSubClass: string;
public benchmarks: Partial<SymbolProfile>[]; public benchmarks: Partial<SymbolProfile>[];
@ -163,7 +164,8 @@ export class AssetProfileDialog implements OnDestroy, OnInit {
this.assetProfile?.scraperConfiguration ?? {} this.assetProfile?.scraperConfiguration ?? {}
), ),
sectors: JSON.stringify(this.assetProfile?.sectors ?? []), sectors: JSON.stringify(this.assetProfile?.sectors ?? []),
symbolMapping: JSON.stringify(this.assetProfile?.symbolMapping ?? {}) symbolMapping: JSON.stringify(this.assetProfile?.symbolMapping ?? {}),
url: this.assetProfile?.url ?? ''
}); });
this.assetProfileForm.markAsPristine(); this.assetProfileForm.markAsPristine();
@ -293,7 +295,8 @@ export class AssetProfileDialog implements OnDestroy, OnInit {
currency: (<Currency>( currency: (<Currency>(
(<unknown>this.assetProfileForm.controls['currency'].value) (<unknown>this.assetProfileForm.controls['currency'].value)
))?.value, ))?.value,
name: this.assetProfileForm.controls['name'].value name: this.assetProfileForm.controls['name'].value,
url: this.assetProfileForm.controls['url'].value
}; };
this.adminService this.adminService

View File

@ -224,7 +224,7 @@
/> />
</mat-form-field> </mat-form-field>
</div> </div>
<div *ngIf="assetProfile?.dataSource === 'MANUAL'" class="mt-3"> <div 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>
<mat-select formControlName="assetClass"> <mat-select formControlName="assetClass">
@ -237,7 +237,7 @@
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
</div> </div>
<div *ngIf="assetProfile?.dataSource === 'MANUAL'" class="mt-3"> <div 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 Sub Class</mat-label> <mat-label i18n>Asset Sub Class</mat-label>
<mat-select formControlName="assetSubClass"> <mat-select formControlName="assetSubClass">
@ -330,6 +330,12 @@
</mat-form-field> </mat-form-field>
</div> </div>
<div> <div>
<mat-form-field appearance="outline" class="w-100 without-hint">
<mat-label i18n>Url</mat-label>
<input formControlName="url" matInput type="text" />
</mat-form-field>
</div>
<div class="mt-3">
<mat-form-field appearance="outline" class="w-100"> <mat-form-field appearance="outline" class="w-100">
<mat-label i18n>Note</mat-label> <mat-label i18n>Note</mat-label>
<textarea <textarea

View File

@ -211,7 +211,8 @@ export class AdminService {
scraperConfiguration, scraperConfiguration,
sectors, sectors,
symbol, symbol,
symbolMapping symbolMapping,
url
}: UniqueAsset & UpdateAssetProfileDto) { }: UniqueAsset & UpdateAssetProfileDto) {
return this.http.patch<EnhancedSymbolProfile>( return this.http.patch<EnhancedSymbolProfile>(
`/api/v1/admin/profile-data/${dataSource}/${symbol}`, `/api/v1/admin/profile-data/${dataSource}/${symbol}`,
@ -224,7 +225,8 @@ export class AdminService {
name, name,
scraperConfiguration, scraperConfiguration,
sectors, sectors,
symbolMapping symbolMapping,
url
} }
); );
} }