|
|
|
@ -11,9 +11,11 @@ import { |
|
|
|
DATE_FORMAT, |
|
|
|
getCountryName, |
|
|
|
getCurrencyFromSymbol, |
|
|
|
getDateFormatString, |
|
|
|
getStringOrNull, |
|
|
|
getStringOrUndefined, |
|
|
|
isCurrency |
|
|
|
isCurrency, |
|
|
|
isSplitRatio |
|
|
|
} from '@ghostfolio/common/helper'; |
|
|
|
import { |
|
|
|
AdminMarketDataDetails, |
|
|
|
@ -37,6 +39,7 @@ import { GfSymbolAutocompleteComponent } from '@ghostfolio/ui/symbol-autocomplet |
|
|
|
import { GfValueComponent } from '@ghostfolio/ui/value'; |
|
|
|
|
|
|
|
import { TextFieldModule } from '@angular/cdk/text-field'; |
|
|
|
import { CommonModule } from '@angular/common'; |
|
|
|
import { HttpErrorResponse } from '@angular/common/http'; |
|
|
|
import { |
|
|
|
ChangeDetectionStrategy, |
|
|
|
@ -63,6 +66,7 @@ import { |
|
|
|
MatCheckboxChange, |
|
|
|
MatCheckboxModule |
|
|
|
} from '@angular/material/checkbox'; |
|
|
|
import { MatDatepickerModule } from '@angular/material/datepicker'; |
|
|
|
import { |
|
|
|
MAT_DIALOG_DATA, |
|
|
|
MatDialogModule, |
|
|
|
@ -76,6 +80,7 @@ import { MatTabsModule } from '@angular/material/tabs'; |
|
|
|
import { IonIcon } from '@ionic/angular/standalone'; |
|
|
|
import { |
|
|
|
AssetClass, |
|
|
|
AssetProfileSplit, |
|
|
|
AssetSubClass, |
|
|
|
DataGatheringFrequency, |
|
|
|
DataSource, |
|
|
|
@ -88,11 +93,14 @@ import { format } from 'date-fns'; |
|
|
|
import { StatusCodes } from 'http-status-codes'; |
|
|
|
import { addIcons } from 'ionicons'; |
|
|
|
import { |
|
|
|
calendarClearOutline, |
|
|
|
codeSlashOutline, |
|
|
|
createOutline, |
|
|
|
ellipsisVertical, |
|
|
|
gitCompareOutline, |
|
|
|
readerOutline, |
|
|
|
serverOutline |
|
|
|
serverOutline, |
|
|
|
trashOutline |
|
|
|
} from 'ionicons/icons'; |
|
|
|
import { isBoolean } from 'lodash'; |
|
|
|
import ms from 'ms'; |
|
|
|
@ -105,6 +113,7 @@ import { AssetProfileDialogParams } from './interfaces/interfaces'; |
|
|
|
changeDetection: ChangeDetectionStrategy.OnPush, |
|
|
|
host: { class: 'd-flex flex-column h-100' }, |
|
|
|
imports: [ |
|
|
|
CommonModule, |
|
|
|
FormsModule, |
|
|
|
GfCurrencySelectorComponent, |
|
|
|
GfEntityLogoComponent, |
|
|
|
@ -116,6 +125,7 @@ import { AssetProfileDialogParams } from './interfaces/interfaces'; |
|
|
|
IonIcon, |
|
|
|
MatButtonModule, |
|
|
|
MatCheckboxModule, |
|
|
|
MatDatepickerModule, |
|
|
|
MatDialogModule, |
|
|
|
MatInputModule, |
|
|
|
MatMenuModule, |
|
|
|
@ -196,6 +206,26 @@ export class GfAssetProfileDialogComponent implements OnInit { |
|
|
|
} |
|
|
|
); |
|
|
|
|
|
|
|
protected readonly assetProfileSplitForm = this.formBuilder.group( |
|
|
|
{ |
|
|
|
date: new FormControl<Date | null>(null, Validators.required), |
|
|
|
denominator: new FormControl<number | null>(null, Validators.required), |
|
|
|
numerator: new FormControl<number | null>(null, Validators.required) |
|
|
|
}, |
|
|
|
{ |
|
|
|
validators: (control: AbstractControl): ValidationErrors | null => { |
|
|
|
const { denominator, numerator } = control.value as { |
|
|
|
denominator: number; |
|
|
|
numerator: number; |
|
|
|
}; |
|
|
|
|
|
|
|
return isSplitRatio({ denominator, numerator }) |
|
|
|
? null |
|
|
|
: { invalidSplitRatio: true }; |
|
|
|
} |
|
|
|
} |
|
|
|
); |
|
|
|
|
|
|
|
protected readonly canDeleteAssetProfile = canDeleteAssetProfile; |
|
|
|
protected canEditAssetProfile = true; |
|
|
|
|
|
|
|
@ -247,6 +277,7 @@ export class GfAssetProfileDialogComponent implements OnInit { |
|
|
|
value: 'max' |
|
|
|
} |
|
|
|
]; |
|
|
|
protected defaultDateFormat: string; |
|
|
|
protected readonly getCountryName = getCountryName; |
|
|
|
protected historicalDataItems: LineChartItem[]; |
|
|
|
protected isBenchmark = false; |
|
|
|
@ -270,6 +301,8 @@ export class GfAssetProfileDialogComponent implements OnInit { |
|
|
|
[name: string]: { name: string; value: number }; |
|
|
|
}; |
|
|
|
|
|
|
|
protected splits: AssetProfileSplit[] = []; |
|
|
|
|
|
|
|
protected readonly translate = translate; |
|
|
|
|
|
|
|
protected user: User; |
|
|
|
@ -293,11 +326,14 @@ export class GfAssetProfileDialogComponent implements OnInit { |
|
|
|
private userService: UserService |
|
|
|
) { |
|
|
|
addIcons({ |
|
|
|
calendarClearOutline, |
|
|
|
codeSlashOutline, |
|
|
|
createOutline, |
|
|
|
ellipsisVertical, |
|
|
|
gitCompareOutline, |
|
|
|
readerOutline, |
|
|
|
serverOutline |
|
|
|
serverOutline, |
|
|
|
trashOutline |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
@ -310,6 +346,7 @@ export class GfAssetProfileDialogComponent implements OnInit { |
|
|
|
|
|
|
|
this.benchmarks = benchmarks; |
|
|
|
this.currencies = currencies; |
|
|
|
this.defaultDateFormat = getDateFormatString(this.data.locale); |
|
|
|
|
|
|
|
this.initialize(); |
|
|
|
} |
|
|
|
@ -364,8 +401,9 @@ export class GfAssetProfileDialogComponent implements OnInit { |
|
|
|
symbol: this.data.symbol |
|
|
|
}) |
|
|
|
.pipe(takeUntilDestroyed(this.destroyRef)) |
|
|
|
.subscribe(({ assetProfile, marketData }) => { |
|
|
|
.subscribe(({ assetProfile, marketData, splits }) => { |
|
|
|
this.assetProfile = assetProfile; |
|
|
|
this.splits = splits ?? []; |
|
|
|
|
|
|
|
this.assetClassLabel = translate(this.assetProfile?.assetClass ?? ''); |
|
|
|
this.assetSubClassLabel = translate( |
|
|
|
@ -521,6 +559,45 @@ export class GfAssetProfileDialogComponent implements OnInit { |
|
|
|
.subscribe(); |
|
|
|
} |
|
|
|
|
|
|
|
protected onAddSplit() { |
|
|
|
const { date, denominator, numerator } = |
|
|
|
this.assetProfileSplitForm.getRawValue(); |
|
|
|
|
|
|
|
if (!date || !denominator || !numerator) { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
this.adminService |
|
|
|
.postAssetProfileSplit({ |
|
|
|
dataSource: this.data.dataSource, |
|
|
|
split: { |
|
|
|
denominator, |
|
|
|
numerator, |
|
|
|
date: format(date, DATE_FORMAT) |
|
|
|
}, |
|
|
|
symbol: this.data.symbol |
|
|
|
}) |
|
|
|
.pipe(takeUntilDestroyed(this.destroyRef)) |
|
|
|
.subscribe(() => { |
|
|
|
this.assetProfileSplitForm.reset(); |
|
|
|
|
|
|
|
this.initialize(); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
protected onDeleteSplit(aId: string) { |
|
|
|
this.adminService |
|
|
|
.deleteAssetProfileSplit({ |
|
|
|
dataSource: this.data.dataSource, |
|
|
|
id: aId, |
|
|
|
symbol: this.data.symbol |
|
|
|
}) |
|
|
|
.pipe(takeUntilDestroyed(this.destroyRef)) |
|
|
|
.subscribe(() => { |
|
|
|
this.initialize(); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
protected onMarketDataChanged(withRefresh: boolean = false) { |
|
|
|
if (withRefresh) { |
|
|
|
this.initialize(); |
|
|
|
|