Feature/add business logic of rule settings (#3826)
* Add business logic of rule settings * Update changelog --------- Co-authored-by: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
This commit is contained in:
parent
1b2a7dc2e4
commit
24a3d92da0
@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Added support to customize the rule thresholds in the _X-ray_ section (experimental)
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Improved the language localization for German (`de`)
|
- Improved the language localization for German (`de`)
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { IsCurrencyCode } from '@ghostfolio/api/validators/is-currency-code';
|
import { IsCurrencyCode } from '@ghostfolio/api/validators/is-currency-code';
|
||||||
|
import { PortfolioReportRule } from '@ghostfolio/common/interfaces';
|
||||||
import type {
|
import type {
|
||||||
ColorScheme,
|
ColorScheme,
|
||||||
DateRange,
|
DateRange,
|
||||||
|
@ -76,11 +76,11 @@ export class AccountClusterRiskCurrentInvestment extends Rule<Settings> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public getSettings(aUserSettings: UserSettings): Settings {
|
public getSettings({ baseCurrency, xRayRules }: UserSettings): Settings {
|
||||||
return {
|
return {
|
||||||
baseCurrency: aUserSettings.baseCurrency,
|
baseCurrency,
|
||||||
isActive: aUserSettings.xRayRules[this.getKey()].isActive,
|
isActive: xRayRules[this.getKey()].isActive,
|
||||||
thresholdMax: 0.5
|
thresholdMax: xRayRules[this.getKey()]?.thresholdMax ?? 0.5
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,9 +34,9 @@ export class AccountClusterRiskSingleAccount extends Rule<RuleSettings> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public getSettings(aUserSettings: UserSettings): RuleSettings {
|
public getSettings({ xRayRules }: UserSettings): RuleSettings {
|
||||||
return {
|
return {
|
||||||
isActive: aUserSettings.xRayRules[this.getKey()].isActive
|
isActive: xRayRules[this.getKey()].isActive
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,10 +62,10 @@ export class CurrencyClusterRiskBaseCurrencyCurrentInvestment extends Rule<Setti
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public getSettings(aUserSettings: UserSettings): Settings {
|
public getSettings({ baseCurrency, xRayRules }: UserSettings): Settings {
|
||||||
return {
|
return {
|
||||||
baseCurrency: aUserSettings.baseCurrency,
|
baseCurrency,
|
||||||
isActive: aUserSettings.xRayRules[this.getKey()].isActive
|
isActive: xRayRules[this.getKey()].isActive
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,11 +62,11 @@ export class CurrencyClusterRiskCurrentInvestment extends Rule<Settings> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public getSettings(aUserSettings: UserSettings): Settings {
|
public getSettings({ baseCurrency, xRayRules }: UserSettings): Settings {
|
||||||
return {
|
return {
|
||||||
baseCurrency: aUserSettings.baseCurrency,
|
baseCurrency,
|
||||||
isActive: aUserSettings.xRayRules[this.getKey()].isActive,
|
isActive: xRayRules[this.getKey()].isActive,
|
||||||
thresholdMax: 0.5
|
thresholdMax: xRayRules[this.getKey()]?.thresholdMax ?? 0.5
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ export class EmergencyFundSetup extends Rule<Settings> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public evaluate(ruleSettings: Settings) {
|
public evaluate(ruleSettings: Settings) {
|
||||||
if (this.emergencyFund < ruleSettings.thresholdMin) {
|
if (!this.emergencyFund) {
|
||||||
return {
|
return {
|
||||||
evaluation: 'No emergency fund has been set up',
|
evaluation: 'No emergency fund has been set up',
|
||||||
value: false
|
value: false
|
||||||
@ -32,16 +32,14 @@ export class EmergencyFundSetup extends Rule<Settings> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public getSettings(aUserSettings: UserSettings): Settings {
|
public getSettings({ baseCurrency, xRayRules }: UserSettings): Settings {
|
||||||
return {
|
return {
|
||||||
baseCurrency: aUserSettings.baseCurrency,
|
baseCurrency,
|
||||||
isActive: aUserSettings.xRayRules[this.getKey()].isActive,
|
isActive: xRayRules[this.getKey()].isActive
|
||||||
thresholdMin: 0
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Settings extends RuleSettings {
|
interface Settings extends RuleSettings {
|
||||||
baseCurrency: string;
|
baseCurrency: string;
|
||||||
thresholdMin: number;
|
|
||||||
}
|
}
|
||||||
|
@ -43,11 +43,11 @@ export class FeeRatioInitialInvestment extends Rule<Settings> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public getSettings(aUserSettings: UserSettings): Settings {
|
public getSettings({ baseCurrency, xRayRules }: UserSettings): Settings {
|
||||||
return {
|
return {
|
||||||
baseCurrency: aUserSettings.baseCurrency,
|
baseCurrency,
|
||||||
isActive: aUserSettings.xRayRules[this.getKey()].isActive,
|
isActive: xRayRules[this.getKey()].isActive,
|
||||||
thresholdMax: 0.01
|
thresholdMax: xRayRules[this.getKey()]?.thresholdMax ?? 0.01
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ import { PortfolioReportRule } from '@ghostfolio/common/interfaces';
|
|||||||
|
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { Component, Inject } from '@angular/core';
|
import { Component, Inject } from '@angular/core';
|
||||||
|
import { FormsModule } from '@angular/forms';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import {
|
import {
|
||||||
MAT_DIALOG_DATA,
|
MAT_DIALOG_DATA,
|
||||||
@ -16,6 +17,7 @@ import { IRuleSettingsDialogParams } from './interfaces/interfaces';
|
|||||||
@Component({
|
@Component({
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
|
FormsModule,
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
MatDialogModule,
|
MatDialogModule,
|
||||||
MatFormFieldModule,
|
MatFormFieldModule,
|
||||||
|
@ -1,23 +1,37 @@
|
|||||||
<div mat-dialog-title>{{ data.rule.name }}</div>
|
<div mat-dialog-title>{{ data.rule.name }}</div>
|
||||||
|
|
||||||
<div class="py-3" mat-dialog-content>
|
<div class="py-3" mat-dialog-content>
|
||||||
<mat-form-field appearance="outline" class="w-100">
|
<mat-form-field
|
||||||
|
appearance="outline"
|
||||||
|
class="w-100"
|
||||||
|
[ngClass]="{ 'd-none': settings.thresholdMin === undefined }"
|
||||||
|
>
|
||||||
<mat-label i18n>Threshold Min</mat-label>
|
<mat-label i18n>Threshold Min</mat-label>
|
||||||
<input matInput name="thresholdMin" type="number" />
|
<input
|
||||||
|
matInput
|
||||||
|
name="thresholdMin"
|
||||||
|
type="number"
|
||||||
|
[(ngModel)]="settings.thresholdMin"
|
||||||
|
/>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field appearance="outline" class="w-100">
|
<mat-form-field
|
||||||
|
appearance="outline"
|
||||||
|
class="w-100"
|
||||||
|
[ngClass]="{ 'd-none': settings.thresholdMax === undefined }"
|
||||||
|
>
|
||||||
<mat-label i18n>Threshold Max</mat-label>
|
<mat-label i18n>Threshold Max</mat-label>
|
||||||
<input matInput name="thresholdMax" type="number" />
|
<input
|
||||||
|
matInput
|
||||||
|
name="thresholdMax"
|
||||||
|
type="number"
|
||||||
|
[(ngModel)]="settings.thresholdMax"
|
||||||
|
/>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div align="end" mat-dialog-actions>
|
<div align="end" mat-dialog-actions>
|
||||||
<button i18n mat-button (click)="dialogRef.close()">Close</button>
|
<button i18n mat-button (click)="dialogRef.close()">Close</button>
|
||||||
<button
|
<button color="primary" mat-flat-button (click)="dialogRef.close(settings)">
|
||||||
color="primary"
|
|
||||||
mat-flat-button
|
|
||||||
(click)="dialogRef.close({ settings })"
|
|
||||||
>
|
|
||||||
<ng-container i18n>Save</ng-container>
|
<ng-container i18n>Save</ng-container>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -62,7 +62,7 @@
|
|||||||
<ion-icon name="ellipsis-horizontal" />
|
<ion-icon name="ellipsis-horizontal" />
|
||||||
</button>
|
</button>
|
||||||
<mat-menu #rulesMenu="matMenu" xPosition="before">
|
<mat-menu #rulesMenu="matMenu" xPosition="before">
|
||||||
@if (rule?.isActive && !isEmpty(rule.settings) && false) {
|
@if (rule?.isActive && !isEmpty(rule.settings)) {
|
||||||
<button mat-menu-item (click)="onCustomizeRule(rule)">
|
<button mat-menu-item (click)="onCustomizeRule(rule)">
|
||||||
<ng-container i18n>Customize</ng-container>...
|
<ng-container i18n>Customize</ng-container>...
|
||||||
</button>
|
</button>
|
||||||
|
@ -55,16 +55,15 @@ export class RuleComponent implements OnInit {
|
|||||||
dialogRef
|
dialogRef
|
||||||
.afterClosed()
|
.afterClosed()
|
||||||
.pipe(takeUntil(this.unsubscribeSubject))
|
.pipe(takeUntil(this.unsubscribeSubject))
|
||||||
.subscribe(
|
.subscribe((settings: PortfolioReportRule['settings']) => {
|
||||||
({ settings }: { settings: PortfolioReportRule['settings'] }) => {
|
if (settings) {
|
||||||
if (settings) {
|
this.ruleUpdated.emit({
|
||||||
console.log(settings);
|
xRayRules: {
|
||||||
|
[rule.key]: settings
|
||||||
// TODO
|
}
|
||||||
// this.ruleUpdated.emit(settings);
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public onUpdateRule(rule: PortfolioReportRule) {
|
public onUpdateRule(rule: PortfolioReportRule) {
|
||||||
|
@ -134,8 +134,6 @@ export class FirePageComponent implements OnDestroy, OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public onRulesUpdated(event: UpdateUserSettingDto) {
|
public onRulesUpdated(event: UpdateUserSettingDto) {
|
||||||
this.isLoading = true;
|
|
||||||
|
|
||||||
this.dataService
|
this.dataService
|
||||||
.putUserSetting(event)
|
.putUserSetting(event)
|
||||||
.pipe(takeUntil(this.unsubscribeSubject))
|
.pipe(takeUntil(this.unsubscribeSubject))
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import { PortfolioReportRule } from '@ghostfolio/common/interfaces';
|
||||||
|
|
||||||
export type XRayRulesSettings = {
|
export type XRayRulesSettings = {
|
||||||
AccountClusterRiskCurrentInvestment?: RuleSettings;
|
AccountClusterRiskCurrentInvestment?: RuleSettings;
|
||||||
AccountClusterRiskSingleAccount?: RuleSettings;
|
AccountClusterRiskSingleAccount?: RuleSettings;
|
||||||
@ -7,6 +9,6 @@ export type XRayRulesSettings = {
|
|||||||
FeeRatioInitialInvestment?: RuleSettings;
|
FeeRatioInitialInvestment?: RuleSettings;
|
||||||
};
|
};
|
||||||
|
|
||||||
interface RuleSettings {
|
interface RuleSettings extends Pick<PortfolioReportRule, 'settings'> {
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user