|
|
@ -4,6 +4,7 @@ import { |
|
|
} from '@ghostfolio/common/config'; |
|
|
} from '@ghostfolio/common/config'; |
|
|
import { DATE_FORMAT } from '@ghostfolio/common/helper'; |
|
|
import { DATE_FORMAT } from '@ghostfolio/common/helper'; |
|
|
import { |
|
|
import { |
|
|
|
|
|
AiServiceHealthResponse, |
|
|
DataProviderGhostfolioAssetProfileResponse, |
|
|
DataProviderGhostfolioAssetProfileResponse, |
|
|
DataProviderGhostfolioStatusResponse, |
|
|
DataProviderGhostfolioStatusResponse, |
|
|
DividendsResponse, |
|
|
DividendsResponse, |
|
|
@ -13,27 +14,41 @@ import { |
|
|
} from '@ghostfolio/common/interfaces'; |
|
|
} from '@ghostfolio/common/interfaces'; |
|
|
|
|
|
|
|
|
import { CommonModule } from '@angular/common'; |
|
|
import { CommonModule } from '@angular/common'; |
|
|
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'; |
|
|
import { |
|
|
|
|
|
HttpClient, |
|
|
|
|
|
HttpErrorResponse, |
|
|
|
|
|
HttpHeaders, |
|
|
|
|
|
HttpParams |
|
|
|
|
|
} from '@angular/common/http'; |
|
|
import { Component, DestroyRef, OnInit } from '@angular/core'; |
|
|
import { Component, DestroyRef, OnInit } from '@angular/core'; |
|
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; |
|
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; |
|
|
|
|
|
import { MatCardModule } from '@angular/material/card'; |
|
|
import { format, startOfYear } from 'date-fns'; |
|
|
import { format, startOfYear } from 'date-fns'; |
|
|
import { map, Observable } from 'rxjs'; |
|
|
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; |
|
|
|
|
|
import { catchError, map, Observable, of, OperatorFunction } from 'rxjs'; |
|
|
|
|
|
|
|
|
|
|
|
import { FetchFailure, FetchResult } from './interfaces/interfaces'; |
|
|
|
|
|
|
|
|
@Component({ |
|
|
@Component({ |
|
|
host: { class: 'page' }, |
|
|
host: { class: 'page' }, |
|
|
imports: [CommonModule], |
|
|
imports: [CommonModule, MatCardModule, NgxSkeletonLoaderModule], |
|
|
selector: 'gf-api-page', |
|
|
selector: 'gf-api-page', |
|
|
styleUrls: ['./api-page.scss'], |
|
|
styleUrls: ['./api-page.scss'], |
|
|
templateUrl: './api-page.html' |
|
|
templateUrl: './api-page.html' |
|
|
}) |
|
|
}) |
|
|
export class GfApiPageComponent implements OnInit { |
|
|
export class GfApiPageComponent implements OnInit { |
|
|
public assetProfile$: Observable<DataProviderGhostfolioAssetProfileResponse>; |
|
|
public aiServiceHealth$: Observable<FetchResult<AiServiceHealthResponse>>; |
|
|
public dividends$: Observable<DividendsResponse['dividends']>; |
|
|
public assetProfile$: Observable< |
|
|
public historicalData$: Observable<HistoricalResponse['historicalData']>; |
|
|
FetchResult<DataProviderGhostfolioAssetProfileResponse> |
|
|
public isinLookupItems$: Observable<LookupResponse['items']>; |
|
|
>; |
|
|
public lookupItems$: Observable<LookupResponse['items']>; |
|
|
public dividends$: Observable<FetchResult<DividendsResponse['dividends']>>; |
|
|
public quotes$: Observable<QuotesResponse['quotes']>; |
|
|
public historicalData$: Observable< |
|
|
public status$: Observable<DataProviderGhostfolioStatusResponse>; |
|
|
FetchResult<HistoricalResponse['historicalData']> |
|
|
|
|
|
>; |
|
|
|
|
|
public isinLookupItems$: Observable<FetchResult<LookupResponse['items']>>; |
|
|
|
|
|
public lookupItems$: Observable<FetchResult<LookupResponse['items']>>; |
|
|
|
|
|
public quotes$: Observable<FetchResult<QuotesResponse['quotes']>>; |
|
|
|
|
|
public status$: Observable<FetchResult<DataProviderGhostfolioStatusResponse>>; |
|
|
|
|
|
|
|
|
private apiKey: string; |
|
|
private apiKey: string; |
|
|
|
|
|
|
|
|
@ -45,6 +60,7 @@ export class GfApiPageComponent implements OnInit { |
|
|
public ngOnInit() { |
|
|
public ngOnInit() { |
|
|
this.apiKey = prompt($localize`Please enter your Ghostfolio API key:`); |
|
|
this.apiKey = prompt($localize`Please enter your Ghostfolio API key:`); |
|
|
|
|
|
|
|
|
|
|
|
this.aiServiceHealth$ = this.fetchAiServiceHealth(); |
|
|
this.assetProfile$ = this.fetchAssetProfile({ symbol: 'AAPL' }); |
|
|
this.assetProfile$ = this.fetchAssetProfile({ symbol: 'AAPL' }); |
|
|
this.dividends$ = this.fetchDividends({ symbol: 'KO' }); |
|
|
this.dividends$ = this.fetchDividends({ symbol: 'KO' }); |
|
|
this.historicalData$ = this.fetchHistoricalData({ symbol: 'AAPL' }); |
|
|
this.historicalData$ = this.fetchHistoricalData({ symbol: 'AAPL' }); |
|
|
@ -54,13 +70,31 @@ export class GfApiPageComponent implements OnInit { |
|
|
this.status$ = this.fetchStatus(); |
|
|
this.status$ = this.fetchStatus(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public isFetchFailure(value: unknown): value is FetchFailure { |
|
|
|
|
|
return typeof value === 'object' && value !== null && 'fetchError' in value; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private catchFetchFailure<T>(): OperatorFunction<T, T | FetchFailure> { |
|
|
|
|
|
return catchError(({ error }: HttpErrorResponse) => { |
|
|
|
|
|
const body = error as { status?: string }; |
|
|
|
|
|
|
|
|
|
|
|
return of<FetchFailure>({ fetchError: body?.status ?? 'Error' }); |
|
|
|
|
|
}) as OperatorFunction<T, T | FetchFailure>; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private fetchAiServiceHealth() { |
|
|
|
|
|
return this.http |
|
|
|
|
|
.get<AiServiceHealthResponse>('/api/v1/health/ai') |
|
|
|
|
|
.pipe(this.catchFetchFailure(), takeUntilDestroyed(this.destroyRef)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
private fetchAssetProfile({ symbol }: { symbol: string }) { |
|
|
private fetchAssetProfile({ symbol }: { symbol: string }) { |
|
|
return this.http |
|
|
return this.http |
|
|
.get<DataProviderGhostfolioAssetProfileResponse>( |
|
|
.get<DataProviderGhostfolioAssetProfileResponse>( |
|
|
`/api/v1/data-providers/ghostfolio/asset-profile/${symbol}`, |
|
|
`/api/v1/data-providers/ghostfolio/asset-profile/${symbol}`, |
|
|
{ headers: this.getHeaders() } |
|
|
{ headers: this.getHeaders() } |
|
|
) |
|
|
) |
|
|
.pipe(takeUntilDestroyed(this.destroyRef)); |
|
|
.pipe(this.catchFetchFailure(), takeUntilDestroyed(this.destroyRef)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private fetchDividends({ symbol }: { symbol: string }) { |
|
|
private fetchDividends({ symbol }: { symbol: string }) { |
|
|
@ -80,6 +114,7 @@ export class GfApiPageComponent implements OnInit { |
|
|
map(({ dividends }) => { |
|
|
map(({ dividends }) => { |
|
|
return dividends; |
|
|
return dividends; |
|
|
}), |
|
|
}), |
|
|
|
|
|
this.catchFetchFailure(), |
|
|
takeUntilDestroyed(this.destroyRef) |
|
|
takeUntilDestroyed(this.destroyRef) |
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|
@ -101,6 +136,7 @@ export class GfApiPageComponent implements OnInit { |
|
|
map(({ historicalData }) => { |
|
|
map(({ historicalData }) => { |
|
|
return historicalData; |
|
|
return historicalData; |
|
|
}), |
|
|
}), |
|
|
|
|
|
this.catchFetchFailure(), |
|
|
takeUntilDestroyed(this.destroyRef) |
|
|
takeUntilDestroyed(this.destroyRef) |
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|
@ -127,6 +163,7 @@ export class GfApiPageComponent implements OnInit { |
|
|
map(({ items }) => { |
|
|
map(({ items }) => { |
|
|
return items; |
|
|
return items; |
|
|
}), |
|
|
}), |
|
|
|
|
|
this.catchFetchFailure(), |
|
|
takeUntilDestroyed(this.destroyRef) |
|
|
takeUntilDestroyed(this.destroyRef) |
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|
@ -143,6 +180,7 @@ export class GfApiPageComponent implements OnInit { |
|
|
map(({ quotes }) => { |
|
|
map(({ quotes }) => { |
|
|
return quotes; |
|
|
return quotes; |
|
|
}), |
|
|
}), |
|
|
|
|
|
this.catchFetchFailure(), |
|
|
takeUntilDestroyed(this.destroyRef) |
|
|
takeUntilDestroyed(this.destroyRef) |
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|
@ -153,7 +191,7 @@ export class GfApiPageComponent implements OnInit { |
|
|
'/api/v2/data-providers/ghostfolio/status', |
|
|
'/api/v2/data-providers/ghostfolio/status', |
|
|
{ headers: this.getHeaders() } |
|
|
{ headers: this.getHeaders() } |
|
|
) |
|
|
) |
|
|
.pipe(takeUntilDestroyed(this.destroyRef)); |
|
|
.pipe(this.catchFetchFailure(), takeUntilDestroyed(this.destroyRef)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private getHeaders() { |
|
|
private getHeaders() { |
|
|
|