diff --git a/apps/api/src/app/portfolio/rules.service.ts b/apps/api/src/app/portfolio/rules.service.ts
index 7c0e83919..c74d54f4f 100644
--- a/apps/api/src/app/portfolio/rules.service.ts
+++ b/apps/api/src/app/portfolio/rules.service.ts
@@ -17,14 +17,17 @@ export class RulesService {
const { evaluation, value } = rule.evaluate(
rule.getSettings(aUserSettings)
);
+
return {
evaluation,
- value,
+ isActive: true,
key: rule.getKey(),
- name: rule.getName()
+ name: rule.getName(),
+ value
};
} else {
return {
+ isActive: false,
key: rule.getKey(),
name: rule.getName()
};
diff --git a/apps/api/src/app/user/update-user-setting.dto.ts b/apps/api/src/app/user/update-user-setting.dto.ts
index 2473ab583..ff4adb476 100644
--- a/apps/api/src/app/user/update-user-setting.dto.ts
+++ b/apps/api/src/app/user/update-user-setting.dto.ts
@@ -1,5 +1,5 @@
import { IsCurrencyCode } from '@ghostfolio/api/validators/is-currency-code';
-import { xRayRules } from '@ghostfolio/common/interfaces/x-ray-rule.interface';
+import { XRayRules } from '@ghostfolio/common/interfaces/x-ray-rule.interface';
import type {
ColorScheme,
DateRange,
@@ -105,5 +105,5 @@ export class UpdateUserSettingDto {
viewMode?: ViewMode;
@IsOptional()
- xRayRules?: xRayRules;
+ xRayRules?: XRayRules;
}
diff --git a/apps/api/src/app/user/user.controller.ts b/apps/api/src/app/user/user.controller.ts
index 1258341c4..1aec17596 100644
--- a/apps/api/src/app/user/user.controller.ts
+++ b/apps/api/src/app/user/user.controller.ts
@@ -155,6 +155,7 @@ export class UserController {
delete userSettings[key];
}
}
+
return this.userService.updateUserSetting({
userSettings,
userId: this.request.user.id
diff --git a/apps/client/src/app/components/rule/rule.component.html b/apps/client/src/app/components/rule/rule.component.html
index 6493c2c0b..556b65a68 100644
--- a/apps/client/src/app/components/rule/rule.component.html
+++ b/apps/client/src/app/components/rule/rule.component.html
@@ -16,16 +16,13 @@
class="align-items-center d-flex icon-container mr-2 px-2"
[ngClass]="{
okay: rule?.value === true,
- warn: rule?.value === false,
- disabled: rule?.value === undefined
+ warn: rule?.value === false
}"
>
@if (rule?.value === true) {
- } @else if (rule?.value === false) {
-
} @else {
-
+
}
}
@@ -53,32 +50,28 @@
@if (rule?.evaluation) {
{{ rule?.evaluation }}
- } @else {
- Rule is disabled
}
-
-
-
-
-
-
+
+
+
+
+
+
}
diff --git a/apps/client/src/app/components/rule/rule.component.ts b/apps/client/src/app/components/rule/rule.component.ts
index 09a56bb46..9318514f2 100644
--- a/apps/client/src/app/components/rule/rule.component.ts
+++ b/apps/client/src/app/components/rule/rule.component.ts
@@ -1,16 +1,14 @@
import { UpdateUserSettingDto } from '@ghostfolio/api/app/user/update-user-setting.dto';
-import { DataService } from '@ghostfolio/client/services/data.service';
import { PortfolioReportRule } from '@ghostfolio/common/interfaces';
import {
- ChangeDetectorRef,
ChangeDetectionStrategy,
Component,
+ EventEmitter,
Input,
- OnInit
+ OnInit,
+ Output
} from '@angular/core';
-import { Subject } from 'rxjs';
-import { takeUntil } from 'rxjs/operators';
@Component({
selector: 'gf-rule',
@@ -21,39 +19,18 @@ import { takeUntil } from 'rxjs/operators';
export class RuleComponent implements OnInit {
@Input() isLoading: boolean;
@Input() rule: PortfolioReportRule;
- private unsubscribeSubject = new Subject();
+ @Output() ruleUpdated = new EventEmitter();
- public constructor(
- private changeDetectorRef: ChangeDetectorRef,
- private dataService: DataService
- ) {}
+ public constructor() {}
public ngOnInit() {}
- public onUpdateAccount(rule: PortfolioReportRule) {
+ public onUpdateRule(rule: PortfolioReportRule) {
let settings: UpdateUserSettingDto = {
xRayRules: {
- [rule.key]: { isActive: !('evaluation' in rule) }
+ [rule.key]: { isActive: !rule.isActive }
}
};
- this.dataService
- .putUserSetting(settings)
- .pipe(takeUntil(this.unsubscribeSubject))
- .subscribe(() => {
- this.dataService
- .fetchPortfolioReport()
- .pipe(takeUntil(this.unsubscribeSubject))
- .subscribe((report) => {
- for (const ruleGroup in report.rules) {
- for (const singleRule in report.rules[ruleGroup]) {
- if (report.rules[ruleGroup][singleRule]['key'] === rule.key) {
- this.rule = report.rules[ruleGroup][singleRule];
- break;
- }
- }
- }
- this.changeDetectorRef.markForCheck();
- });
- });
+ this.ruleUpdated.emit(settings);
}
}
diff --git a/apps/client/src/app/components/rules/rules.component.html b/apps/client/src/app/components/rules/rules.component.html
index 5ef182329..3e78d7cf4 100644
--- a/apps/client/src/app/components/rules/rules.component.html
+++ b/apps/client/src/app/components/rules/rules.component.html
@@ -13,8 +13,8 @@
}
@if (rules !== null && rules !== undefined) {
- @for (rule of rules; track rule) {
-
+ @for (rule of rules; track rule.key) {
+
}
}
diff --git a/apps/client/src/app/components/rules/rules.component.ts b/apps/client/src/app/components/rules/rules.component.ts
index 9017700c2..04a6ae1f3 100644
--- a/apps/client/src/app/components/rules/rules.component.ts
+++ b/apps/client/src/app/components/rules/rules.component.ts
@@ -1,6 +1,13 @@
+import { UpdateUserSettingDto } from '@ghostfolio/api/app/user/update-user-setting.dto';
import { PortfolioReportRule } from '@ghostfolio/common/interfaces';
-import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
+import {
+ ChangeDetectionStrategy,
+ Component,
+ EventEmitter,
+ Input,
+ Output
+} from '@angular/core';
@Component({
selector: 'gf-rules',
@@ -11,6 +18,11 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
export class RulesComponent {
@Input() hasPermissionToCreateOrder: boolean;
@Input() rules: PortfolioReportRule[];
+ @Output() rulesUpdated = new EventEmitter();
public constructor() {}
+
+ public onRulesUpdated(event: UpdateUserSettingDto) {
+ this.rulesUpdated.emit(event);
+ }
}
diff --git a/apps/client/src/app/pages/portfolio/fire/fire-page.component.ts b/apps/client/src/app/pages/portfolio/fire/fire-page.component.ts
index c33b2c3f5..34394d608 100644
--- a/apps/client/src/app/pages/portfolio/fire/fire-page.component.ts
+++ b/apps/client/src/app/pages/portfolio/fire/fire-page.component.ts
@@ -1,3 +1,4 @@
+import { UpdateUserSettingDto } from '@ghostfolio/api/app/user/update-user-setting.dto';
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';
@@ -149,6 +150,29 @@ export class FirePageComponent implements OnDestroy, OnInit {
});
}
+ public onRulesUpdated(event: UpdateUserSettingDto) {
+ this.isLoading = true;
+ this.dataService
+ .putUserSetting(event)
+ .pipe(takeUntil(this.unsubscribeSubject))
+ .subscribe(() => {
+ this.dataService
+ .fetchPortfolioReport()
+ .pipe(takeUntil(this.unsubscribeSubject))
+ .subscribe((portfolioReport) => {
+ this.accountClusterRiskRules =
+ portfolioReport.rules['accountClusterRisk'] || null;
+ this.currencyClusterRiskRules =
+ portfolioReport.rules['currencyClusterRisk'] || null;
+ this.emergencyFundRules =
+ portfolioReport.rules['emergencyFund'] || null;
+ this.feeRules = portfolioReport.rules['fees'] || null;
+ this.isLoading = false;
+ this.changeDetectorRef.markForCheck();
+ });
+ });
+ }
+
public onSavingsRateChange(savingsRate: number) {
this.dataService
.putUserSetting({ savingsRate })
diff --git a/apps/client/src/app/pages/portfolio/fire/fire-page.html b/apps/client/src/app/pages/portfolio/fire/fire-page.html
index 7c8e09ee7..f7295e662 100644
--- a/apps/client/src/app/pages/portfolio/fire/fire-page.html
+++ b/apps/client/src/app/pages/portfolio/fire/fire-page.html
@@ -127,6 +127,7 @@
@@ -139,6 +140,7 @@
@@ -151,6 +153,7 @@
@@ -163,6 +166,7 @@
diff --git a/libs/common/src/lib/interfaces/portfolio-report-rule.interface.ts b/libs/common/src/lib/interfaces/portfolio-report-rule.interface.ts
index 7e0be4fb1..61fe389af 100644
--- a/libs/common/src/lib/interfaces/portfolio-report-rule.interface.ts
+++ b/libs/common/src/lib/interfaces/portfolio-report-rule.interface.ts
@@ -1,5 +1,6 @@
export interface PortfolioReportRule {
evaluation?: string;
+ isActive: boolean;
key: string;
name: string;
value?: boolean;
diff --git a/libs/common/src/lib/interfaces/user-settings.interface.ts b/libs/common/src/lib/interfaces/user-settings.interface.ts
index eaeae5206..8e4911ae2 100644
--- a/libs/common/src/lib/interfaces/user-settings.interface.ts
+++ b/libs/common/src/lib/interfaces/user-settings.interface.ts
@@ -5,7 +5,7 @@ import {
ViewMode
} from '@ghostfolio/common/types';
-import { xRayRules } from './x-ray-rule.interface';
+import { XRayRules } from './x-ray-rule.interface';
export interface UserSettings {
annualInterestRate?: number;
@@ -25,5 +25,5 @@ export interface UserSettings {
retirementDate?: string;
savingsRate?: number;
viewMode?: ViewMode;
- xRayRules?: xRayRules;
+ xRayRules?: XRayRules;
}
diff --git a/libs/common/src/lib/interfaces/x-ray-rule.interface.ts b/libs/common/src/lib/interfaces/x-ray-rule.interface.ts
index d0881f2c8..aecb78a5f 100644
--- a/libs/common/src/lib/interfaces/x-ray-rule.interface.ts
+++ b/libs/common/src/lib/interfaces/x-ray-rule.interface.ts
@@ -1,4 +1,4 @@
-export interface xRayRules {
+export interface XRayRules {
AccountClusterRiskCurrentInvestment?: Rule;
AccountClusterRiskSingleAccount?: Rule;
CurrencyClusterRiskBaseCurrencyCurrentInvestment?: Rule;