|
|
@ -8,6 +8,7 @@ import { |
|
|
|
} from '@angular/core'; |
|
|
|
import { FormBuilder, FormControl, Validators } from '@angular/forms'; |
|
|
|
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; |
|
|
|
import { MatSnackBar } from '@angular/material/snack-bar'; |
|
|
|
import { UpdateAssetProfileDto } from '@ghostfolio/api/app/admin/update-asset-profile.dto'; |
|
|
|
import { AdminService } from '@ghostfolio/client/services/admin.service'; |
|
|
|
import { DataService } from '@ghostfolio/client/services/data.service'; |
|
|
@ -25,8 +26,8 @@ import { |
|
|
|
} from '@prisma/client'; |
|
|
|
import { format } from 'date-fns'; |
|
|
|
import { parse as csvToJson } from 'papaparse'; |
|
|
|
import { Subject } from 'rxjs'; |
|
|
|
import { takeUntil } from 'rxjs/operators'; |
|
|
|
import { EMPTY, Subject } from 'rxjs'; |
|
|
|
import { catchError, takeUntil } from 'rxjs/operators'; |
|
|
|
|
|
|
|
import { AssetProfileDialogParams } from './interfaces/interfaces'; |
|
|
|
|
|
|
@ -50,6 +51,9 @@ export class AssetProfileDialog implements OnDestroy, OnInit { |
|
|
|
assetClass: new FormControl<AssetClass>(undefined), |
|
|
|
assetSubClass: new FormControl<AssetSubClass>(undefined), |
|
|
|
comment: '', |
|
|
|
historicalData: this.formBuilder.group({ |
|
|
|
csvString: '' |
|
|
|
}), |
|
|
|
name: ['', Validators.required], |
|
|
|
scraperConfiguration: '', |
|
|
|
symbolMapping: '' |
|
|
@ -59,7 +63,6 @@ export class AssetProfileDialog implements OnDestroy, OnInit { |
|
|
|
public countries: { |
|
|
|
[code: string]: { name: string; value: number }; |
|
|
|
}; |
|
|
|
public historicalDataAsCsvString: string; |
|
|
|
public isBenchmark = false; |
|
|
|
public marketDataDetails: MarketData[] = []; |
|
|
|
public sectors: { |
|
|
@ -78,7 +81,8 @@ export class AssetProfileDialog implements OnDestroy, OnInit { |
|
|
|
@Inject(MAT_DIALOG_DATA) public data: AssetProfileDialogParams, |
|
|
|
private dataService: DataService, |
|
|
|
public dialogRef: MatDialogRef<AssetProfileDialog>, |
|
|
|
private formBuilder: FormBuilder |
|
|
|
private formBuilder: FormBuilder, |
|
|
|
private snackBar: MatSnackBar |
|
|
|
) {} |
|
|
|
|
|
|
|
public ngOnInit(): void { |
|
|
@ -88,9 +92,6 @@ export class AssetProfileDialog implements OnDestroy, OnInit { |
|
|
|
} |
|
|
|
|
|
|
|
public initialize() { |
|
|
|
this.historicalDataAsCsvString = |
|
|
|
AssetProfileDialog.HISTORICAL_DATA_TEMPLATE; |
|
|
|
|
|
|
|
this.adminService |
|
|
|
.fetchAdminMarketDataBySymbol({ |
|
|
|
dataSource: this.data.dataSource, |
|
|
@ -131,6 +132,9 @@ export class AssetProfileDialog implements OnDestroy, OnInit { |
|
|
|
assetClass: this.assetProfile.assetClass ?? null, |
|
|
|
assetSubClass: this.assetProfile.assetSubClass ?? null, |
|
|
|
comment: this.assetProfile?.comment ?? '', |
|
|
|
historicalData: { |
|
|
|
csvString: AssetProfileDialog.HISTORICAL_DATA_TEMPLATE |
|
|
|
}, |
|
|
|
name: this.assetProfile.name ?? this.assetProfile.symbol, |
|
|
|
scraperConfiguration: JSON.stringify( |
|
|
|
this.assetProfile?.scraperConfiguration ?? {} |
|
|
@ -163,26 +167,46 @@ export class AssetProfileDialog implements OnDestroy, OnInit { |
|
|
|
} |
|
|
|
|
|
|
|
public onImportHistoricalData() { |
|
|
|
const marketData = csvToJson(this.historicalDataAsCsvString, { |
|
|
|
dynamicTyping: true, |
|
|
|
header: true, |
|
|
|
skipEmptyLines: true |
|
|
|
}).data; |
|
|
|
|
|
|
|
this.adminService |
|
|
|
.postMarketData({ |
|
|
|
dataSource: this.data.dataSource, |
|
|
|
marketData: { |
|
|
|
marketData: marketData.map(({ date, marketPrice }) => { |
|
|
|
return { marketPrice, date: parseDate(date).toISOString() }; |
|
|
|
}) |
|
|
|
}, |
|
|
|
symbol: this.data.symbol |
|
|
|
}) |
|
|
|
.pipe(takeUntil(this.unsubscribeSubject)) |
|
|
|
.subscribe(() => { |
|
|
|
this.initialize(); |
|
|
|
}); |
|
|
|
try { |
|
|
|
const marketData = csvToJson( |
|
|
|
this.assetProfileForm.controls['historicalData'].controls['csvString'] |
|
|
|
.value, |
|
|
|
{ |
|
|
|
dynamicTyping: true, |
|
|
|
header: true, |
|
|
|
skipEmptyLines: true |
|
|
|
} |
|
|
|
).data; |
|
|
|
|
|
|
|
this.adminService |
|
|
|
.postMarketData({ |
|
|
|
dataSource: this.data.dataSource, |
|
|
|
marketData: { |
|
|
|
marketData: marketData.map(({ date, marketPrice }) => { |
|
|
|
return { marketPrice, date: parseDate(date).toISOString() }; |
|
|
|
}) |
|
|
|
}, |
|
|
|
symbol: this.data.symbol |
|
|
|
}) |
|
|
|
.pipe( |
|
|
|
catchError(({ error, message }) => { |
|
|
|
this.snackBar.open(`${error}: ${message[0]}`, undefined, { |
|
|
|
duration: 3000 |
|
|
|
}); |
|
|
|
return EMPTY; |
|
|
|
}), |
|
|
|
takeUntil(this.unsubscribeSubject) |
|
|
|
) |
|
|
|
.subscribe(() => { |
|
|
|
this.initialize(); |
|
|
|
}); |
|
|
|
} catch { |
|
|
|
this.snackBar.open( |
|
|
|
$localize`Oops! Could not parse historical data.`, |
|
|
|
undefined, |
|
|
|
{ duration: 3000 } |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public onMarketDataChanged(withRefresh: boolean = false) { |
|
|
|