Feature/add date range selector to holdings tab (#595)
* Add date range selector to holdings tab * Update changelog
This commit is contained in:
parent
438484879d
commit
77065dac50
@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Added the date range component to the holdings tab
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Fixed the creation of historical data in the admin control panel (upsert instead of update)
|
- Fixed the creation of historical data in the admin control panel (upsert instead of update)
|
||||||
|
@ -8,6 +8,7 @@ import {
|
|||||||
SettingsStorageService
|
SettingsStorageService
|
||||||
} from '@ghostfolio/client/services/settings-storage.service';
|
} from '@ghostfolio/client/services/settings-storage.service';
|
||||||
import { UserService } from '@ghostfolio/client/services/user/user.service';
|
import { UserService } from '@ghostfolio/client/services/user/user.service';
|
||||||
|
import { defaultDateRangeOptions } from '@ghostfolio/common/config';
|
||||||
import { Position, User } from '@ghostfolio/common/interfaces';
|
import { Position, User } from '@ghostfolio/common/interfaces';
|
||||||
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
|
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
|
||||||
import { DateRange } from '@ghostfolio/common/types';
|
import { DateRange } from '@ghostfolio/common/types';
|
||||||
@ -22,6 +23,7 @@ import { takeUntil } from 'rxjs/operators';
|
|||||||
})
|
})
|
||||||
export class HomeHoldingsComponent implements OnDestroy, OnInit {
|
export class HomeHoldingsComponent implements OnDestroy, OnInit {
|
||||||
public dateRange: DateRange;
|
public dateRange: DateRange;
|
||||||
|
public dateRangeOptions = defaultDateRangeOptions;
|
||||||
public deviceType: string;
|
public deviceType: string;
|
||||||
public hasPermissionToCreateOrder: boolean;
|
public hasPermissionToCreateOrder: boolean;
|
||||||
public positions: Position[];
|
public positions: Position[];
|
||||||
@ -78,6 +80,12 @@ export class HomeHoldingsComponent implements OnDestroy, OnInit {
|
|||||||
this.update();
|
this.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public onChangeDateRange(aDateRange: DateRange) {
|
||||||
|
this.dateRange = aDateRange;
|
||||||
|
this.settingsStorageService.setSetting(RANGE, this.dateRange);
|
||||||
|
this.update();
|
||||||
|
}
|
||||||
|
|
||||||
public ngOnDestroy() {
|
public ngOnDestroy() {
|
||||||
this.unsubscribeSubject.next();
|
this.unsubscribeSubject.next();
|
||||||
this.unsubscribeSubject.complete();
|
this.unsubscribeSubject.complete();
|
||||||
@ -105,6 +113,8 @@ export class HomeHoldingsComponent implements OnDestroy, OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private update() {
|
private update() {
|
||||||
|
this.positions = undefined;
|
||||||
|
|
||||||
this.dataService
|
this.dataService
|
||||||
.fetchPositions({ range: this.dateRange })
|
.fetchPositions({ range: this.dateRange })
|
||||||
.pipe(takeUntil(this.unsubscribeSubject))
|
.pipe(takeUntil(this.unsubscribeSubject))
|
||||||
|
@ -1,4 +1,12 @@
|
|||||||
<div class="container justify-content-center pb-3 px-3">
|
<div class="container justify-content-center p-3">
|
||||||
|
<div class="mb-3 text-center">
|
||||||
|
<gf-toggle
|
||||||
|
[defaultValue]="dateRange"
|
||||||
|
[isLoading]="positions === undefined"
|
||||||
|
[options]="dateRangeOptions"
|
||||||
|
(change)="onChangeDateRange($event.value)"
|
||||||
|
></gf-toggle>
|
||||||
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="align-items-center col-xs-12 col-md-8 offset-md-2">
|
<div class="align-items-center col-xs-12 col-md-8 offset-md-2">
|
||||||
<mat-card class="p-0">
|
<mat-card class="p-0">
|
||||||
|
@ -5,6 +5,7 @@ import { MatCardModule } from '@angular/material/card';
|
|||||||
import { RouterModule } from '@angular/router';
|
import { RouterModule } from '@angular/router';
|
||||||
import { GfPositionDetailDialogModule } from '@ghostfolio/client/components/position/position-detail-dialog/position-detail-dialog.module';
|
import { GfPositionDetailDialogModule } from '@ghostfolio/client/components/position/position-detail-dialog/position-detail-dialog.module';
|
||||||
import { GfPositionsModule } from '@ghostfolio/client/components/positions/positions.module';
|
import { GfPositionsModule } from '@ghostfolio/client/components/positions/positions.module';
|
||||||
|
import { GfToggleModule } from '@ghostfolio/client/components/toggle/toggle.module';
|
||||||
|
|
||||||
import { HomeHoldingsComponent } from './home-holdings.component';
|
import { HomeHoldingsComponent } from './home-holdings.component';
|
||||||
|
|
||||||
@ -15,6 +16,7 @@ import { HomeHoldingsComponent } from './home-holdings.component';
|
|||||||
CommonModule,
|
CommonModule,
|
||||||
GfPositionDetailDialogModule,
|
GfPositionDetailDialogModule,
|
||||||
GfPositionsModule,
|
GfPositionsModule,
|
||||||
|
GfToggleModule,
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
MatCardModule,
|
MatCardModule,
|
||||||
RouterModule
|
RouterModule
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
|
import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { ToggleOption } from '@ghostfolio/client/components/toggle/interfaces/toggle-option.type';
|
|
||||||
import { DataService } from '@ghostfolio/client/services/data.service';
|
import { DataService } from '@ghostfolio/client/services/data.service';
|
||||||
import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service';
|
import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service';
|
||||||
import {
|
import {
|
||||||
@ -7,6 +6,7 @@ import {
|
|||||||
SettingsStorageService
|
SettingsStorageService
|
||||||
} from '@ghostfolio/client/services/settings-storage.service';
|
} from '@ghostfolio/client/services/settings-storage.service';
|
||||||
import { UserService } from '@ghostfolio/client/services/user/user.service';
|
import { UserService } from '@ghostfolio/client/services/user/user.service';
|
||||||
|
import { defaultDateRangeOptions } from '@ghostfolio/common/config';
|
||||||
import { PortfolioPerformance, User } from '@ghostfolio/common/interfaces';
|
import { PortfolioPerformance, User } from '@ghostfolio/common/interfaces';
|
||||||
import { DateRange } from '@ghostfolio/common/types';
|
import { DateRange } from '@ghostfolio/common/types';
|
||||||
import { LineChartItem } from '@ghostfolio/ui/line-chart/interfaces/line-chart.interface';
|
import { LineChartItem } from '@ghostfolio/ui/line-chart/interfaces/line-chart.interface';
|
||||||
@ -21,13 +21,7 @@ import { takeUntil } from 'rxjs/operators';
|
|||||||
})
|
})
|
||||||
export class HomeOverviewComponent implements OnDestroy, OnInit {
|
export class HomeOverviewComponent implements OnDestroy, OnInit {
|
||||||
public dateRange: DateRange;
|
public dateRange: DateRange;
|
||||||
public dateRangeOptions: ToggleOption[] = [
|
public dateRangeOptions = defaultDateRangeOptions;
|
||||||
{ label: 'Today', value: '1d' },
|
|
||||||
{ label: 'YTD', value: 'ytd' },
|
|
||||||
{ label: '1Y', value: '1y' },
|
|
||||||
{ label: '5Y', value: '5y' },
|
|
||||||
{ label: 'Max', value: 'max' }
|
|
||||||
];
|
|
||||||
public deviceType: string;
|
public deviceType: string;
|
||||||
public hasError: boolean;
|
public hasError: boolean;
|
||||||
public hasImpersonationId: boolean;
|
public hasImpersonationId: boolean;
|
||||||
|
@ -8,8 +8,7 @@ import {
|
|||||||
Output
|
Output
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { FormControl } from '@angular/forms';
|
import { FormControl } from '@angular/forms';
|
||||||
|
import { ToggleOption } from '@ghostfolio/common/types';
|
||||||
import { ToggleOption } from './interfaces/toggle-option.type';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'gf-toggle',
|
selector: 'gf-toggle',
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
|
import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { ToggleOption } from '@ghostfolio/client/components/toggle/interfaces/toggle-option.type';
|
|
||||||
import { DataService } from '@ghostfolio/client/services/data.service';
|
import { DataService } from '@ghostfolio/client/services/data.service';
|
||||||
import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service';
|
import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service';
|
||||||
import { UserService } from '@ghostfolio/client/services/user/user.service';
|
import { UserService } from '@ghostfolio/client/services/user/user.service';
|
||||||
@ -10,6 +9,7 @@ import {
|
|||||||
PortfolioPosition,
|
PortfolioPosition,
|
||||||
User
|
User
|
||||||
} from '@ghostfolio/common/interfaces';
|
} from '@ghostfolio/common/interfaces';
|
||||||
|
import { ToggleOption } from '@ghostfolio/common/types';
|
||||||
import { AssetClass } from '@prisma/client';
|
import { AssetClass } from '@prisma/client';
|
||||||
import { DeviceDetectorService } from 'ngx-device-detector';
|
import { DeviceDetectorService } from 'ngx-device-detector';
|
||||||
import { Subject } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
|
import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { ToggleOption } from '@ghostfolio/client/components/toggle/interfaces/toggle-option.type';
|
|
||||||
import { DataService } from '@ghostfolio/client/services/data.service';
|
import { DataService } from '@ghostfolio/client/services/data.service';
|
||||||
import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service';
|
import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service';
|
||||||
import { UserService } from '@ghostfolio/client/services/user/user.service';
|
import { UserService } from '@ghostfolio/client/services/user/user.service';
|
||||||
import { PortfolioPosition, User } from '@ghostfolio/common/interfaces';
|
import { PortfolioPosition, User } from '@ghostfolio/common/interfaces';
|
||||||
import { InvestmentItem } from '@ghostfolio/common/interfaces/investment-item.interface';
|
import { InvestmentItem } from '@ghostfolio/common/interfaces/investment-item.interface';
|
||||||
|
import { ToggleOption } from '@ghostfolio/common/types';
|
||||||
import { DeviceDetectorService } from 'ngx-device-detector';
|
import { DeviceDetectorService } from 'ngx-device-detector';
|
||||||
import { Subject } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
import { takeUntil } from 'rxjs/operators';
|
import { takeUntil } from 'rxjs/operators';
|
||||||
|
@ -1,5 +1,15 @@
|
|||||||
|
import { ToggleOption } from './types';
|
||||||
|
|
||||||
export const baseCurrency = 'USD';
|
export const baseCurrency = 'USD';
|
||||||
|
|
||||||
|
export const defaultDateRangeOptions: ToggleOption[] = [
|
||||||
|
{ label: 'Today', value: '1d' },
|
||||||
|
{ label: 'YTD', value: 'ytd' },
|
||||||
|
{ label: '1Y', value: '1y' },
|
||||||
|
{ label: '5Y', value: '5y' },
|
||||||
|
{ label: 'Max', value: 'max' }
|
||||||
|
];
|
||||||
|
|
||||||
export const ghostfolioScraperApiSymbolPrefix = '_GF_';
|
export const ghostfolioScraperApiSymbolPrefix = '_GF_';
|
||||||
export const ghostfolioCashSymbol = `${ghostfolioScraperApiSymbolPrefix}CASH`;
|
export const ghostfolioCashSymbol = `${ghostfolioScraperApiSymbolPrefix}CASH`;
|
||||||
export const ghostfolioFearAndGreedIndexSymbol = `${ghostfolioScraperApiSymbolPrefix}FEAR_AND_GREED_INDEX`;
|
export const ghostfolioFearAndGreedIndexSymbol = `${ghostfolioScraperApiSymbolPrefix}FEAR_AND_GREED_INDEX`;
|
||||||
|
@ -4,6 +4,7 @@ import type { DateRange } from './date-range.type';
|
|||||||
import type { Granularity } from './granularity.type';
|
import type { Granularity } from './granularity.type';
|
||||||
import type { OrderWithAccount } from './order-with-account.type';
|
import type { OrderWithAccount } from './order-with-account.type';
|
||||||
import type { RequestWithUser } from './request-with-user.type';
|
import type { RequestWithUser } from './request-with-user.type';
|
||||||
|
import { ToggleOption } from './toggle-option.type';
|
||||||
|
|
||||||
export type {
|
export type {
|
||||||
AccessWithGranteeUser,
|
AccessWithGranteeUser,
|
||||||
@ -11,5 +12,6 @@ export type {
|
|||||||
DateRange,
|
DateRange,
|
||||||
Granularity,
|
Granularity,
|
||||||
OrderWithAccount,
|
OrderWithAccount,
|
||||||
RequestWithUser
|
RequestWithUser,
|
||||||
|
ToggleOption
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user