Feature/restructure XRayRulesSettings (#3898)
* Restructure XRayRulesSettings * Update changelog
This commit is contained in:
parent
aee5e833a5
commit
f8da265f5f
@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Improved the labels of the chart of the holdings tab on the home page (experimental)
|
- Improved the labels of the chart of the holdings tab on the home page (experimental)
|
||||||
|
- Refactored the rule thresholds in the _X-ray_ section (experimental)
|
||||||
- Exposed the timeout of the portfolio snapshot computation as an environment variable (`PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_TIMEOUT`)
|
- Exposed the timeout of the portfolio snapshot computation as an environment variable (`PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_TIMEOUT`)
|
||||||
- Harmonized the processor concurrency environment variables
|
- Harmonized the processor concurrency environment variables
|
||||||
- Improved the portfolio unit tests to work with exported activity files
|
- Improved the portfolio unit tests to work with exported activity files
|
||||||
|
@ -24,13 +24,10 @@ export class RulesService {
|
|||||||
return {
|
return {
|
||||||
evaluation,
|
evaluation,
|
||||||
value,
|
value,
|
||||||
|
configuration: rule.getConfiguration(),
|
||||||
isActive: true,
|
isActive: true,
|
||||||
key: rule.getKey(),
|
key: rule.getKey(),
|
||||||
name: rule.getName(),
|
name: rule.getName()
|
||||||
settings: <PortfolioReportRule['settings']>{
|
|
||||||
thresholdMax: settings['thresholdMax'],
|
|
||||||
thresholdMin: settings['thresholdMin']
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
|
@ -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,35 @@ export class UserService {
|
|||||||
(user.Settings.settings as UserSettings).viewMode = 'DEFAULT';
|
(user.Settings.settings as UserSettings).viewMode = 'DEFAULT';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set default values for X-ray rules
|
(user.Settings.settings as UserSettings).xRayRules = {
|
||||||
if (!(user.Settings.settings as UserSettings).xRayRules) {
|
AccountClusterRiskCurrentInvestment:
|
||||||
(user.Settings.settings as UserSettings).xRayRules = {
|
new AccountClusterRiskCurrentInvestment(undefined, {}).getSettings(
|
||||||
AccountClusterRiskCurrentInvestment: { isActive: true },
|
user.Settings.settings
|
||||||
AccountClusterRiskSingleAccount: { isActive: true },
|
),
|
||||||
CurrencyClusterRiskBaseCurrencyCurrentInvestment: { isActive: true },
|
AccountClusterRiskSingleAccount: new AccountClusterRiskSingleAccount(
|
||||||
CurrencyClusterRiskCurrentInvestment: { isActive: true },
|
undefined,
|
||||||
EmergencyFundSetup: { isActive: true },
|
{}
|
||||||
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);
|
||||||
|
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
|
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
|
||||||
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
|
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
|
||||||
import { groupBy } from '@ghostfolio/common/helper';
|
import { groupBy } from '@ghostfolio/common/helper';
|
||||||
import { PortfolioPosition, UserSettings } from '@ghostfolio/common/interfaces';
|
import {
|
||||||
|
PortfolioPosition,
|
||||||
|
PortfolioReportRule,
|
||||||
|
UserSettings
|
||||||
|
} from '@ghostfolio/common/interfaces';
|
||||||
|
|
||||||
import { Big } from 'big.js';
|
import { Big } from 'big.js';
|
||||||
|
|
||||||
@ -65,5 +69,9 @@ export abstract class Rule<T extends RuleSettings> implements RuleInterface<T> {
|
|||||||
|
|
||||||
public abstract evaluate(aRuleSettings: T): EvaluationResult;
|
public abstract evaluate(aRuleSettings: T): EvaluationResult;
|
||||||
|
|
||||||
|
public abstract getConfiguration(): Partial<
|
||||||
|
PortfolioReportRule['configuration']
|
||||||
|
>;
|
||||||
|
|
||||||
public abstract getSettings(aUserSettings: UserSettings): T;
|
public abstract getSettings(aUserSettings: UserSettings): T;
|
||||||
}
|
}
|
||||||
|
@ -76,11 +76,22 @@ export class AccountClusterRiskCurrentInvestment extends Rule<Settings> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getConfiguration() {
|
||||||
|
return {
|
||||||
|
threshold: {
|
||||||
|
max: 1,
|
||||||
|
min: 0,
|
||||||
|
step: 0.01
|
||||||
|
},
|
||||||
|
thresholdMax: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
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
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,9 +34,13 @@ export class AccountClusterRiskSingleAccount extends Rule<RuleSettings> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getConfiguration() {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
public getSettings({ xRayRules }: UserSettings): RuleSettings {
|
public getSettings({ xRayRules }: UserSettings): RuleSettings {
|
||||||
return {
|
return {
|
||||||
isActive: xRayRules[this.getKey()].isActive
|
isActive: xRayRules?.[this.getKey()].isActive ?? true
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,10 +61,14 @@ export class CurrencyClusterRiskBaseCurrencyCurrentInvestment extends Rule<Setti
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getConfiguration() {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
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
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,11 +61,22 @@ export class CurrencyClusterRiskCurrentInvestment extends Rule<Settings> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getConfiguration() {
|
||||||
|
return {
|
||||||
|
threshold: {
|
||||||
|
max: 1,
|
||||||
|
min: 0,
|
||||||
|
step: 0.01
|
||||||
|
},
|
||||||
|
thresholdMax: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
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
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,10 +32,14 @@ export class EmergencyFundSetup extends Rule<Settings> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getConfiguration() {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
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
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,11 +43,22 @@ export class FeeRatioInitialInvestment extends Rule<Settings> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getConfiguration() {
|
||||||
|
return {
|
||||||
|
threshold: {
|
||||||
|
max: 0.1,
|
||||||
|
min: 0,
|
||||||
|
step: 0.005
|
||||||
|
},
|
||||||
|
thresholdMax: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
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
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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'];
|
||||||
}
|
}
|
||||||
|
@ -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,10 @@ 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -4,34 +4,38 @@
|
|||||||
<mat-form-field
|
<mat-form-field
|
||||||
appearance="outline"
|
appearance="outline"
|
||||||
class="w-100"
|
class="w-100"
|
||||||
[ngClass]="{ 'd-none': settings.thresholdMin === undefined }"
|
[ngClass]="{ 'd-none': !data.rule.configuration.thresholdMin }"
|
||||||
>
|
>
|
||||||
<mat-label i18n>Threshold Min</mat-label>
|
<mat-label i18n>Threshold Min</mat-label>
|
||||||
<input
|
<input
|
||||||
matInput
|
matInput
|
||||||
name="thresholdMin"
|
name="thresholdMin"
|
||||||
type="number"
|
type="number"
|
||||||
[(ngModel)]="settings.thresholdMin"
|
[(ngModel)]="data.settings.thresholdMin"
|
||||||
/>
|
/>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field
|
<mat-form-field
|
||||||
appearance="outline"
|
appearance="outline"
|
||||||
class="w-100"
|
class="w-100"
|
||||||
[ngClass]="{ 'd-none': settings.thresholdMax === undefined }"
|
[ngClass]="{ 'd-none': !data.rule.configuration.thresholdMax }"
|
||||||
>
|
>
|
||||||
<mat-label i18n>Threshold Max</mat-label>
|
<mat-label i18n>Threshold Max</mat-label>
|
||||||
<input
|
<input
|
||||||
matInput
|
matInput
|
||||||
name="thresholdMax"
|
name="thresholdMax"
|
||||||
type="number"
|
type="number"
|
||||||
[(ngModel)]="settings.thresholdMax"
|
[(ngModel)]="data.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 color="primary" mat-flat-button (click)="dialogRef.close(settings)">
|
<button
|
||||||
|
color="primary"
|
||||||
|
mat-flat-button
|
||||||
|
(click)="dialogRef.close(data.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)) {
|
@if (rule?.isActive && rule?.configuration) {
|
||||||
<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>
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import { UpdateUserSettingDto } from '@ghostfolio/api/app/user/update-user-setting.dto';
|
import { UpdateUserSettingDto } from '@ghostfolio/api/app/user/update-user-setting.dto';
|
||||||
|
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
|
||||||
import { PortfolioReportRule } from '@ghostfolio/common/interfaces';
|
import { PortfolioReportRule } from '@ghostfolio/common/interfaces';
|
||||||
|
import { XRayRulesSettings } from '@ghostfolio/common/types';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ChangeDetectionStrategy,
|
ChangeDetectionStrategy,
|
||||||
@ -10,7 +12,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 +28,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,16 +46,17 @@ 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'
|
||||||
});
|
});
|
||||||
|
|
||||||
dialogRef
|
dialogRef
|
||||||
.afterClosed()
|
.afterClosed()
|
||||||
.pipe(takeUntil(this.unsubscribeSubject))
|
.pipe(takeUntil(this.unsubscribeSubject))
|
||||||
.subscribe((settings: PortfolioReportRule['settings']) => {
|
.subscribe((settings: RuleSettings) => {
|
||||||
if (settings) {
|
if (settings) {
|
||||||
this.ruleUpdated.emit({
|
this.ruleUpdated.emit({
|
||||||
xRayRules: {
|
xRayRules: {
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
hasPermissionToUpdateUserSettings
|
hasPermissionToUpdateUserSettings
|
||||||
"
|
"
|
||||||
[rule]="rule"
|
[rule]="rule"
|
||||||
|
[settings]="settings?.[rule.key]"
|
||||||
(ruleUpdated)="onRuleUpdated($event)"
|
(ruleUpdated)="onRuleUpdated($event)"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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>
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
export interface PortfolioReportRule {
|
export interface PortfolioReportRule {
|
||||||
|
configuration?: {
|
||||||
|
threshold?: {
|
||||||
|
max: number;
|
||||||
|
min: number;
|
||||||
|
step: number;
|
||||||
|
};
|
||||||
|
thresholdMax?: boolean;
|
||||||
|
thresholdMin?: boolean;
|
||||||
|
};
|
||||||
evaluation?: string;
|
evaluation?: string;
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
key: string;
|
key: string;
|
||||||
name: string;
|
name: string;
|
||||||
settings?: {
|
|
||||||
thresholdMax?: number;
|
|
||||||
thresholdMin?: number;
|
|
||||||
};
|
|
||||||
value?: boolean;
|
value?: boolean;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
import { PortfolioReportRule } from '@ghostfolio/common/interfaces';
|
|
||||||
|
|
||||||
export type XRayRulesSettings = {
|
export type XRayRulesSettings = {
|
||||||
AccountClusterRiskCurrentInvestment?: RuleSettings;
|
AccountClusterRiskCurrentInvestment?: RuleSettings;
|
||||||
AccountClusterRiskSingleAccount?: RuleSettings;
|
AccountClusterRiskSingleAccount?: RuleSettings;
|
||||||
@ -9,6 +7,8 @@ export type XRayRulesSettings = {
|
|||||||
FeeRatioInitialInvestment?: RuleSettings;
|
FeeRatioInitialInvestment?: RuleSettings;
|
||||||
};
|
};
|
||||||
|
|
||||||
interface RuleSettings extends Pick<PortfolioReportRule, 'settings'> {
|
interface RuleSettings {
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
|
thresholdMax?: number;
|
||||||
|
thresholdMin?: number;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user