Feature/split scraper configuration into sub form (#4157)
* Split scraper configuration into sub form * Update changelog
This commit is contained in:
parent
5d2f763ca2
commit
a75599bf5d
@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
- Extracted the scraper configuration to a sub form in the asset profile details dialog of the admin control
|
||||||
- Migrated the database seeding to _TypeScript_
|
- Migrated the database seeding to _TypeScript_
|
||||||
- Improved the language localization for German (`de`)
|
- Improved the language localization for German (`de`)
|
||||||
- Upgraded `@trivago/prettier-plugin-sort-imports` from version `4.3.0` to `5.2.1`
|
- Upgraded `@trivago/prettier-plugin-sort-imports` from version `4.3.0` to `5.2.1`
|
||||||
|
@ -7,5 +7,21 @@
|
|||||||
gf-line-chart {
|
gf-line-chart {
|
||||||
aspect-ratio: 16/9;
|
aspect-ratio: 16/9;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mat-expansion-panel {
|
||||||
|
--mat-expansion-container-background-color: transparent;
|
||||||
|
|
||||||
|
::ng-deep {
|
||||||
|
.mat-expansion-panel-body {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-expansion-panel-header {
|
||||||
|
&:hover {
|
||||||
|
--mat-expansion-header-hover-state-layer-color: transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,8 @@ import {
|
|||||||
Component,
|
Component,
|
||||||
Inject,
|
Inject,
|
||||||
OnDestroy,
|
OnDestroy,
|
||||||
OnInit
|
OnInit,
|
||||||
|
signal
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { FormBuilder, FormControl, Validators } from '@angular/forms';
|
import { FormBuilder, FormControl, Validators } from '@angular/forms';
|
||||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||||
@ -64,7 +65,14 @@ export class AssetProfileDialog implements OnDestroy, OnInit {
|
|||||||
csvString: ''
|
csvString: ''
|
||||||
}),
|
}),
|
||||||
name: ['', Validators.required],
|
name: ['', Validators.required],
|
||||||
scraperConfiguration: '',
|
scraperConfiguration: this.formBuilder.group({
|
||||||
|
defaultMarketPrice: null,
|
||||||
|
headers: JSON.stringify({}),
|
||||||
|
locale: '',
|
||||||
|
mode: '',
|
||||||
|
selector: '',
|
||||||
|
url: ''
|
||||||
|
}),
|
||||||
sectors: '',
|
sectors: '',
|
||||||
symbolMapping: '',
|
symbolMapping: '',
|
||||||
url: ''
|
url: ''
|
||||||
@ -79,6 +87,11 @@ export class AssetProfileDialog implements OnDestroy, OnInit {
|
|||||||
public historicalDataItems: LineChartItem[];
|
public historicalDataItems: LineChartItem[];
|
||||||
public isBenchmark = false;
|
public isBenchmark = false;
|
||||||
public marketDataItems: MarketData[] = [];
|
public marketDataItems: MarketData[] = [];
|
||||||
|
public modeValues = [
|
||||||
|
{ value: 'lazy', viewValue: $localize`Lazy` },
|
||||||
|
{ value: 'instant', viewValue: $localize`Instant` }
|
||||||
|
];
|
||||||
|
public scraperConfiguationIsExpanded = signal(false);
|
||||||
public sectors: {
|
public sectors: {
|
||||||
[name: string]: { name: string; value: number };
|
[name: string]: { name: string; value: number };
|
||||||
};
|
};
|
||||||
@ -181,9 +194,18 @@ export class AssetProfileDialog implements OnDestroy, OnInit {
|
|||||||
csvString: AssetProfileDialog.HISTORICAL_DATA_TEMPLATE
|
csvString: AssetProfileDialog.HISTORICAL_DATA_TEMPLATE
|
||||||
},
|
},
|
||||||
name: this.assetProfile.name ?? this.assetProfile.symbol,
|
name: this.assetProfile.name ?? this.assetProfile.symbol,
|
||||||
scraperConfiguration: JSON.stringify(
|
scraperConfiguration: {
|
||||||
this.assetProfile?.scraperConfiguration ?? {}
|
defaultMarketPrice:
|
||||||
),
|
this.assetProfile?.scraperConfiguration?.defaultMarketPrice ??
|
||||||
|
null,
|
||||||
|
headers: JSON.stringify(
|
||||||
|
this.assetProfile?.scraperConfiguration?.headers ?? {}
|
||||||
|
),
|
||||||
|
locale: this.assetProfile?.scraperConfiguration?.locale ?? '',
|
||||||
|
mode: this.assetProfile?.scraperConfiguration?.mode ?? 'lazy',
|
||||||
|
selector: this.assetProfile?.scraperConfiguration?.selector ?? '',
|
||||||
|
url: this.assetProfile?.scraperConfiguration?.url ?? ''
|
||||||
|
},
|
||||||
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 ?? ''
|
url: this.assetProfile?.url ?? ''
|
||||||
@ -252,9 +274,31 @@ export class AssetProfileDialog implements OnDestroy, OnInit {
|
|||||||
} catch {}
|
} catch {}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
scraperConfiguration = JSON.parse(
|
scraperConfiguration = {
|
||||||
this.assetProfileForm.get('scraperConfiguration').value
|
defaultMarketPrice:
|
||||||
);
|
this.assetProfileForm.controls['scraperConfiguration'].controls[
|
||||||
|
'defaultMarketPrice'
|
||||||
|
].value,
|
||||||
|
headers: JSON.parse(
|
||||||
|
this.assetProfileForm.controls['scraperConfiguration'].controls[
|
||||||
|
'headers'
|
||||||
|
].value
|
||||||
|
),
|
||||||
|
locale:
|
||||||
|
this.assetProfileForm.controls['scraperConfiguration'].controls[
|
||||||
|
'locale'
|
||||||
|
].value,
|
||||||
|
mode: this.assetProfileForm.controls['scraperConfiguration'].controls[
|
||||||
|
'mode'
|
||||||
|
].value,
|
||||||
|
selector:
|
||||||
|
this.assetProfileForm.controls['scraperConfiguration'].controls[
|
||||||
|
'selector'
|
||||||
|
].value,
|
||||||
|
url: this.assetProfileForm.controls['scraperConfiguration'].controls[
|
||||||
|
'url'
|
||||||
|
].value
|
||||||
|
};
|
||||||
} catch {}
|
} catch {}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -306,8 +350,31 @@ export class AssetProfileDialog implements OnDestroy, OnInit {
|
|||||||
this.adminService
|
this.adminService
|
||||||
.testMarketData({
|
.testMarketData({
|
||||||
dataSource: this.data.dataSource,
|
dataSource: this.data.dataSource,
|
||||||
scraperConfiguration: this.assetProfileForm.get('scraperConfiguration')
|
scraperConfiguration: JSON.stringify({
|
||||||
.value,
|
defaultMarketPrice:
|
||||||
|
this.assetProfileForm.controls['scraperConfiguration'].controls[
|
||||||
|
'defaultMarketPrice'
|
||||||
|
].value,
|
||||||
|
headers: JSON.parse(
|
||||||
|
this.assetProfileForm.controls['scraperConfiguration'].controls[
|
||||||
|
'headers'
|
||||||
|
].value
|
||||||
|
),
|
||||||
|
locale:
|
||||||
|
this.assetProfileForm.controls['scraperConfiguration'].controls[
|
||||||
|
'locale'
|
||||||
|
].value,
|
||||||
|
mode: this.assetProfileForm.controls['scraperConfiguration'].controls[
|
||||||
|
'mode'
|
||||||
|
].value,
|
||||||
|
selector:
|
||||||
|
this.assetProfileForm.controls['scraperConfiguration'].controls[
|
||||||
|
'selector'
|
||||||
|
].value,
|
||||||
|
url: this.assetProfileForm.controls['scraperConfiguration'].controls[
|
||||||
|
'url'
|
||||||
|
].value
|
||||||
|
}),
|
||||||
symbol: this.data.symbol
|
symbol: this.data.symbol
|
||||||
})
|
})
|
||||||
.pipe(
|
.pipe(
|
||||||
|
@ -278,31 +278,106 @@
|
|||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
@if (assetProfile?.dataSource === 'MANUAL') {
|
@if (assetProfile?.dataSource === 'MANUAL') {
|
||||||
<div>
|
<div class="mb-3">
|
||||||
<mat-form-field appearance="outline" class="w-100">
|
<mat-accordion class="my-3">
|
||||||
<mat-label i18n>Scraper Configuration</mat-label>
|
<mat-expansion-panel
|
||||||
<div class="align-items-end d-flex">
|
class="shadow-none"
|
||||||
<textarea
|
[expanded]="
|
||||||
cdkTextareaAutosize
|
assetProfileForm.controls.scraperConfiguration.controls.selector
|
||||||
formControlName="scraperConfiguration"
|
.value !== '' &&
|
||||||
matInput
|
assetProfileForm.controls.scraperConfiguration.controls.url
|
||||||
type="text"
|
.value !== ''
|
||||||
(keyup.enter)="$event.stopPropagation()"
|
"
|
||||||
></textarea>
|
(closed)="scraperConfiguationIsExpanded.set(false)"
|
||||||
<button
|
(opened)="scraperConfiguationIsExpanded.set(true)"
|
||||||
color="accent"
|
>
|
||||||
mat-flat-button
|
<mat-expansion-panel-header class="p-0">
|
||||||
type="button"
|
<mat-panel-title i18n>Scraper Configuration</mat-panel-title>
|
||||||
[disabled]="
|
</mat-expansion-panel-header>
|
||||||
assetProfileForm.get('scraperConfiguration').value === '{}'
|
<div formGroupName="scraperConfiguration">
|
||||||
"
|
<div class="mt-3">
|
||||||
(click)="onTestMarketData()"
|
<mat-form-field appearance="outline" class="w-100 without-hint">
|
||||||
>
|
<mat-label i18n>Default Market Price</mat-label>
|
||||||
<ng-container i18n>Test</ng-container>
|
<input
|
||||||
</button>
|
formControlName="defaultMarketPrice"
|
||||||
</div>
|
matInput
|
||||||
</mat-form-field>
|
type="number"
|
||||||
|
/>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3">
|
||||||
|
<mat-form-field appearance="outline" class="w-100 without-hint">
|
||||||
|
<mat-label i18n>Headers</mat-label>
|
||||||
|
<textarea
|
||||||
|
cdkTextareaAutosize
|
||||||
|
formControlName="headers"
|
||||||
|
matInput
|
||||||
|
type="text"
|
||||||
|
[matAutocomplete]="auto"
|
||||||
|
></textarea>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3">
|
||||||
|
<mat-form-field appearance="outline" class="w-100 without-hint">
|
||||||
|
<mat-label i18n>Locale</mat-label>
|
||||||
|
<input formControlName="locale" matInput type="text" />
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3">
|
||||||
|
<mat-form-field appearance="outline" class="w-100 without-hint">
|
||||||
|
<mat-label i18n>Mode</mat-label>
|
||||||
|
<mat-select formControlName="mode">
|
||||||
|
@for (modeValue of modeValues; track modeValue) {
|
||||||
|
<mat-option [value]="modeValue.value">{{
|
||||||
|
modeValue.viewValue
|
||||||
|
}}</mat-option>
|
||||||
|
}
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3">
|
||||||
|
<mat-form-field appearance="outline" class="w-100 without-hint">
|
||||||
|
<mat-label>
|
||||||
|
<ng-container i18n>Selector</ng-container>*
|
||||||
|
</mat-label>
|
||||||
|
<textarea
|
||||||
|
cdkTextareaAutosize
|
||||||
|
formControlName="selector"
|
||||||
|
matInput
|
||||||
|
type="text"
|
||||||
|
></textarea>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3">
|
||||||
|
<mat-form-field appearance="outline" class="w-100 without-hint">
|
||||||
|
<mat-label>
|
||||||
|
<ng-container i18n>Url</ng-container>*
|
||||||
|
</mat-label>
|
||||||
|
<input formControlName="url" matInput type="text" />
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div class="my-3 text-right">
|
||||||
|
<button
|
||||||
|
color="accent"
|
||||||
|
mat-flat-button
|
||||||
|
type="button"
|
||||||
|
[disabled]="
|
||||||
|
assetProfileForm.controls.scraperConfiguration.controls
|
||||||
|
.selector.value === '' ||
|
||||||
|
assetProfileForm.controls.scraperConfiguration.controls.url
|
||||||
|
.value === ''
|
||||||
|
"
|
||||||
|
(click)="onTestMarketData()"
|
||||||
|
>
|
||||||
|
<ng-container i18n>Test</ng-container>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</mat-expansion-panel>
|
||||||
|
</mat-accordion>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
|
@if (assetProfile?.dataSource === 'MANUAL') {
|
||||||
<div>
|
<div>
|
||||||
<mat-form-field appearance="outline" class="w-100">
|
<mat-form-field appearance="outline" class="w-100">
|
||||||
<mat-label i18n>Sectors</mat-label>
|
<mat-label i18n>Sectors</mat-label>
|
||||||
|
@ -13,6 +13,7 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||||
import { MatDialogModule } from '@angular/material/dialog';
|
import { MatDialogModule } from '@angular/material/dialog';
|
||||||
|
import { MatExpansionModule } from '@angular/material/expansion';
|
||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
import { MatMenuModule } from '@angular/material/menu';
|
import { MatMenuModule } from '@angular/material/menu';
|
||||||
import { MatSelectModule } from '@angular/material/select';
|
import { MatSelectModule } from '@angular/material/select';
|
||||||
@ -34,6 +35,7 @@ import { AssetProfileDialog } from './asset-profile-dialog.component';
|
|||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
MatCheckboxModule,
|
MatCheckboxModule,
|
||||||
MatDialogModule,
|
MatDialogModule,
|
||||||
|
MatExpansionModule,
|
||||||
MatInputModule,
|
MatInputModule,
|
||||||
MatMenuModule,
|
MatMenuModule,
|
||||||
MatSelectModule,
|
MatSelectModule,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user