mirror of https://github.com/ghostfolio/ghostfolio
Browse Source
* Introduce portfolio group, remove tools * Extract allocations to separate page * Update changelogpull/263/head
Thomas
4 years ago
committed by
GitHub
39 changed files with 366 additions and 187 deletions
@ -0,0 +1,15 @@ |
|||
import { NgModule } from '@angular/core'; |
|||
import { RouterModule, Routes } from '@angular/router'; |
|||
import { AuthGuard } from '@ghostfolio/client/core/auth.guard'; |
|||
|
|||
import { AllocationsPageComponent } from './allocations-page.component'; |
|||
|
|||
const routes: Routes = [ |
|||
{ path: '', component: AllocationsPageComponent, canActivate: [AuthGuard] } |
|||
]; |
|||
|
|||
@NgModule({ |
|||
imports: [RouterModule.forChild(routes)], |
|||
exports: [RouterModule] |
|||
}) |
|||
export class AllocationsPageRoutingModule {} |
@ -1,16 +1,4 @@ |
|||
:host { |
|||
.investment-chart { |
|||
.mat-card { |
|||
.mat-card-content { |
|||
aspect-ratio: 16 / 9; |
|||
|
|||
gf-investment-chart { |
|||
height: 100%; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
.proportion-charts { |
|||
.mat-card { |
|||
.mat-card-content { |
@ -0,0 +1,92 @@ |
|||
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 { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service'; |
|||
import { UserService } from '@ghostfolio/client/services/user/user.service'; |
|||
import { PortfolioPosition, User } from '@ghostfolio/common/interfaces'; |
|||
import { InvestmentItem } from '@ghostfolio/common/interfaces/investment-item.interface'; |
|||
import { DeviceDetectorService } from 'ngx-device-detector'; |
|||
import { Subject } from 'rxjs'; |
|||
import { takeUntil } from 'rxjs/operators'; |
|||
|
|||
@Component({ |
|||
selector: 'gf-analysis-page', |
|||
templateUrl: './analysis-page.html', |
|||
styleUrls: ['./analysis-page.scss'] |
|||
}) |
|||
export class AnalysisPageComponent implements OnDestroy, OnInit { |
|||
public accounts: { |
|||
[symbol: string]: Pick<PortfolioPosition, 'name'> & { value: number }; |
|||
}; |
|||
public continents: { |
|||
[code: string]: { name: string; value: number }; |
|||
}; |
|||
public countries: { |
|||
[code: string]: { name: string; value: number }; |
|||
}; |
|||
public deviceType: string; |
|||
public hasImpersonationId: boolean; |
|||
public period = 'current'; |
|||
public periodOptions: ToggleOption[] = [ |
|||
{ label: 'Initial', value: 'original' }, |
|||
{ label: 'Current', value: 'current' } |
|||
]; |
|||
public investments: InvestmentItem[]; |
|||
public portfolioPositions: { [symbol: string]: PortfolioPosition }; |
|||
public positions: { [symbol: string]: any }; |
|||
public sectors: { |
|||
[name: string]: { name: string; value: number }; |
|||
}; |
|||
public user: User; |
|||
|
|||
private unsubscribeSubject = new Subject<void>(); |
|||
|
|||
/** |
|||
* @constructor |
|||
*/ |
|||
public constructor( |
|||
private changeDetectorRef: ChangeDetectorRef, |
|||
private dataService: DataService, |
|||
private deviceService: DeviceDetectorService, |
|||
private impersonationStorageService: ImpersonationStorageService, |
|||
private userService: UserService |
|||
) {} |
|||
|
|||
/** |
|||
* Initializes the controller |
|||
*/ |
|||
public ngOnInit() { |
|||
this.deviceType = this.deviceService.getDeviceInfo().deviceType; |
|||
|
|||
this.impersonationStorageService |
|||
.onChangeHasImpersonation() |
|||
.pipe(takeUntil(this.unsubscribeSubject)) |
|||
.subscribe((aId) => { |
|||
this.hasImpersonationId = !!aId; |
|||
}); |
|||
|
|||
this.dataService |
|||
.fetchInvestments() |
|||
.pipe(takeUntil(this.unsubscribeSubject)) |
|||
.subscribe((response) => { |
|||
this.investments = response; |
|||
|
|||
this.changeDetectorRef.markForCheck(); |
|||
}); |
|||
|
|||
this.userService.stateChanged |
|||
.pipe(takeUntil(this.unsubscribeSubject)) |
|||
.subscribe((state) => { |
|||
if (state?.user) { |
|||
this.user = state.user; |
|||
|
|||
this.changeDetectorRef.markForCheck(); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
public ngOnDestroy() { |
|||
this.unsubscribeSubject.next(); |
|||
this.unsubscribeSubject.complete(); |
|||
} |
|||
} |
@ -0,0 +1,20 @@ |
|||
<div class="container"> |
|||
<div class="investment-chart row"> |
|||
<div class="col-lg"> |
|||
<h3 class="d-flex justify-content-center mb-3" i18n>Analysis</h3> |
|||
<mat-card class="mb-3"> |
|||
<mat-card-header> |
|||
<mat-card-title class="align-items-center d-flex" i18n |
|||
>Timeline</mat-card-title |
|||
> |
|||
</mat-card-header> |
|||
<mat-card-content> |
|||
<gf-investment-chart |
|||
class="h-100" |
|||
[investments]="investments" |
|||
></gf-investment-chart> |
|||
</mat-card-content> |
|||
</mat-card> |
|||
</div> |
|||
</div> |
|||
</div> |
@ -0,0 +1,21 @@ |
|||
import { CommonModule } from '@angular/common'; |
|||
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; |
|||
import { MatCardModule } from '@angular/material/card'; |
|||
import { GfInvestmentChartModule } from '@ghostfolio/client/components/investment-chart/investment-chart.module'; |
|||
|
|||
import { AnalysisPageRoutingModule } from './analysis-page-routing.module'; |
|||
import { AnalysisPageComponent } from './analysis-page.component'; |
|||
|
|||
@NgModule({ |
|||
declarations: [AnalysisPageComponent], |
|||
exports: [], |
|||
imports: [ |
|||
AnalysisPageRoutingModule, |
|||
CommonModule, |
|||
GfInvestmentChartModule, |
|||
MatCardModule |
|||
], |
|||
providers: [], |
|||
schemas: [CUSTOM_ELEMENTS_SCHEMA] |
|||
}) |
|||
export class AnalysisPageModule {} |
@ -0,0 +1,9 @@ |
|||
:host { |
|||
.investment-chart { |
|||
.mat-card { |
|||
.mat-card-content { |
|||
aspect-ratio: 16 / 9; |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,44 @@ |
|||
import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; |
|||
import { UserService } from '@ghostfolio/client/services/user/user.service'; |
|||
import { User } from '@ghostfolio/common/interfaces'; |
|||
import { Subject } from 'rxjs'; |
|||
import { takeUntil } from 'rxjs/operators'; |
|||
|
|||
@Component({ |
|||
selector: 'gf-portfolio-page', |
|||
templateUrl: './portfolio-page.html', |
|||
styleUrls: ['./portfolio-page.scss'] |
|||
}) |
|||
export class PortfolioPageComponent implements OnDestroy, OnInit { |
|||
public user: User; |
|||
|
|||
private unsubscribeSubject = new Subject<void>(); |
|||
|
|||
/** |
|||
* @constructor |
|||
*/ |
|||
public constructor( |
|||
private changeDetectorRef: ChangeDetectorRef, |
|||
private userService: UserService |
|||
) {} |
|||
|
|||
/** |
|||
* Initializes the controller |
|||
*/ |
|||
public ngOnInit() { |
|||
this.userService.stateChanged |
|||
.pipe(takeUntil(this.unsubscribeSubject)) |
|||
.subscribe((state) => { |
|||
if (state?.user) { |
|||
this.user = state.user; |
|||
|
|||
this.changeDetectorRef.markForCheck(); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
public ngOnDestroy() { |
|||
this.unsubscribeSubject.next(); |
|||
this.unsubscribeSubject.complete(); |
|||
} |
|||
} |
@ -0,0 +1,83 @@ |
|||
<div class="container"> |
|||
<h3 class="d-flex justify-content-center mb-3" i18n>Portfolio</h3> |
|||
<div class="row"> |
|||
<div class="col-xs-12 col-md-6"> |
|||
<mat-card class="mb-3"> |
|||
<h4 i18n>Transactions</h4> |
|||
<p class="mb-0">Manage your transactions.</p> |
|||
<p class="text-right"> |
|||
<a |
|||
color="primary" |
|||
i18n |
|||
mat-button |
|||
[routerLink]="['/portfolio', 'transactions']" |
|||
> |
|||
Open Transactions → |
|||
</a> |
|||
</p> |
|||
</mat-card> |
|||
</div> |
|||
<div |
|||
*ngIf="user?.settings?.viewMode === 'DEFAULT'" |
|||
class="col-xs-12 col-md-6" |
|||
> |
|||
<mat-card class="mb-3"> |
|||
<h4 i18n>Allocations</h4> |
|||
<p class="mb-0">Check the allocations of your portfolio.</p> |
|||
<p class="text-right"> |
|||
<a |
|||
color="primary" |
|||
i18n |
|||
mat-button |
|||
[routerLink]="['/portfolio', 'allocations']" |
|||
> |
|||
Open Allocations → |
|||
</a> |
|||
</p> |
|||
</mat-card> |
|||
</div> |
|||
</div> |
|||
<div class="row"> |
|||
<div |
|||
*ngIf="user?.settings?.viewMode === 'DEFAULT'" |
|||
class="col-xs-12 col-md-6" |
|||
> |
|||
<mat-card class="mb-3"> |
|||
<h4 i18n>Analysis</h4> |
|||
<p class="mb-0">Ghostfolio Analysis visualizes your portfolio.</p> |
|||
<p class="text-right"> |
|||
<a |
|||
color="primary" |
|||
i18n |
|||
mat-button |
|||
[routerLink]="['/portfolio', 'analysis']" |
|||
> |
|||
Open Analysis → |
|||
</a> |
|||
</p> |
|||
</mat-card> |
|||
</div> |
|||
<div |
|||
*ngIf="user?.settings?.viewMode === 'DEFAULT'" |
|||
class="col-xs-12 col-md-6" |
|||
> |
|||
<mat-card class="mb-3"> |
|||
<h4 i18n>X-ray</h4> |
|||
<p class="mb-0"> |
|||
Ghostfolio X-ray uses static analysis to identify potential issues and |
|||
risks in your portfolio. |
|||
</p> |
|||
<p class="text-right"> |
|||
<a |
|||
color="primary" |
|||
i18n |
|||
mat-button |
|||
[routerLink]="['/portfolio', 'report']" |
|||
> |
|||
Open X-ray → |
|||
</a> |
|||
</p> |
|||
</mat-card> |
|||
</div> |
|||
</div> |
|||
</div> |
@ -1,21 +0,0 @@ |
|||
import { Component, OnInit } from '@angular/core'; |
|||
import { Subject } from 'rxjs'; |
|||
|
|||
@Component({ |
|||
selector: 'gf-tools-page', |
|||
templateUrl: './tools-page.html', |
|||
styleUrls: ['./tools-page.scss'] |
|||
}) |
|||
export class ToolsPageComponent implements OnInit { |
|||
private unsubscribeSubject = new Subject<void>(); |
|||
|
|||
/** |
|||
* @constructor |
|||
*/ |
|||
public constructor() {} |
|||
|
|||
/** |
|||
* Initializes the controller |
|||
*/ |
|||
public ngOnInit() {} |
|||
} |
@ -1,43 +0,0 @@ |
|||
<div class="container"> |
|||
<h3 class="d-flex justify-content-center mb-3" i18n>Tools</h3> |
|||
<div class="row"> |
|||
<div class="col-xs-12 col-md-6"> |
|||
<mat-card class="mb-3"> |
|||
<h4 i18n>Analysis</h4> |
|||
<p class="mb-0"> |
|||
Ghostfolio Analysis shows your positions and visualizes your |
|||
portfolio. |
|||
</p> |
|||
<p class="text-right"> |
|||
<a |
|||
color="primary" |
|||
i18n |
|||
mat-button |
|||
[routerLink]="['/tools', 'analysis']" |
|||
> |
|||
Open Analysis → |
|||
</a> |
|||
</p> |
|||
</mat-card> |
|||
</div> |
|||
<div class="col-xs-12 col-md-6"> |
|||
<mat-card class="mb-3"> |
|||
<h4 i18n>X-ray</h4> |
|||
<p class="mb-0"> |
|||
Ghostfolio X-ray uses static analysis to identify potential issues and |
|||
risks in your portfolio. |
|||
</p> |
|||
<p class="text-right"> |
|||
<a |
|||
color="primary" |
|||
i18n |
|||
mat-button |
|||
[routerLink]="['/tools', 'report']" |
|||
> |
|||
Open X-ray → |
|||
</a> |
|||
</p> |
|||
</mat-card> |
|||
</div> |
|||
</div> |
|||
</div> |
Loading…
Reference in new issue