Feature/more discreet data provider warning (#589)
* Upgrade http-status-codes to version 2.2.0 * Make the data provider warning more discreet * Update changelog
This commit is contained in:
parent
994275e093
commit
db1d474ddf
@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
### Changed
|
||||
|
||||
- Made the data provider warning more discreet
|
||||
- Upgraded `http-status-codes` from version `2.1.4` to `2.2.0`
|
||||
- Upgraded `ngx-device-detector` from version `2.1.1` to `3.0.0`
|
||||
- Upgraded `ngx-markdown` from version `12.0.1` to `13.0.0`
|
||||
- Upgraded `ngx-stripe` from version `12.0.2` to `13.0.0`
|
||||
|
@ -51,7 +51,7 @@ export class PortfolioController {
|
||||
@Get('investments')
|
||||
@UseGuards(AuthGuard('jwt'))
|
||||
public async findAll(
|
||||
@Headers('impersonation-id') impersonationId,
|
||||
@Headers('impersonation-id') impersonationId: string,
|
||||
@Res() res: Response
|
||||
): Promise<InvestmentItem[]> {
|
||||
if (
|
||||
@ -87,7 +87,7 @@ export class PortfolioController {
|
||||
@Get('chart')
|
||||
@UseGuards(AuthGuard('jwt'))
|
||||
public async getChart(
|
||||
@Headers('impersonation-id') impersonationId,
|
||||
@Headers('impersonation-id') impersonationId: string,
|
||||
@Query('range') range,
|
||||
@Res() res: Response
|
||||
): Promise<PortfolioChart> {
|
||||
@ -98,18 +98,14 @@ export class PortfolioController {
|
||||
|
||||
let chartData = historicalDataContainer.items;
|
||||
|
||||
let hasNullValue = false;
|
||||
let hasError = false;
|
||||
|
||||
chartData.forEach((chartDataItem) => {
|
||||
if (hasNotDefinedValuesInObject(chartDataItem)) {
|
||||
hasNullValue = true;
|
||||
hasError = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (hasNullValue) {
|
||||
res.status(StatusCodes.ACCEPTED);
|
||||
}
|
||||
|
||||
if (
|
||||
impersonationId ||
|
||||
this.userService.isRestrictedView(this.request.user)
|
||||
@ -131,6 +127,7 @@ export class PortfolioController {
|
||||
}
|
||||
|
||||
return <any>res.json({
|
||||
hasError,
|
||||
chart: chartData,
|
||||
isAllTimeHigh: historicalDataContainer.isAllTimeHigh,
|
||||
isAllTimeLow: historicalDataContainer.isAllTimeLow
|
||||
@ -140,7 +137,7 @@ export class PortfolioController {
|
||||
@Get('details')
|
||||
@UseGuards(AuthGuard('jwt'))
|
||||
public async getDetails(
|
||||
@Headers('impersonation-id') impersonationId,
|
||||
@Headers('impersonation-id') impersonationId: string,
|
||||
@Query('range') range,
|
||||
@Res() res: Response
|
||||
): Promise<PortfolioDetails> {
|
||||
@ -152,6 +149,8 @@ export class PortfolioController {
|
||||
return <any>res.json({ accounts: {}, holdings: {} });
|
||||
}
|
||||
|
||||
let hasError = false;
|
||||
|
||||
const { accounts, holdings, hasErrors } =
|
||||
await this.portfolioService.getDetails(
|
||||
impersonationId,
|
||||
@ -160,7 +159,7 @@ export class PortfolioController {
|
||||
);
|
||||
|
||||
if (hasErrors || hasNotDefinedValuesInObject(holdings)) {
|
||||
res.status(StatusCodes.ACCEPTED);
|
||||
hasError = true;
|
||||
}
|
||||
|
||||
if (
|
||||
@ -198,43 +197,38 @@ export class PortfolioController {
|
||||
}
|
||||
}
|
||||
|
||||
return <any>res.json({ accounts, holdings });
|
||||
return <any>res.json({ accounts, hasError, holdings });
|
||||
}
|
||||
|
||||
@Get('performance')
|
||||
@UseGuards(AuthGuard('jwt'))
|
||||
public async getPerformance(
|
||||
@Headers('impersonation-id') impersonationId,
|
||||
@Headers('impersonation-id') impersonationId: string,
|
||||
@Query('range') range,
|
||||
@Res() res: Response
|
||||
): Promise<PortfolioPerformance> {
|
||||
): Promise<{ hasErrors: boolean; performance: PortfolioPerformance }> {
|
||||
const performanceInformation = await this.portfolioService.getPerformance(
|
||||
impersonationId,
|
||||
range
|
||||
);
|
||||
|
||||
if (performanceInformation?.hasErrors) {
|
||||
res.status(StatusCodes.ACCEPTED);
|
||||
}
|
||||
|
||||
let performance = performanceInformation.performance;
|
||||
if (
|
||||
impersonationId ||
|
||||
this.userService.isRestrictedView(this.request.user)
|
||||
) {
|
||||
performance = nullifyValuesInObject(performance, [
|
||||
'currentGrossPerformance',
|
||||
'currentValue'
|
||||
]);
|
||||
performanceInformation.performance = nullifyValuesInObject(
|
||||
performanceInformation.performance,
|
||||
['currentGrossPerformance', 'currentValue']
|
||||
);
|
||||
}
|
||||
|
||||
return <any>res.json(performance);
|
||||
return <any>res.json(performanceInformation);
|
||||
}
|
||||
|
||||
@Get('positions')
|
||||
@UseGuards(AuthGuard('jwt'))
|
||||
public async getPositions(
|
||||
@Headers('impersonation-id') impersonationId,
|
||||
@Headers('impersonation-id') impersonationId: string,
|
||||
@Query('range') range,
|
||||
@Res() res: Response
|
||||
): Promise<PortfolioPositions> {
|
||||
@ -243,10 +237,6 @@ export class PortfolioController {
|
||||
range
|
||||
);
|
||||
|
||||
if (result?.hasErrors) {
|
||||
res.status(StatusCodes.ACCEPTED);
|
||||
}
|
||||
|
||||
if (
|
||||
impersonationId ||
|
||||
this.userService.isRestrictedView(this.request.user)
|
||||
@ -353,7 +343,7 @@ export class PortfolioController {
|
||||
@Get('position/:symbol')
|
||||
@UseGuards(AuthGuard('jwt'))
|
||||
public async getPosition(
|
||||
@Headers('impersonation-id') impersonationId,
|
||||
@Headers('impersonation-id') impersonationId: string,
|
||||
@Param('symbol') symbol
|
||||
): Promise<PortfolioPositionDetail> {
|
||||
let position = await this.portfolioService.getPosition(
|
||||
@ -387,7 +377,7 @@ export class PortfolioController {
|
||||
@Get('report')
|
||||
@UseGuards(AuthGuard('jwt'))
|
||||
public async getReport(
|
||||
@Headers('impersonation-id') impersonationId,
|
||||
@Headers('impersonation-id') impersonationId: string,
|
||||
@Res() res: Response
|
||||
): Promise<PortfolioReport> {
|
||||
if (
|
||||
|
@ -29,6 +29,7 @@ export class HomeOverviewComponent implements OnDestroy, OnInit {
|
||||
{ label: 'Max', value: 'max' }
|
||||
];
|
||||
public deviceType: string;
|
||||
public hasError: boolean;
|
||||
public hasImpersonationId: boolean;
|
||||
public historicalDataItems: LineChartItem[];
|
||||
public isAllTimeHigh: boolean;
|
||||
@ -116,7 +117,8 @@ export class HomeOverviewComponent implements OnDestroy, OnInit {
|
||||
.fetchPortfolioPerformance({ range: this.dateRange })
|
||||
.pipe(takeUntil(this.unsubscribeSubject))
|
||||
.subscribe((response) => {
|
||||
this.performance = response;
|
||||
this.hasError = response.hasErrors;
|
||||
this.performance = response.performance;
|
||||
this.isLoadingPerformance = false;
|
||||
|
||||
this.changeDetectorRef.markForCheck();
|
||||
|
@ -1,15 +1,5 @@
|
||||
<div
|
||||
class="
|
||||
align-items-center
|
||||
container
|
||||
d-flex
|
||||
flex-column
|
||||
h-100
|
||||
justify-content-center
|
||||
overview
|
||||
p-0
|
||||
position-relative
|
||||
"
|
||||
class="align-items-center container d-flex flex-column h-100 justify-content-center overview p-0 position-relative"
|
||||
>
|
||||
<div class="row w-100">
|
||||
<div class="chart-container col">
|
||||
@ -37,6 +27,8 @@
|
||||
<gf-portfolio-performance
|
||||
class="pb-4"
|
||||
[baseCurrency]="user?.settings?.baseCurrency"
|
||||
[deviceType]="deviceType"
|
||||
[hasError]="hasError"
|
||||
[isAllTimeHigh]="isAllTimeHigh"
|
||||
[isAllTimeLow]="isAllTimeLow"
|
||||
[isLoading]="isLoadingPerformance"
|
||||
|
@ -1,12 +1,15 @@
|
||||
<div class="container p-0">
|
||||
<div
|
||||
class="no-gutters row"
|
||||
[ngClass]="{
|
||||
'text-danger': isAllTimeLow,
|
||||
'text-success': isAllTimeHigh
|
||||
}"
|
||||
>
|
||||
<div class="flex-grow-1"></div>
|
||||
<div class="no-gutters row">
|
||||
<div
|
||||
class="flex-grow-1 status text-muted text-right"
|
||||
[title]="
|
||||
hasError
|
||||
? 'Sorry! Our data provider partner is experiencing the hiccups.'
|
||||
: ''
|
||||
"
|
||||
>
|
||||
<ion-icon *ngIf="hasError" name="alert-circle-outline"></ion-icon>
|
||||
</div>
|
||||
<div *ngIf="isLoading" class="align-items-center d-flex">
|
||||
<ngx-skeleton-loader
|
||||
animation="pulse"
|
||||
@ -20,6 +23,10 @@
|
||||
<div
|
||||
class="display-4 font-weight-bold m-0 text-center value-container"
|
||||
[hidden]="isLoading"
|
||||
[ngClass]="{
|
||||
'text-danger': isAllTimeLow,
|
||||
'text-success': isAllTimeHigh
|
||||
}"
|
||||
>
|
||||
<span #value id="value"></span>
|
||||
</div>
|
||||
|
@ -1,6 +1,10 @@
|
||||
:host {
|
||||
display: block;
|
||||
|
||||
.status {
|
||||
font-size: 1.33rem;
|
||||
}
|
||||
|
||||
.value-container {
|
||||
#value {
|
||||
font-variant-numeric: tabular-nums;
|
||||
|
@ -19,6 +19,8 @@ import { isNumber } from 'lodash';
|
||||
})
|
||||
export class PortfolioPerformanceComponent implements OnChanges, OnInit {
|
||||
@Input() baseCurrency: string;
|
||||
@Input() deviceType: string;
|
||||
@Input() hasError: boolean;
|
||||
@Input() isAllTimeHigh: boolean;
|
||||
@Input() isAllTimeLow: boolean;
|
||||
@Input() isLoading: boolean;
|
||||
@ -44,7 +46,11 @@ export class PortfolioPerformanceComponent implements OnChanges, OnInit {
|
||||
this.unit = this.baseCurrency;
|
||||
|
||||
new CountUp('value', this.performance?.currentValue, {
|
||||
decimalPlaces: 2,
|
||||
decimalPlaces:
|
||||
this.deviceType === 'mobile' &&
|
||||
this.performance?.currentValue >= 100000
|
||||
? 0
|
||||
: 2,
|
||||
duration: 1,
|
||||
separator: `'`
|
||||
}).start();
|
||||
|
@ -4,8 +4,7 @@ import {
|
||||
HttpEvent,
|
||||
HttpHandler,
|
||||
HttpInterceptor,
|
||||
HttpRequest,
|
||||
HttpResponse
|
||||
HttpRequest
|
||||
} from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import {
|
||||
@ -43,26 +42,6 @@ export class HttpResponseInterceptor implements HttpInterceptor {
|
||||
): Observable<HttpEvent<any>> {
|
||||
return next.handle(request).pipe(
|
||||
tap((event: HttpEvent<any>) => {
|
||||
if (event instanceof HttpResponse) {
|
||||
if (event.status === StatusCodes.ACCEPTED) {
|
||||
if (!this.snackBarRef) {
|
||||
this.snackBarRef = this.snackBar.open(
|
||||
'Sorry! Our data provider partner is experiencing a mild case of the hiccups ;(',
|
||||
'Try again?',
|
||||
{ duration: 6000 }
|
||||
);
|
||||
|
||||
this.snackBarRef.afterDismissed().subscribe(() => {
|
||||
this.snackBarRef = undefined;
|
||||
});
|
||||
|
||||
this.snackBarRef.onAction().subscribe(() => {
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return event;
|
||||
}),
|
||||
catchError((error: HttpErrorResponse) => {
|
||||
|
@ -181,7 +181,10 @@ export class DataService {
|
||||
}
|
||||
|
||||
public fetchPortfolioPerformance(aParams: { [param: string]: any }) {
|
||||
return this.http.get<PortfolioPerformance>('/api/portfolio/performance', {
|
||||
return this.http.get<{
|
||||
hasErrors: boolean;
|
||||
performance: PortfolioPerformance;
|
||||
}>('/api/portfolio/performance', {
|
||||
params: aParams
|
||||
});
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { HistoricalDataItem } from '@ghostfolio/api/app/portfolio/interfaces/portfolio-position-detail.interface';
|
||||
|
||||
export interface PortfolioChart {
|
||||
hasError: boolean;
|
||||
isAllTimeHigh: boolean;
|
||||
isAllTimeLow: boolean;
|
||||
chart: HistoricalDataItem[];
|
||||
|
@ -94,7 +94,7 @@
|
||||
"cryptocurrencies": "7.0.0",
|
||||
"date-fns": "2.22.1",
|
||||
"envalid": "7.2.1",
|
||||
"http-status-codes": "2.1.4",
|
||||
"http-status-codes": "2.2.0",
|
||||
"ionicons": "5.5.1",
|
||||
"lodash": "4.17.21",
|
||||
"ngx-device-detector": "3.0.0",
|
||||
|
@ -10032,10 +10032,10 @@ http-signature@~1.2.0:
|
||||
jsprim "^1.2.2"
|
||||
sshpk "^1.7.0"
|
||||
|
||||
http-status-codes@2.1.4:
|
||||
version "2.1.4"
|
||||
resolved "https://registry.yarnpkg.com/http-status-codes/-/http-status-codes-2.1.4.tgz#453d99b4bd9424254c4f6a9a3a03715923052798"
|
||||
integrity sha512-MZVIsLKGVOVE1KEnldppe6Ij+vmemMuApDfjhVSLzyYP+td0bREEYyAoIw9yFePoBXManCuBqmiNP5FqJS5Xkg==
|
||||
http-status-codes@2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/http-status-codes/-/http-status-codes-2.2.0.tgz#bb2efe63d941dfc2be18e15f703da525169622be"
|
||||
integrity sha512-feERVo9iWxvnejp3SEfm/+oNG517npqL2/PIA8ORjyOZjGC7TwCRQsZylciLS64i6pJ0wRYz3rkXLRwbtFa8Ng==
|
||||
|
||||
https-browserify@^1.0.0:
|
||||
version "1.0.0"
|
||||
|
Loading…
x
Reference in New Issue
Block a user