Feature/restructure portfolio page (#1429)
* Restructure portfolio page * Update changelogpull/1431/head
parent
3b4da72ea3
commit
43426c9b01
@ -1,110 +1,15 @@
|
|||||||
<div class="container">
|
<router-outlet></router-outlet>
|
||||||
<h3 class="d-flex justify-content-center mb-3" i18n>Portfolio</h3>
|
|
||||||
<div class="row">
|
<nav mat-align-tabs="center" mat-tab-nav-bar>
|
||||||
<div class="col-xs-12 col-md-6 mb-3">
|
<a
|
||||||
<mat-card class="d-flex flex-column h-100">
|
#rla="routerLinkActive"
|
||||||
<h4 i18n>Holdings</h4>
|
*ngFor="let tab of tabs"
|
||||||
<div class="flex-grow-1" i18n>
|
class="px-3"
|
||||||
Get an overview of your current holdings.
|
mat-tab-link
|
||||||
</div>
|
routerLinkActive
|
||||||
<div class="mt-2 text-right">
|
[active]="rla.isActive"
|
||||||
<a
|
[routerLink]="tab.path"
|
||||||
color="primary"
|
>
|
||||||
mat-button
|
<ion-icon size="large" [name]="tab.iconName"></ion-icon>
|
||||||
[routerLink]="['/portfolio', 'holdings']"
|
</a>
|
||||||
>
|
</nav>
|
||||||
<span i18n>Open Holdings</span>
|
|
||||||
<ion-icon class="ml-1" name="arrow-forward-outline"></ion-icon>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</mat-card>
|
|
||||||
</div>
|
|
||||||
<div class="col-xs-12 col-md-6 mb-3">
|
|
||||||
<mat-card class="d-flex flex-column h-100">
|
|
||||||
<h4 i18n>Activities</h4>
|
|
||||||
<div class="flex-grow-1" i18n>
|
|
||||||
Manage your activities: stocks, ETFs, cryptocurrencies, dividend, and
|
|
||||||
valuables.
|
|
||||||
</div>
|
|
||||||
<div class="mt-2 text-right">
|
|
||||||
<a
|
|
||||||
color="primary"
|
|
||||||
mat-button
|
|
||||||
[routerLink]="['/portfolio', 'activities']"
|
|
||||||
>
|
|
||||||
<span i18n>Open Activities</span>
|
|
||||||
<ion-icon class="ml-1" name="arrow-forward-outline"></ion-icon>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</mat-card>
|
|
||||||
</div>
|
|
||||||
<div class="col-xs-12 col-md-6 mb-3">
|
|
||||||
<mat-card class="d-flex flex-column h-100">
|
|
||||||
<h4 i18n>Allocations</h4>
|
|
||||||
<div class="flex-grow-1" i18n>
|
|
||||||
Check the allocations of your portfolio by account, asset class,
|
|
||||||
currency, sector and region.
|
|
||||||
</div>
|
|
||||||
<div class="mt-2 text-right">
|
|
||||||
<a
|
|
||||||
color="primary"
|
|
||||||
mat-button
|
|
||||||
[routerLink]="['/portfolio', 'allocations']"
|
|
||||||
>
|
|
||||||
<span i18n>Open Allocations</span>
|
|
||||||
<ion-icon class="ml-1" name="arrow-forward-outline"></ion-icon>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</mat-card>
|
|
||||||
</div>
|
|
||||||
<div class="col-xs-12 col-md-6 mb-3">
|
|
||||||
<mat-card class="d-flex flex-column h-100">
|
|
||||||
<h4 i18n>Analysis</h4>
|
|
||||||
<div class="flex-grow-1" i18n>
|
|
||||||
Ghostfolio Analysis visualizes your portfolio and shows your top and
|
|
||||||
bottom performers.
|
|
||||||
</div>
|
|
||||||
<div class="mt-2 text-right">
|
|
||||||
<a
|
|
||||||
color="primary"
|
|
||||||
mat-button
|
|
||||||
[routerLink]="['/portfolio', 'analysis']"
|
|
||||||
>
|
|
||||||
<span i18n>Open Analysis</span>
|
|
||||||
<ion-icon class="ml-1" name="arrow-forward-outline"></ion-icon>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</mat-card>
|
|
||||||
</div>
|
|
||||||
<div class="col-xs-12 col-md-6 mb-3">
|
|
||||||
<mat-card class="d-flex flex-column h-100">
|
|
||||||
<h4>X-ray</h4>
|
|
||||||
<div class="flex-grow-1" i18n>
|
|
||||||
Ghostfolio X-ray uses static analysis to identify potential issues and
|
|
||||||
risks in your portfolio.
|
|
||||||
</div>
|
|
||||||
<div class="mt-2 text-right">
|
|
||||||
<a color="primary" mat-button [routerLink]="['/portfolio', 'report']">
|
|
||||||
<span i18n>Open X-ray</span>
|
|
||||||
<ion-icon class="ml-1" name="arrow-forward-outline"></ion-icon>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</mat-card>
|
|
||||||
</div>
|
|
||||||
<div class="col-xs-12 col-md-6 mb-3">
|
|
||||||
<mat-card class="d-flex flex-column h-100">
|
|
||||||
<h4>FIRE</h4>
|
|
||||||
<div class="flex-grow-1" i18n>
|
|
||||||
Ghostfolio FIRE calculates metrics for the
|
|
||||||
<i>Financial Independence, Retire Early</i> lifestyle.
|
|
||||||
</div>
|
|
||||||
<div class="mt-2 text-right">
|
|
||||||
<a color="primary" mat-button [routerLink]="['/portfolio', 'fire']">
|
|
||||||
<span i18n>Open FIRE</span>
|
|
||||||
<ion-icon class="ml-1" name="arrow-forward-outline"></ion-icon>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</mat-card>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
import { NgModule } from '@angular/core';
|
|
||||||
import { RouterModule, Routes } from '@angular/router';
|
|
||||||
import { AuthGuard } from '@ghostfolio/client/core/auth.guard';
|
|
||||||
|
|
||||||
import { ReportPageComponent } from './report-page.component';
|
|
||||||
|
|
||||||
const routes: Routes = [
|
|
||||||
{
|
|
||||||
canActivate: [AuthGuard],
|
|
||||||
component: ReportPageComponent,
|
|
||||||
path: '',
|
|
||||||
title: 'X-ray'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
imports: [RouterModule.forChild(routes)],
|
|
||||||
exports: [RouterModule]
|
|
||||||
})
|
|
||||||
export class ReportPageRoutingModule {}
|
|
@ -1,64 +0,0 @@
|
|||||||
import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
|
|
||||||
import { DataService } from '@ghostfolio/client/services/data.service';
|
|
||||||
import { UserService } from '@ghostfolio/client/services/user/user.service';
|
|
||||||
import { PortfolioReportRule, User } from '@ghostfolio/common/interfaces';
|
|
||||||
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
|
|
||||||
import { Subject } from 'rxjs';
|
|
||||||
import { takeUntil } from 'rxjs/operators';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
host: { class: 'page' },
|
|
||||||
selector: 'gf-report-page',
|
|
||||||
styleUrls: ['./report-page.scss'],
|
|
||||||
templateUrl: './report-page.html'
|
|
||||||
})
|
|
||||||
export class ReportPageComponent implements OnDestroy, OnInit {
|
|
||||||
public accountClusterRiskRules: PortfolioReportRule[];
|
|
||||||
public currencyClusterRiskRules: PortfolioReportRule[];
|
|
||||||
public feeRules: PortfolioReportRule[];
|
|
||||||
public hasPermissionToCreateOrder: boolean;
|
|
||||||
public user: User;
|
|
||||||
|
|
||||||
private unsubscribeSubject = new Subject<void>();
|
|
||||||
|
|
||||||
public constructor(
|
|
||||||
private changeDetectorRef: ChangeDetectorRef,
|
|
||||||
private dataService: DataService,
|
|
||||||
private userService: UserService
|
|
||||||
) {}
|
|
||||||
|
|
||||||
public ngOnInit() {
|
|
||||||
this.dataService
|
|
||||||
.fetchPortfolioReport()
|
|
||||||
.pipe(takeUntil(this.unsubscribeSubject))
|
|
||||||
.subscribe((portfolioReport) => {
|
|
||||||
this.accountClusterRiskRules =
|
|
||||||
portfolioReport.rules['accountClusterRisk'] || null;
|
|
||||||
this.currencyClusterRiskRules =
|
|
||||||
portfolioReport.rules['currencyClusterRisk'] || null;
|
|
||||||
this.feeRules = portfolioReport.rules['fees'] || null;
|
|
||||||
|
|
||||||
this.changeDetectorRef.markForCheck();
|
|
||||||
});
|
|
||||||
|
|
||||||
this.userService.stateChanged
|
|
||||||
.pipe(takeUntil(this.unsubscribeSubject))
|
|
||||||
.subscribe((state) => {
|
|
||||||
if (state?.user) {
|
|
||||||
this.user = state.user;
|
|
||||||
|
|
||||||
this.hasPermissionToCreateOrder = hasPermission(
|
|
||||||
this.user.permissions,
|
|
||||||
permissions.createOrder
|
|
||||||
);
|
|
||||||
|
|
||||||
this.changeDetectorRef.markForCheck();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public ngOnDestroy() {
|
|
||||||
this.unsubscribeSubject.next();
|
|
||||||
this.unsubscribeSubject.complete();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,57 +0,0 @@
|
|||||||
<div class="container">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col">
|
|
||||||
<h3 class="align-items-center d-flex justify-content-center mb-3">
|
|
||||||
X-ray
|
|
||||||
</h3>
|
|
||||||
<p class="mb-4">
|
|
||||||
Ghostfolio X-ray uses static analysis to identify potential issues and
|
|
||||||
risks in your portfolio.
|
|
||||||
<span class="d-none"
|
|
||||||
>It will be highly configurable in the future: activate / deactivate
|
|
||||||
rules and customize the thresholds to match your personal investment
|
|
||||||
style.</span
|
|
||||||
>
|
|
||||||
</p>
|
|
||||||
<div class="mb-4">
|
|
||||||
<h4 class="align-items-center d-flex m-0">
|
|
||||||
<span>Currency Cluster Risks</span
|
|
||||||
><gf-premium-indicator
|
|
||||||
*ngIf="user?.subscription?.type === 'Basic'"
|
|
||||||
class="ml-1"
|
|
||||||
></gf-premium-indicator>
|
|
||||||
</h4>
|
|
||||||
<gf-rules
|
|
||||||
[hasPermissionToCreateOrder]="hasPermissionToCreateOrder"
|
|
||||||
[rules]="currencyClusterRiskRules"
|
|
||||||
></gf-rules>
|
|
||||||
</div>
|
|
||||||
<div class="mb-4">
|
|
||||||
<h4 class="align-items-center d-flex m-0">
|
|
||||||
<span>Account Cluster Risks</span
|
|
||||||
><gf-premium-indicator
|
|
||||||
*ngIf="user?.subscription?.type === 'Basic'"
|
|
||||||
class="ml-1"
|
|
||||||
></gf-premium-indicator>
|
|
||||||
</h4>
|
|
||||||
<gf-rules
|
|
||||||
[hasPermissionToCreateOrder]="hasPermissionToCreateOrder"
|
|
||||||
[rules]="accountClusterRiskRules"
|
|
||||||
></gf-rules>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<h4 class="align-items-center d-flex m-0">
|
|
||||||
<span>Fees</span
|
|
||||||
><gf-premium-indicator
|
|
||||||
*ngIf="user?.subscription?.type === 'Basic'"
|
|
||||||
class="ml-1"
|
|
||||||
></gf-premium-indicator>
|
|
||||||
</h4>
|
|
||||||
<gf-rules
|
|
||||||
[hasPermissionToCreateOrder]="hasPermissionToCreateOrder"
|
|
||||||
[rules]="feeRules"
|
|
||||||
></gf-rules>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
@ -1,19 +0,0 @@
|
|||||||
import { CommonModule } from '@angular/common';
|
|
||||||
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
|
||||||
import { RulesModule } from '@ghostfolio/client/components/rules/rules.module';
|
|
||||||
import { GfPremiumIndicatorModule } from '@ghostfolio/ui/premium-indicator';
|
|
||||||
|
|
||||||
import { ReportPageRoutingModule } from './report-page-routing.module';
|
|
||||||
import { ReportPageComponent } from './report-page.component';
|
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
declarations: [ReportPageComponent],
|
|
||||||
imports: [
|
|
||||||
CommonModule,
|
|
||||||
GfPremiumIndicatorModule,
|
|
||||||
ReportPageRoutingModule,
|
|
||||||
RulesModule
|
|
||||||
],
|
|
||||||
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
|
||||||
})
|
|
||||||
export class ReportPageModule {}
|
|
@ -1,8 +0,0 @@
|
|||||||
:host {
|
|
||||||
color: rgb(var(--dark-primary-text));
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
:host-context(.is-dark-theme) {
|
|
||||||
color: rgb(var(--light-primary-text));
|
|
||||||
}
|
|
Loading…
Reference in new issue