Browse Source

Merge 09f01df2cd into d4a0f48ca2

pull/6284/merge
Omkar Gujja 2 days ago
committed by GitHub
parent
commit
422a456c8c
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 4
      apps/api/src/app/admin/admin.service.ts
  2. 13
      apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts
  3. 124
      apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html
  4. 15
      libs/common/src/lib/utils/form.util.ts

4
apps/api/src/app/admin/admin.service.ts

@ -622,7 +622,9 @@ export class AdminService {
assetClass: assetClass as AssetClass, assetClass: assetClass as AssetClass,
assetSubClass: assetSubClass as AssetSubClass, assetSubClass: assetSubClass as AssetSubClass,
name: name as string, name: name as string,
url: url as string countries: countries as Prisma.JsonArray,
url: url as string,
sectors: sectors as Prisma.JsonArray
}; };
const updatedSymbolProfile: Prisma.SymbolProfileUpdateInput = { const updatedSymbolProfile: Prisma.SymbolProfileUpdateInput = {

13
apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts

@ -15,7 +15,10 @@ import {
User User
} from '@ghostfolio/common/interfaces'; } from '@ghostfolio/common/interfaces';
import { DateRange } from '@ghostfolio/common/types'; import { DateRange } from '@ghostfolio/common/types';
import { validateObjectForForm } from '@ghostfolio/common/utils'; import {
validateObjectForForm,
jsonValidator
} from '@ghostfolio/common/utils/form.util';
import { GfCurrencySelectorComponent } from '@ghostfolio/ui/currency-selector'; import { GfCurrencySelectorComponent } from '@ghostfolio/ui/currency-selector';
import { GfEntityLogoComponent } from '@ghostfolio/ui/entity-logo'; import { GfEntityLogoComponent } from '@ghostfolio/ui/entity-logo';
import { GfHistoricalMarketDataEditorComponent } from '@ghostfolio/ui/historical-market-data-editor'; import { GfHistoricalMarketDataEditorComponent } from '@ghostfolio/ui/historical-market-data-editor';
@ -145,7 +148,7 @@ export class GfAssetProfileDialogComponent 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: '',
countries: '', countries: ['', jsonValidator()],
currency: '', currency: '',
historicalData: this.formBuilder.group({ historicalData: this.formBuilder.group({
csvString: '' csvString: ''
@ -154,14 +157,14 @@ export class GfAssetProfileDialogComponent implements OnDestroy, OnInit {
name: ['', Validators.required], name: ['', Validators.required],
scraperConfiguration: this.formBuilder.group({ scraperConfiguration: this.formBuilder.group({
defaultMarketPrice: null, defaultMarketPrice: null,
headers: JSON.stringify({}), headers: [JSON.stringify({}), jsonValidator()],
locale: '', locale: '',
mode: '', mode: '',
selector: '', selector: '',
url: '' url: ''
}), }),
sectors: '', sectors: ['', jsonValidator()],
symbolMapping: '', symbolMapping: ['', jsonValidator()],
url: '' url: ''
}); });

124
apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html

@ -391,6 +391,129 @@
</mat-form-field> </mat-form-field>
</div> </div>
@if (assetProfile?.dataSource === 'MANUAL') { @if (assetProfile?.dataSource === 'MANUAL') {
<div class="mb-3">
<mat-accordion class="my-3">
<mat-expansion-panel
class="shadow-none"
[expanded]="
assetProfileForm.controls.scraperConfiguration.controls
.selector.value !== '' &&
assetProfileForm.controls.scraperConfiguration.controls
.url.value !== ''
"
(closed)="scraperConfiguationIsExpanded.set(false)"
(opened)="scraperConfiguationIsExpanded.set(true)"
>
<mat-expansion-panel-header class="p-0 pr-3">
<mat-panel-title class="font-weight-bold" i18n
>Scraper Configuration</mat-panel-title
>
</mat-expansion-panel-header>
<div formGroupName="scraperConfiguration">
<div class="mt-3">
<mat-form-field
appearance="outline"
class="w-100 without-hint"
>
<mat-label i18n>Default Market Price</mat-label>
<input
formControlName="defaultMarketPrice"
matInput
type="number"
/>
</mat-form-field>
</div>
<div class="mt-3">
<mat-form-field
appearance="outline"
class="w-100 without-hint"
>
<mat-label i18n>HTTP Request 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> <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>
@ -413,7 +536,6 @@
></textarea> ></textarea>
</mat-form-field> </mat-form-field>
</div> </div>
}
<div> <div>
<mat-form-field appearance="outline" class="w-100 without-hint"> <mat-form-field appearance="outline" class="w-100 without-hint">
<mat-label i18n>Url</mat-label> <mat-label i18n>Url</mat-label>

15
libs/common/src/lib/utils/form.util.ts

@ -1,3 +1,4 @@
import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';
import { FormGroup } from '@angular/forms'; import { FormGroup } from '@angular/forms';
import { plainToInstance } from 'class-transformer'; import { plainToInstance } from 'class-transformer';
import { validate } from 'class-validator'; import { validate } from 'class-validator';
@ -44,3 +45,17 @@ export async function validateObjectForForm<T>({
return Promise.reject(nonIgnoredErrors); return Promise.reject(nonIgnoredErrors);
} }
export function jsonValidator(): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {
if (!control.value) {
return null;
}
try {
JSON.parse(control.value);
} catch {
return { invalidJson: true };
}
};
}

Loading…
Cancel
Save