Feature/respect data source in symbol data endpoint (#370)
* Respect data source in symbol data endpoint * Respect data source in the data provider service * Combine symbol with data source in get() of data provider service * Improve search functionality for multiple data sources * Update changelog
This commit is contained in:
@@ -29,6 +29,7 @@ import {
|
||||
} from '@ghostfolio/common/interfaces';
|
||||
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
|
||||
import { DateRange } from '@ghostfolio/common/types';
|
||||
import { DataSource } from '@prisma/client';
|
||||
import { DeviceDetectorService } from 'ngx-device-detector';
|
||||
import { Subject, Subscription } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
@@ -112,7 +113,10 @@ export class HomePageComponent implements OnDestroy, OnInit {
|
||||
|
||||
if (this.hasPermissionToAccessFearAndGreedIndex) {
|
||||
this.dataService
|
||||
.fetchSymbolItem(ghostfolioFearAndGreedIndexSymbol)
|
||||
.fetchSymbolItem({
|
||||
dataSource: DataSource.RAKUTEN,
|
||||
symbol: ghostfolioFearAndGreedIndexSymbol
|
||||
})
|
||||
.pipe(takeUntil(this.unsubscribeSubject))
|
||||
.subscribe(({ marketPrice }) => {
|
||||
this.fearAndGreedIndex = marketPrice;
|
||||
|
@@ -3,7 +3,8 @@ import {
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
Inject,
|
||||
OnDestroy
|
||||
OnDestroy,
|
||||
ViewChild
|
||||
} from '@angular/core';
|
||||
import { FormControl, Validators } from '@angular/forms';
|
||||
import { MatAutocompleteSelectedEvent } from '@angular/material/autocomplete';
|
||||
@@ -11,6 +12,7 @@ import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { LookupItem } from '@ghostfolio/api/app/symbol/interfaces/lookup-item.interface';
|
||||
import { DataService } from '@ghostfolio/client/services/data.service';
|
||||
import { Currency } from '@prisma/client';
|
||||
import { isString } from 'lodash';
|
||||
import { EMPTY, Observable, Subject } from 'rxjs';
|
||||
import {
|
||||
catchError,
|
||||
@@ -31,13 +33,18 @@ import { CreateOrUpdateTransactionDialogParams } from './interfaces/interfaces';
|
||||
templateUrl: 'create-or-update-transaction-dialog.html'
|
||||
})
|
||||
export class CreateOrUpdateTransactionDialog implements OnDestroy {
|
||||
@ViewChild('autocomplete') autocomplete;
|
||||
|
||||
public currencies: Currency[] = [];
|
||||
public currentMarketPrice = null;
|
||||
public filteredLookupItems: Observable<LookupItem[]>;
|
||||
public isLoading = false;
|
||||
public platforms: { id: string; name: string }[];
|
||||
public searchSymbolCtrl = new FormControl(
|
||||
this.data.transaction.symbol,
|
||||
{
|
||||
dataSource: this.data.transaction.dataSource,
|
||||
name: this.data.transaction.symbol
|
||||
},
|
||||
Validators.required
|
||||
);
|
||||
|
||||
@@ -60,9 +67,9 @@ export class CreateOrUpdateTransactionDialog implements OnDestroy {
|
||||
startWith(''),
|
||||
debounceTime(400),
|
||||
distinctUntilChanged(),
|
||||
switchMap((aQuery: string) => {
|
||||
if (aQuery) {
|
||||
return this.dataService.fetchSymbols(aQuery);
|
||||
switchMap((query: string) => {
|
||||
if (isString(query)) {
|
||||
return this.dataService.fetchSymbols(query);
|
||||
}
|
||||
|
||||
return [];
|
||||
@@ -71,7 +78,10 @@ export class CreateOrUpdateTransactionDialog implements OnDestroy {
|
||||
|
||||
if (this.data.transaction.symbol) {
|
||||
this.dataService
|
||||
.fetchSymbolItem(this.data.transaction.symbol)
|
||||
.fetchSymbolItem({
|
||||
dataSource: this.data.transaction.dataSource,
|
||||
symbol: this.data.transaction.symbol
|
||||
})
|
||||
.pipe(takeUntil(this.unsubscribeSubject))
|
||||
.subscribe(({ marketPrice }) => {
|
||||
this.currentMarketPrice = marketPrice;
|
||||
@@ -85,9 +95,21 @@ export class CreateOrUpdateTransactionDialog implements OnDestroy {
|
||||
this.data.transaction.unitPrice = this.currentMarketPrice;
|
||||
}
|
||||
|
||||
public displayFn(aLookupItem: LookupItem) {
|
||||
return aLookupItem?.name ?? '';
|
||||
}
|
||||
|
||||
public onBlurSymbol() {
|
||||
const symbol = this.searchSymbolCtrl.value;
|
||||
this.updateSymbol(symbol);
|
||||
this.data.transaction.currency = null;
|
||||
this.data.transaction.dataSource = null;
|
||||
|
||||
if (this.autocomplete.isOpen) {
|
||||
this.searchSymbolCtrl.setErrors({ incorrect: true });
|
||||
} else {
|
||||
this.data.transaction.unitPrice = null;
|
||||
}
|
||||
|
||||
this.changeDetectorRef.markForCheck();
|
||||
}
|
||||
|
||||
public onCancel(): void {
|
||||
@@ -95,7 +117,8 @@ export class CreateOrUpdateTransactionDialog implements OnDestroy {
|
||||
}
|
||||
|
||||
public onUpdateSymbol(event: MatAutocompleteSelectedEvent) {
|
||||
this.updateSymbol(event.option.value);
|
||||
this.data.transaction.dataSource = event.option.value.dataSource;
|
||||
this.updateSymbol(event.option.value.symbol);
|
||||
}
|
||||
|
||||
public ngOnDestroy() {
|
||||
@@ -106,10 +129,15 @@ export class CreateOrUpdateTransactionDialog implements OnDestroy {
|
||||
private updateSymbol(symbol: string) {
|
||||
this.isLoading = true;
|
||||
|
||||
this.searchSymbolCtrl.setErrors(null);
|
||||
|
||||
this.data.transaction.symbol = symbol;
|
||||
|
||||
this.dataService
|
||||
.fetchSymbolItem(this.data.transaction.symbol)
|
||||
.fetchSymbolItem({
|
||||
dataSource: this.data.transaction.dataSource,
|
||||
symbol: this.data.transaction.symbol
|
||||
})
|
||||
.pipe(
|
||||
catchError(() => {
|
||||
this.data.transaction.currency = null;
|
||||
|
@@ -28,18 +28,19 @@
|
||||
matInput
|
||||
required
|
||||
[formControl]="searchSymbolCtrl"
|
||||
[matAutocomplete]="auto"
|
||||
[matAutocomplete]="autocomplete"
|
||||
(blur)="onBlurSymbol()"
|
||||
/>
|
||||
<mat-autocomplete
|
||||
#auto="matAutocomplete"
|
||||
#autocomplete="matAutocomplete"
|
||||
[displayWith]="displayFn"
|
||||
(optionSelected)="onUpdateSymbol($event)"
|
||||
>
|
||||
<ng-container>
|
||||
<mat-option
|
||||
*ngFor="let lookupItem of filteredLookupItems | async"
|
||||
class="autocomplete"
|
||||
[value]="lookupItem.symbol"
|
||||
[value]="lookupItem"
|
||||
>
|
||||
<span class="mr-2 symbol">{{ lookupItem.symbol | gfSymbol }}</span
|
||||
><span><b>{{ lookupItem.name }}</b></span>
|
||||
|
@@ -29,8 +29,11 @@ import {
|
||||
import { InvestmentItem } from '@ghostfolio/common/interfaces/investment-item.interface';
|
||||
import { permissions } from '@ghostfolio/common/permissions';
|
||||
import { DateRange } from '@ghostfolio/common/types';
|
||||
import { Order as OrderModel } from '@prisma/client';
|
||||
import { Account as AccountModel } from '@prisma/client';
|
||||
import {
|
||||
Account as AccountModel,
|
||||
DataSource,
|
||||
Order as OrderModel
|
||||
} from '@prisma/client';
|
||||
import { parseISO } from 'date-fns';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { Observable } from 'rxjs';
|
||||
@@ -108,8 +111,14 @@ export class DataService {
|
||||
return info;
|
||||
}
|
||||
|
||||
public fetchSymbolItem(aSymbol: string) {
|
||||
return this.http.get<SymbolItem>(`/api/symbol/${aSymbol}`);
|
||||
public fetchSymbolItem({
|
||||
dataSource,
|
||||
symbol
|
||||
}: {
|
||||
dataSource: DataSource;
|
||||
symbol: string;
|
||||
}) {
|
||||
return this.http.get<SymbolItem>(`/api/symbol/${dataSource}/${symbol}`);
|
||||
}
|
||||
|
||||
public fetchPositions({
|
||||
|
Reference in New Issue
Block a user