Feature/improve allocations by etf holding (#3467)

* Improve allocations by ETF holding

* Update changelog
This commit is contained in:
Thomas Kaul
2024-06-08 11:17:27 +02:00
committed by GitHub
parent fdcf5fd396
commit 23e4d5454d
11 changed files with 161 additions and 88 deletions

View File

@@ -169,7 +169,7 @@
}"
(click)="
!ignoreAssetSubClasses.includes(row.assetSubClass) &&
onOpenPositionDialog({
onOpenHoldingDialog({
dataSource: row.dataSource,
symbol: row.symbol
})
@@ -193,7 +193,7 @@
@if (dataSource.data.length > pageSize && !isLoading) {
<div class="my-3 text-center">
<button mat-stroked-button (click)="onShowAllPositions()">
<button mat-stroked-button (click)="onShowAllHoldings()">
<ng-container i18n>Show all</ng-container>
</button>
</div>

View File

@@ -102,7 +102,7 @@ export class GfHoldingsTableComponent implements OnChanges, OnDestroy, OnInit {
}
}
public onOpenPositionDialog({ dataSource, symbol }: UniqueAsset) {
public onOpenHoldingDialog({ dataSource, symbol }: UniqueAsset) {
if (this.hasPermissionToOpenDetails) {
this.router.navigate([], {
queryParams: { dataSource, symbol, holdingDetailDialog: true }
@@ -110,7 +110,7 @@ export class GfHoldingsTableComponent implements OnChanges, OnDestroy, OnInit {
}
}
public onShowAllPositions() {
public onShowAllHoldings() {
this.pageSize = Number.MAX_SAFE_INTEGER;
setTimeout(() => {

View File

@@ -112,7 +112,7 @@ export class GfPortfolioProportionChartComponent
this.positions[symbol][this.keys[0]].toUpperCase()
].value = chartData[
this.positions[symbol][this.keys[0]].toUpperCase()
].value.plus(this.positions[symbol].value);
].value.plus(this.positions[symbol].value || 0);
if (
chartData[this.positions[symbol][this.keys[0]].toUpperCase()]
@@ -124,20 +124,20 @@ export class GfPortfolioProportionChartComponent
chartData[
this.positions[symbol][this.keys[0]].toUpperCase()
].subCategory[this.positions[symbol][this.keys[1]]].value.plus(
this.positions[symbol].value
this.positions[symbol].value || 0
);
} else {
chartData[
this.positions[symbol][this.keys[0]].toUpperCase()
].subCategory[
this.positions[symbol][this.keys[1]] ?? UNKNOWN_KEY
] = { value: new Big(this.positions[symbol].value) };
] = { value: new Big(this.positions[symbol].value || 0) };
}
} else {
chartData[this.positions[symbol][this.keys[0]].toUpperCase()] = {
name: this.positions[symbol][this.keys[0]],
subCategory: {},
value: new Big(this.positions[symbol].value ?? 0)
value: new Big(this.positions[symbol].value || 0)
};
if (this.positions[symbol][this.keys[1]]) {
@@ -145,7 +145,7 @@ export class GfPortfolioProportionChartComponent
this.positions[symbol][this.keys[0]].toUpperCase()
].subCategory = {
[this.positions[symbol][this.keys[1]]]: {
value: new Big(this.positions[symbol].value)
value: new Big(this.positions[symbol].value || 0)
}
};
}
@@ -153,7 +153,7 @@ export class GfPortfolioProportionChartComponent
} else {
if (chartData[UNKNOWN_KEY]) {
chartData[UNKNOWN_KEY].value = chartData[UNKNOWN_KEY].value.plus(
this.positions[symbol].value
this.positions[symbol].value || 0
);
} else {
chartData[UNKNOWN_KEY] = {
@@ -161,7 +161,7 @@ export class GfPortfolioProportionChartComponent
subCategory: this.keys[1]
? { [this.keys[1]]: { value: new Big(0) } }
: undefined,
value: new Big(this.positions[symbol].value)
value: new Big(this.positions[symbol].value || 0)
};
}
}
@@ -170,7 +170,7 @@ export class GfPortfolioProportionChartComponent
Object.keys(this.positions).forEach((symbol) => {
chartData[symbol] = {
name: this.positions[symbol].name,
value: new Big(this.positions[symbol].value)
value: new Big(this.positions[symbol].value || 0)
};
});
}

View File

@@ -11,7 +11,7 @@
<ng-container i18n>Name</ng-container>
</th>
<td *matCellDef="let element" class="px-2" mat-cell>
{{ element?.name }}
{{ element?.name | titlecase }}
</td>
</ng-container>
@@ -59,3 +59,30 @@
<tr *matHeaderRowDef="displayedColumns" mat-header-row></tr>
<tr *matRowDef="let row; columns: displayedColumns" mat-row></tr>
</table>
<mat-paginator class="d-none" [pageSize]="pageSize" />
@if (isLoading) {
<ngx-skeleton-loader
animation="pulse"
class="px-4 py-3"
[theme]="{
height: '1.5rem',
width: '100%'
}"
/>
}
@if (dataSource.data.length > pageSize && !isLoading) {
<div class="my-3 text-center">
<button mat-stroked-button (click)="onShowAllHoldings()">
<ng-container i18n>Show all</ng-container>
</button>
</div>
}
@if (dataSource.data.length === 0 && !isLoading) {
<div class="p-3 text-center text-muted">
<small i18n>No data available</small>
</div>
}

View File

@@ -2,6 +2,7 @@ import { getLocale } from '@ghostfolio/common/helper';
import { Holding } from '@ghostfolio/common/interfaces';
import { GfValueComponent } from '@ghostfolio/ui/value';
import { CommonModule } from '@angular/common';
import {
CUSTOM_ELEMENTS_SCHEMA,
ChangeDetectionStrategy,
@@ -13,14 +14,24 @@ import {
ViewChild
} from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatPaginator, MatPaginatorModule } from '@angular/material/paginator';
import { MatSort, MatSortModule } from '@angular/material/sort';
import { MatTableDataSource, MatTableModule } from '@angular/material/table';
import { get } from 'lodash';
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
import { Subject } from 'rxjs';
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [GfValueComponent, MatButtonModule, MatSortModule, MatTableModule],
imports: [
CommonModule,
GfValueComponent,
MatButtonModule,
MatPaginatorModule,
MatSortModule,
MatTableModule,
NgxSkeletonLoaderModule
],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
selector: 'gf-top-holdings',
standalone: true,
@@ -30,8 +41,10 @@ import { Subject } from 'rxjs';
export class GfTopHoldingsComponent implements OnChanges, OnDestroy, OnInit {
@Input() baseCurrency: string;
@Input() locale = getLocale();
@Input() pageSize = Number.MAX_SAFE_INTEGER;
@Input() topHoldings: Holding[];
@ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
public dataSource: MatTableDataSource<Holding> = new MatTableDataSource();
@@ -40,6 +53,7 @@ export class GfTopHoldingsComponent implements OnChanges, OnDestroy, OnInit {
'valueInBaseCurrency',
'allocationInPercentage'
];
public isLoading = true;
private unsubscribeSubject = new Subject<void>();
@@ -48,14 +62,26 @@ export class GfTopHoldingsComponent implements OnChanges, OnDestroy, OnInit {
public ngOnInit() {}
public ngOnChanges() {
if (this.topHoldings) {
this.dataSource = new MatTableDataSource(this.topHoldings);
this.isLoading = true;
this.dataSource.sort = this.sort;
this.dataSource.sortingDataAccessor = get;
this.dataSource = new MatTableDataSource(this.topHoldings);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
this.dataSource.sortingDataAccessor = get;
if (this.topHoldings) {
this.isLoading = false;
}
}
public onShowAllHoldings() {
this.pageSize = Number.MAX_SAFE_INTEGER;
setTimeout(() => {
this.dataSource.paginator = this.paginator;
});
}
public ngOnDestroy() {
this.unsubscribeSubject.next();
this.unsubscribeSubject.complete();