Browse Source

Restructure XRayRulesSettings

pull/3898/head
Thomas Kaul 11 months ago
parent
commit
1304de2050
  1. 9
      apps/api/src/app/portfolio/rules.service.ts
  2. 47
      apps/api/src/app/user/user.service.ts
  3. 4
      apps/api/src/models/rules/account-cluster-risk/current-investment.ts
  4. 2
      apps/api/src/models/rules/account-cluster-risk/single-account.ts
  5. 2
      apps/api/src/models/rules/currency-cluster-risk/base-currency-current-investment.ts
  6. 4
      apps/api/src/models/rules/currency-cluster-risk/current-investment.ts
  7. 2
      apps/api/src/models/rules/emergency-fund/emergency-fund-setup.ts
  8. 4
      apps/api/src/models/rules/fees/fee-ratio-initial-investment.ts
  9. 2
      apps/client/src/app/components/rule/rule-settings-dialog/interfaces/interfaces.ts
  10. 6
      apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.component.ts
  11. 6
      apps/client/src/app/components/rule/rule.component.html
  12. 12
      apps/client/src/app/components/rule/rule.component.ts
  13. 1
      apps/client/src/app/components/rules/rules.component.html
  14. 4
      apps/client/src/app/components/rules/rules.component.ts
  15. 5
      apps/client/src/app/pages/portfolio/fire/fire-page.component.ts
  16. 5
      apps/client/src/app/pages/portfolio/fire/fire-page.html
  17. 4
      libs/common/src/lib/interfaces/portfolio-report-rule.interface.ts
  18. 2
      libs/common/src/lib/types/x-ray-rules-settings.type.ts

9
apps/api/src/app/portfolio/rules.service.ts

@ -6,6 +6,7 @@ import {
} from '@ghostfolio/common/interfaces'; } from '@ghostfolio/common/interfaces';
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { isNumber } from 'lodash';
@Injectable() @Injectable()
export class RulesService { export class RulesService {
@ -27,10 +28,10 @@ export class RulesService {
isActive: true, isActive: true,
key: rule.getKey(), key: rule.getKey(),
name: rule.getName(), name: rule.getName(),
settings: <PortfolioReportRule['settings']>{ settings: {
thresholdMax: settings['thresholdMax'], thresholdMax: isNumber(settings['thresholdMax']) ? true : false,
thresholdMin: settings['thresholdMin'] thresholdMin: isNumber(settings['thresholdMin']) ? true : false
} } as PortfolioReportRule['settings']
}; };
} else { } else {
return { return {

47
apps/api/src/app/user/user.service.ts

@ -2,6 +2,12 @@ import { OrderService } from '@ghostfolio/api/app/order/order.service';
import { SubscriptionService } from '@ghostfolio/api/app/subscription/subscription.service'; import { SubscriptionService } from '@ghostfolio/api/app/subscription/subscription.service';
import { environment } from '@ghostfolio/api/environments/environment'; import { environment } from '@ghostfolio/api/environments/environment';
import { PortfolioChangedEvent } from '@ghostfolio/api/events/portfolio-changed.event'; import { PortfolioChangedEvent } from '@ghostfolio/api/events/portfolio-changed.event';
import { AccountClusterRiskCurrentInvestment } from '@ghostfolio/api/models/rules/account-cluster-risk/current-investment';
import { AccountClusterRiskSingleAccount } from '@ghostfolio/api/models/rules/account-cluster-risk/single-account';
import { CurrencyClusterRiskBaseCurrencyCurrentInvestment } from '@ghostfolio/api/models/rules/currency-cluster-risk/base-currency-current-investment';
import { CurrencyClusterRiskCurrentInvestment } from '@ghostfolio/api/models/rules/currency-cluster-risk/current-investment';
import { EmergencyFundSetup } from '@ghostfolio/api/models/rules/emergency-fund/emergency-fund-setup';
import { FeeRatioInitialInvestment } from '@ghostfolio/api/models/rules/fees/fee-ratio-initial-investment';
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
import { I18nService } from '@ghostfolio/api/services/i18n/i18n.service'; import { I18nService } from '@ghostfolio/api/services/i18n/i18n.service';
import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service';
@ -200,17 +206,36 @@ export class UserService {
(user.Settings.settings as UserSettings).viewMode = 'DEFAULT'; (user.Settings.settings as UserSettings).viewMode = 'DEFAULT';
} }
// Set default values for X-ray rules // TODO
if (!(user.Settings.settings as UserSettings).xRayRules) { (user.Settings.settings as UserSettings).xRayRules = {
(user.Settings.settings as UserSettings).xRayRules = { AccountClusterRiskCurrentInvestment:
AccountClusterRiskCurrentInvestment: { isActive: true }, new AccountClusterRiskCurrentInvestment(undefined, {}).getSettings(
AccountClusterRiskSingleAccount: { isActive: true }, user.Settings.settings
CurrencyClusterRiskBaseCurrencyCurrentInvestment: { isActive: true }, ),
CurrencyClusterRiskCurrentInvestment: { isActive: true }, AccountClusterRiskSingleAccount: new AccountClusterRiskSingleAccount(
EmergencyFundSetup: { isActive: true }, undefined,
FeeRatioInitialInvestment: { isActive: true } {}
}; ).getSettings(user.Settings.settings),
} CurrencyClusterRiskBaseCurrencyCurrentInvestment:
new CurrencyClusterRiskBaseCurrencyCurrentInvestment(
undefined,
undefined
).getSettings(user.Settings.settings),
CurrencyClusterRiskCurrentInvestment:
new CurrencyClusterRiskCurrentInvestment(
undefined,
undefined
).getSettings(user.Settings.settings),
EmergencyFundSetup: new EmergencyFundSetup(
undefined,
undefined
).getSettings(user.Settings.settings),
FeeRatioInitialInvestment: new FeeRatioInitialInvestment(
undefined,
undefined,
undefined
).getSettings(user.Settings.settings)
};
let currentPermissions = getPermissions(user.role); let currentPermissions = getPermissions(user.role);

4
apps/api/src/models/rules/account-cluster-risk/current-investment.ts

@ -79,8 +79,8 @@ export class AccountClusterRiskCurrentInvestment extends Rule<Settings> {
public getSettings({ baseCurrency, xRayRules }: UserSettings): Settings { public getSettings({ baseCurrency, xRayRules }: UserSettings): Settings {
return { return {
baseCurrency, baseCurrency,
isActive: xRayRules[this.getKey()].isActive, isActive: xRayRules?.[this.getKey()].isActive ?? true,
thresholdMax: xRayRules[this.getKey()]?.thresholdMax ?? 0.5 thresholdMax: xRayRules?.[this.getKey()]?.thresholdMax ?? 0.5
}; };
} }
} }

2
apps/api/src/models/rules/account-cluster-risk/single-account.ts

@ -36,7 +36,7 @@ export class AccountClusterRiskSingleAccount extends Rule<RuleSettings> {
public getSettings({ xRayRules }: UserSettings): RuleSettings { public getSettings({ xRayRules }: UserSettings): RuleSettings {
return { return {
isActive: xRayRules[this.getKey()].isActive isActive: xRayRules?.[this.getKey()].isActive ?? true
}; };
} }
} }

2
apps/api/src/models/rules/currency-cluster-risk/base-currency-current-investment.ts

@ -64,7 +64,7 @@ export class CurrencyClusterRiskBaseCurrencyCurrentInvestment extends Rule<Setti
public getSettings({ baseCurrency, xRayRules }: UserSettings): Settings { public getSettings({ baseCurrency, xRayRules }: UserSettings): Settings {
return { return {
baseCurrency, baseCurrency,
isActive: xRayRules[this.getKey()].isActive isActive: xRayRules?.[this.getKey()].isActive ?? true
}; };
} }
} }

4
apps/api/src/models/rules/currency-cluster-risk/current-investment.ts

@ -64,8 +64,8 @@ export class CurrencyClusterRiskCurrentInvestment extends Rule<Settings> {
public getSettings({ baseCurrency, xRayRules }: UserSettings): Settings { public getSettings({ baseCurrency, xRayRules }: UserSettings): Settings {
return { return {
baseCurrency, baseCurrency,
isActive: xRayRules[this.getKey()].isActive, isActive: xRayRules?.[this.getKey()].isActive ?? true,
thresholdMax: xRayRules[this.getKey()]?.thresholdMax ?? 0.5 thresholdMax: xRayRules?.[this.getKey()]?.thresholdMax ?? 0.5
}; };
} }
} }

2
apps/api/src/models/rules/emergency-fund/emergency-fund-setup.ts

@ -35,7 +35,7 @@ export class EmergencyFundSetup extends Rule<Settings> {
public getSettings({ baseCurrency, xRayRules }: UserSettings): Settings { public getSettings({ baseCurrency, xRayRules }: UserSettings): Settings {
return { return {
baseCurrency, baseCurrency,
isActive: xRayRules[this.getKey()].isActive isActive: xRayRules?.[this.getKey()].isActive ?? true
}; };
} }
} }

4
apps/api/src/models/rules/fees/fee-ratio-initial-investment.ts

@ -46,8 +46,8 @@ export class FeeRatioInitialInvestment extends Rule<Settings> {
public getSettings({ baseCurrency, xRayRules }: UserSettings): Settings { public getSettings({ baseCurrency, xRayRules }: UserSettings): Settings {
return { return {
baseCurrency, baseCurrency,
isActive: xRayRules[this.getKey()].isActive, isActive: xRayRules?.[this.getKey()].isActive ?? true,
thresholdMax: xRayRules[this.getKey()]?.thresholdMax ?? 0.01 thresholdMax: xRayRules?.[this.getKey()]?.thresholdMax ?? 0.01
}; };
} }
} }

2
apps/client/src/app/components/rule/rule-settings-dialog/interfaces/interfaces.ts

@ -1,5 +1,7 @@
import { PortfolioReportRule } from '@ghostfolio/common/interfaces'; import { PortfolioReportRule } from '@ghostfolio/common/interfaces';
import { XRayRulesSettings } from '@ghostfolio/common/types';
export interface IRuleSettingsDialogParams { export interface IRuleSettingsDialogParams {
rule: PortfolioReportRule; rule: PortfolioReportRule;
settings: XRayRulesSettings['AccountClusterRiskCurrentInvestment'];
} }

6
apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.component.ts

@ -1,4 +1,4 @@
import { PortfolioReportRule } from '@ghostfolio/common/interfaces'; import { XRayRulesSettings } from '@ghostfolio/common/types';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { Component, Inject } from '@angular/core'; import { Component, Inject } from '@angular/core';
@ -29,12 +29,12 @@ import { IRuleSettingsDialogParams } from './interfaces/interfaces';
templateUrl: './rule-settings-dialog.html' templateUrl: './rule-settings-dialog.html'
}) })
export class GfRuleSettingsDialogComponent { export class GfRuleSettingsDialogComponent {
public settings: PortfolioReportRule['settings']; public settings: XRayRulesSettings['AccountClusterRiskCurrentInvestment'];
public constructor( public constructor(
@Inject(MAT_DIALOG_DATA) public data: IRuleSettingsDialogParams, @Inject(MAT_DIALOG_DATA) public data: IRuleSettingsDialogParams,
public dialogRef: MatDialogRef<GfRuleSettingsDialogComponent> public dialogRef: MatDialogRef<GfRuleSettingsDialogComponent>
) { ) {
this.settings = this.data.rule.settings; this.settings = this.data.settings;
} }
} }

6
apps/client/src/app/components/rule/rule.component.html

@ -62,7 +62,11 @@
<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)) { @if (
rule?.isActive &&
(rule?.settings.thresholdMax >= 0 ||
rule?.settings.thresholdMin >= 0)
) {
<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>

12
apps/client/src/app/components/rule/rule.component.ts

@ -1,5 +1,6 @@
import { UpdateUserSettingDto } from '@ghostfolio/api/app/user/update-user-setting.dto'; import { UpdateUserSettingDto } from '@ghostfolio/api/app/user/update-user-setting.dto';
import { PortfolioReportRule } from '@ghostfolio/common/interfaces'; import { PortfolioReportRule } from '@ghostfolio/common/interfaces';
import { XRayRulesSettings } from '@ghostfolio/common/types';
import { import {
ChangeDetectionStrategy, ChangeDetectionStrategy,
@ -10,7 +11,6 @@ import {
Output Output
} from '@angular/core'; } from '@angular/core';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { isEmpty } from 'lodash';
import { DeviceDetectorService } from 'ngx-device-detector'; import { DeviceDetectorService } from 'ngx-device-detector';
import { Subject, takeUntil } from 'rxjs'; import { Subject, takeUntil } from 'rxjs';
@ -27,11 +27,10 @@ export class RuleComponent implements OnInit {
@Input() hasPermissionToUpdateUserSettings: boolean; @Input() hasPermissionToUpdateUserSettings: boolean;
@Input() isLoading: boolean; @Input() isLoading: boolean;
@Input() rule: PortfolioReportRule; @Input() rule: PortfolioReportRule;
@Input() settings: XRayRulesSettings['AccountClusterRiskCurrentInvestment'];
@Output() ruleUpdated = new EventEmitter<UpdateUserSettingDto>(); @Output() ruleUpdated = new EventEmitter<UpdateUserSettingDto>();
public isEmpty = isEmpty;
private deviceType: string; private deviceType: string;
private unsubscribeSubject = new Subject<void>(); private unsubscribeSubject = new Subject<void>();
@ -46,9 +45,10 @@ export class RuleComponent implements OnInit {
public onCustomizeRule(rule: PortfolioReportRule) { public onCustomizeRule(rule: PortfolioReportRule) {
const dialogRef = this.dialog.open(GfRuleSettingsDialogComponent, { const dialogRef = this.dialog.open(GfRuleSettingsDialogComponent, {
data: <IRuleSettingsDialogParams>{ data: {
rule rule,
}, settings: this.settings
} as IRuleSettingsDialogParams,
width: this.deviceType === 'mobile' ? '100vw' : '50rem' width: this.deviceType === 'mobile' ? '100vw' : '50rem'
}); });

1
apps/client/src/app/components/rules/rules.component.html

@ -12,6 +12,7 @@
hasPermissionToUpdateUserSettings hasPermissionToUpdateUserSettings
" "
[rule]="rule" [rule]="rule"
[settings]="settings?.[rule.key]"
(ruleUpdated)="onRuleUpdated($event)" (ruleUpdated)="onRuleUpdated($event)"
/> />
} }

4
apps/client/src/app/components/rules/rules.component.ts

@ -1,5 +1,6 @@
import { UpdateUserSettingDto } from '@ghostfolio/api/app/user/update-user-setting.dto'; import { UpdateUserSettingDto } from '@ghostfolio/api/app/user/update-user-setting.dto';
import { PortfolioReportRule } from '@ghostfolio/common/interfaces'; import { PortfolioReportRule } from '@ghostfolio/common/interfaces';
import { XRayRulesSettings } from '@ghostfolio/common/types';
import { import {
ChangeDetectionStrategy, ChangeDetectionStrategy,
@ -19,11 +20,10 @@ export class RulesComponent {
@Input() hasPermissionToUpdateUserSettings: boolean; @Input() hasPermissionToUpdateUserSettings: boolean;
@Input() isLoading: boolean; @Input() isLoading: boolean;
@Input() rules: PortfolioReportRule[]; @Input() rules: PortfolioReportRule[];
@Input() settings: XRayRulesSettings;
@Output() rulesUpdated = new EventEmitter<UpdateUserSettingDto>(); @Output() rulesUpdated = new EventEmitter<UpdateUserSettingDto>();
public constructor() {}
public onRuleUpdated(event: UpdateUserSettingDto) { public onRuleUpdated(event: UpdateUserSettingDto) {
this.rulesUpdated.emit(event); this.rulesUpdated.emit(event);
} }

5
apps/client/src/app/pages/portfolio/fire/fire-page.component.ts

@ -138,6 +138,11 @@ export class FirePageComponent implements OnDestroy, OnInit {
.putUserSetting(event) .putUserSetting(event)
.pipe(takeUntil(this.unsubscribeSubject)) .pipe(takeUntil(this.unsubscribeSubject))
.subscribe(() => { .subscribe(() => {
this.userService
.get(true)
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe();
this.initializePortfolioReport(); this.initializePortfolioReport();
}); });
} }

5
apps/client/src/app/pages/portfolio/fire/fire-page.html

@ -132,6 +132,7 @@
" "
[isLoading]="isLoadingPortfolioReport" [isLoading]="isLoadingPortfolioReport"
[rules]="emergencyFundRules" [rules]="emergencyFundRules"
[settings]="user?.settings?.xRayRules"
(rulesUpdated)="onRulesUpdated($event)" (rulesUpdated)="onRulesUpdated($event)"
/> />
</div> </div>
@ -150,6 +151,7 @@
" "
[isLoading]="isLoadingPortfolioReport" [isLoading]="isLoadingPortfolioReport"
[rules]="currencyClusterRiskRules" [rules]="currencyClusterRiskRules"
[settings]="user?.settings?.xRayRules"
(rulesUpdated)="onRulesUpdated($event)" (rulesUpdated)="onRulesUpdated($event)"
/> />
</div> </div>
@ -168,6 +170,7 @@
" "
[isLoading]="isLoadingPortfolioReport" [isLoading]="isLoadingPortfolioReport"
[rules]="accountClusterRiskRules" [rules]="accountClusterRiskRules"
[settings]="user?.settings?.xRayRules"
(rulesUpdated)="onRulesUpdated($event)" (rulesUpdated)="onRulesUpdated($event)"
/> />
</div> </div>
@ -186,6 +189,7 @@
" "
[isLoading]="isLoadingPortfolioReport" [isLoading]="isLoadingPortfolioReport"
[rules]="feeRules" [rules]="feeRules"
[settings]="user?.settings?.xRayRules"
(rulesUpdated)="onRulesUpdated($event)" (rulesUpdated)="onRulesUpdated($event)"
/> />
</div> </div>
@ -200,6 +204,7 @@
" "
[isLoading]="isLoadingPortfolioReport" [isLoading]="isLoadingPortfolioReport"
[rules]="inactiveRules" [rules]="inactiveRules"
[settings]="user?.settings?.xRayRules"
(rulesUpdated)="onRulesUpdated($event)" (rulesUpdated)="onRulesUpdated($event)"
/> />
</div> </div>

4
libs/common/src/lib/interfaces/portfolio-report-rule.interface.ts

@ -4,8 +4,8 @@ export interface PortfolioReportRule {
key: string; key: string;
name: string; name: string;
settings?: { settings?: {
thresholdMax?: number; thresholdMax: boolean;
thresholdMin?: number; thresholdMin: boolean;
}; };
value?: boolean; value?: boolean;
} }

2
libs/common/src/lib/types/x-ray-rules-settings.type.ts

@ -11,4 +11,6 @@ export type XRayRulesSettings = {
interface RuleSettings extends Pick<PortfolioReportRule, 'settings'> { interface RuleSettings extends Pick<PortfolioReportRule, 'settings'> {
isActive: boolean; isActive: boolean;
thresholdMax?: number;
thresholdMin?: number;
} }

Loading…
Cancel
Save