Feature/extend system message (#2628)
* Extend system message * Update changelog
This commit is contained in:
parent
3a66ccdebe
commit
12aac101bd
@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Extended the system message
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Fixed the unit for the _Zen Mode_ in the overview tab of the home page
|
- Fixed the unit for the _Zen Mode_ in the overview tab of the home page
|
||||||
|
@ -15,7 +15,6 @@ import {
|
|||||||
PROPERTY_IS_READ_ONLY_MODE,
|
PROPERTY_IS_READ_ONLY_MODE,
|
||||||
PROPERTY_SLACK_COMMUNITY_USERS,
|
PROPERTY_SLACK_COMMUNITY_USERS,
|
||||||
PROPERTY_STRIPE_CONFIG,
|
PROPERTY_STRIPE_CONFIG,
|
||||||
PROPERTY_SYSTEM_MESSAGE,
|
|
||||||
ghostfolioFearAndGreedIndexDataSource
|
ghostfolioFearAndGreedIndexDataSource
|
||||||
} from '@ghostfolio/common/config';
|
} from '@ghostfolio/common/config';
|
||||||
import {
|
import {
|
||||||
@ -58,7 +57,6 @@ export class InfoService {
|
|||||||
const platforms = await this.platformService.getPlatforms({
|
const platforms = await this.platformService.getPlatforms({
|
||||||
orderBy: { name: 'asc' }
|
orderBy: { name: 'asc' }
|
||||||
});
|
});
|
||||||
let systemMessage: string;
|
|
||||||
|
|
||||||
const globalPermissions: string[] = [];
|
const globalPermissions: string[] = [];
|
||||||
|
|
||||||
@ -104,10 +102,6 @@ export class InfoService {
|
|||||||
|
|
||||||
if (this.configurationService.get('ENABLE_FEATURE_SYSTEM_MESSAGE')) {
|
if (this.configurationService.get('ENABLE_FEATURE_SYSTEM_MESSAGE')) {
|
||||||
globalPermissions.push(permissions.enableSystemMessage);
|
globalPermissions.push(permissions.enableSystemMessage);
|
||||||
|
|
||||||
systemMessage = (await this.propertyService.getByKey(
|
|
||||||
PROPERTY_SYSTEM_MESSAGE
|
|
||||||
)) as string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const isUserSignupEnabled =
|
const isUserSignupEnabled =
|
||||||
@ -135,7 +129,6 @@ export class InfoService {
|
|||||||
platforms,
|
platforms,
|
||||||
statistics,
|
statistics,
|
||||||
subscriptions,
|
subscriptions,
|
||||||
systemMessage,
|
|
||||||
tags,
|
tags,
|
||||||
baseCurrency: DEFAULT_CURRENCY,
|
baseCurrency: DEFAULT_CURRENCY,
|
||||||
currencies: this.exchangeRateDataService.getCurrencies()
|
currencies: this.exchangeRateDataService.getCurrencies()
|
||||||
|
@ -7,9 +7,14 @@ import { TagService } from '@ghostfolio/api/services/tag/tag.service';
|
|||||||
import {
|
import {
|
||||||
DEFAULT_CURRENCY,
|
DEFAULT_CURRENCY,
|
||||||
PROPERTY_IS_READ_ONLY_MODE,
|
PROPERTY_IS_READ_ONLY_MODE,
|
||||||
|
PROPERTY_SYSTEM_MESSAGE,
|
||||||
locale
|
locale
|
||||||
} from '@ghostfolio/common/config';
|
} from '@ghostfolio/common/config';
|
||||||
import { User as IUser, UserSettings } from '@ghostfolio/common/interfaces';
|
import {
|
||||||
|
User as IUser,
|
||||||
|
SystemMessage,
|
||||||
|
UserSettings
|
||||||
|
} from '@ghostfolio/common/interfaces';
|
||||||
import {
|
import {
|
||||||
getPermissions,
|
getPermissions,
|
||||||
hasRole,
|
hasRole,
|
||||||
@ -48,6 +53,17 @@ export class UserService {
|
|||||||
orderBy: { alias: 'asc' },
|
orderBy: { alias: 'asc' },
|
||||||
where: { GranteeUser: { id } }
|
where: { GranteeUser: { id } }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let systemMessage: SystemMessage;
|
||||||
|
|
||||||
|
const systemMessageProperty = (await this.propertyService.getByKey(
|
||||||
|
PROPERTY_SYSTEM_MESSAGE
|
||||||
|
)) as SystemMessage;
|
||||||
|
|
||||||
|
if (systemMessageProperty?.targetGroups?.includes(subscription.type)) {
|
||||||
|
systemMessage = systemMessageProperty;
|
||||||
|
}
|
||||||
|
|
||||||
let tags = await this.tagService.getByUser(id);
|
let tags = await this.tagService.getByUser(id);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@ -61,6 +77,7 @@ export class UserService {
|
|||||||
id,
|
id,
|
||||||
permissions,
|
permissions,
|
||||||
subscription,
|
subscription,
|
||||||
|
systemMessage,
|
||||||
tags,
|
tags,
|
||||||
access: access.map((accessItem) => {
|
access: access.map((accessItem) => {
|
||||||
return {
|
return {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<header>
|
<header>
|
||||||
<div
|
<div
|
||||||
*ngIf="canCreateAccount || (info?.systemMessage && user)"
|
*ngIf="canCreateAccount || user?.systemMessage"
|
||||||
class="info-message-container"
|
class="info-message-container"
|
||||||
>
|
>
|
||||||
<div class="info-message-inner-container position-fixed w-100">
|
<div class="info-message-inner-container position-fixed w-100">
|
||||||
@ -19,11 +19,11 @@
|
|||||||
</div></a
|
</div></a
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
*ngIf="!canCreateAccount && info?.systemMessage && user"
|
*ngIf="!canCreateAccount && user?.systemMessage"
|
||||||
class="cursor-pointer d-inline-block info-message text-truncate"
|
class="cursor-pointer d-inline-block info-message text-truncate"
|
||||||
(click)="onShowSystemMessage()"
|
(click)="onClickSystemMessage()"
|
||||||
>
|
>
|
||||||
{{ info.systemMessage }}
|
{{ user.systemMessage.message }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -155,10 +155,7 @@ export class AppComponent implements OnDestroy, OnInit {
|
|||||||
);
|
);
|
||||||
|
|
||||||
this.hasInfoMessage =
|
this.hasInfoMessage =
|
||||||
hasPermission(
|
this.canCreateAccount || !!this.user?.systemMessage;
|
||||||
this.user?.permissions,
|
|
||||||
permissions.createUserAccount
|
|
||||||
) || !!this.info.systemMessage;
|
|
||||||
|
|
||||||
this.initializeTheme(this.user?.settings.colorScheme);
|
this.initializeTheme(this.user?.settings.colorScheme);
|
||||||
|
|
||||||
@ -166,12 +163,16 @@ export class AppComponent implements OnDestroy, OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public onCreateAccount() {
|
public onClickSystemMessage() {
|
||||||
this.tokenStorageService.signOut();
|
if (this.user.systemMessage.routerLink) {
|
||||||
|
this.router.navigate(this.user.systemMessage.routerLink);
|
||||||
|
} else {
|
||||||
|
alert(this.user.systemMessage.message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public onShowSystemMessage() {
|
public onCreateAccount() {
|
||||||
alert(this.info.systemMessage);
|
this.tokenStorageService.signOut();
|
||||||
}
|
}
|
||||||
|
|
||||||
public onSignOut() {
|
public onSignOut() {
|
||||||
|
@ -12,7 +12,12 @@ import {
|
|||||||
PROPERTY_SYSTEM_MESSAGE,
|
PROPERTY_SYSTEM_MESSAGE,
|
||||||
ghostfolioPrefix
|
ghostfolioPrefix
|
||||||
} from '@ghostfolio/common/config';
|
} from '@ghostfolio/common/config';
|
||||||
import { Coupon, InfoItem, User } from '@ghostfolio/common/interfaces';
|
import {
|
||||||
|
Coupon,
|
||||||
|
InfoItem,
|
||||||
|
SystemMessage,
|
||||||
|
User
|
||||||
|
} from '@ghostfolio/common/interfaces';
|
||||||
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
|
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
|
||||||
import {
|
import {
|
||||||
differenceInSeconds,
|
differenceInSeconds,
|
||||||
@ -39,6 +44,7 @@ export class AdminOverviewComponent implements OnDestroy, OnInit {
|
|||||||
public hasPermissionToToggleReadOnlyMode: boolean;
|
public hasPermissionToToggleReadOnlyMode: boolean;
|
||||||
public info: InfoItem;
|
public info: InfoItem;
|
||||||
public permissions = permissions;
|
public permissions = permissions;
|
||||||
|
public systemMessage: SystemMessage;
|
||||||
public transactionCount: number;
|
public transactionCount: number;
|
||||||
public userCount: number;
|
public userCount: number;
|
||||||
public user: User;
|
public user: User;
|
||||||
@ -149,7 +155,13 @@ export class AdminOverviewComponent implements OnDestroy, OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public onDeleteSystemMessage() {
|
public onDeleteSystemMessage() {
|
||||||
this.putAdminSetting({ key: PROPERTY_SYSTEM_MESSAGE, value: undefined });
|
const confirmation = confirm(
|
||||||
|
$localize`Do you really want to delete this system message?`
|
||||||
|
);
|
||||||
|
|
||||||
|
if (confirmation === true) {
|
||||||
|
this.putAdminSetting({ key: PROPERTY_SYSTEM_MESSAGE, value: undefined });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public onFlushCache() {
|
public onFlushCache() {
|
||||||
@ -184,12 +196,21 @@ export class AdminOverviewComponent implements OnDestroy, OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public onSetSystemMessage() {
|
public onSetSystemMessage() {
|
||||||
const systemMessage = prompt($localize`Please set your system message:`);
|
const systemMessage = prompt(
|
||||||
|
$localize`Please set your system message:`,
|
||||||
|
JSON.stringify(
|
||||||
|
this.systemMessage ??
|
||||||
|
<SystemMessage>{
|
||||||
|
message: '⚒️ Scheduled maintenance in progress...',
|
||||||
|
targetGroups: ['Basic', 'Premium']
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
if (systemMessage) {
|
if (systemMessage) {
|
||||||
this.putAdminSetting({
|
this.putAdminSetting({
|
||||||
key: PROPERTY_SYSTEM_MESSAGE,
|
key: PROPERTY_SYSTEM_MESSAGE,
|
||||||
value: systemMessage
|
value: JSON.parse(systemMessage)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -208,6 +229,9 @@ export class AdminOverviewComponent implements OnDestroy, OnInit {
|
|||||||
this.coupons = (settings[PROPERTY_COUPONS] as Coupon[]) ?? [];
|
this.coupons = (settings[PROPERTY_COUPONS] as Coupon[]) ?? [];
|
||||||
this.customCurrencies = settings[PROPERTY_CURRENCIES] as string[];
|
this.customCurrencies = settings[PROPERTY_CURRENCIES] as string[];
|
||||||
this.exchangeRates = exchangeRates;
|
this.exchangeRates = exchangeRates;
|
||||||
|
this.systemMessage = settings[
|
||||||
|
PROPERTY_SYSTEM_MESSAGE
|
||||||
|
] as SystemMessage;
|
||||||
this.transactionCount = transactionCount;
|
this.transactionCount = transactionCount;
|
||||||
this.userCount = userCount;
|
this.userCount = userCount;
|
||||||
this.version = version;
|
this.version = version;
|
||||||
|
@ -115,8 +115,8 @@
|
|||||||
<div *ngIf="hasPermissionForSystemMessage" class="d-flex my-3">
|
<div *ngIf="hasPermissionForSystemMessage" class="d-flex my-3">
|
||||||
<div class="w-50" i18n>System Message</div>
|
<div class="w-50" i18n>System Message</div>
|
||||||
<div class="w-50">
|
<div class="w-50">
|
||||||
<div *ngIf="info?.systemMessage">
|
<div *ngIf="systemMessage" class="align-items-center d-flex">
|
||||||
<span>{{ info.systemMessage }}</span>
|
<div class="text-truncate">{{ systemMessage | json }}</div>
|
||||||
<button
|
<button
|
||||||
class="h-100 mx-1 no-min-width px-2"
|
class="h-100 mx-1 no-min-width px-2"
|
||||||
mat-button
|
mat-button
|
||||||
@ -127,6 +127,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
*ngIf="!info?.systemMessage"
|
*ngIf="!info?.systemMessage"
|
||||||
|
class="mt-2"
|
||||||
color="accent"
|
color="accent"
|
||||||
mat-flat-button
|
mat-flat-button
|
||||||
(click)="onSetSystemMessage()"
|
(click)="onSetSystemMessage()"
|
||||||
|
@ -42,6 +42,7 @@ import type { PortfolioPerformanceResponse } from './responses/portfolio-perform
|
|||||||
import type { ScraperConfiguration } from './scraper-configuration.interface';
|
import type { ScraperConfiguration } from './scraper-configuration.interface';
|
||||||
import type { Statistics } from './statistics.interface';
|
import type { Statistics } from './statistics.interface';
|
||||||
import type { Subscription } from './subscription.interface';
|
import type { Subscription } from './subscription.interface';
|
||||||
|
import { SystemMessage } from './system-message.interface';
|
||||||
import { TabConfiguration } from './tab-configuration.interface';
|
import { TabConfiguration } from './tab-configuration.interface';
|
||||||
import type { TimelinePosition } from './timeline-position.interface';
|
import type { TimelinePosition } from './timeline-position.interface';
|
||||||
import type { UniqueAsset } from './unique-asset.interface';
|
import type { UniqueAsset } from './unique-asset.interface';
|
||||||
@ -90,6 +91,7 @@ export {
|
|||||||
ResponseError,
|
ResponseError,
|
||||||
ScraperConfiguration,
|
ScraperConfiguration,
|
||||||
Statistics,
|
Statistics,
|
||||||
|
SystemMessage,
|
||||||
Subscription,
|
Subscription,
|
||||||
TabConfiguration,
|
TabConfiguration,
|
||||||
TimelinePosition,
|
TimelinePosition,
|
||||||
|
@ -17,6 +17,5 @@ export interface InfoItem {
|
|||||||
statistics: Statistics;
|
statistics: Statistics;
|
||||||
stripePublicKey?: string;
|
stripePublicKey?: string;
|
||||||
subscriptions: { [offer in SubscriptionOffer]: Subscription };
|
subscriptions: { [offer in SubscriptionOffer]: Subscription };
|
||||||
systemMessage?: string;
|
|
||||||
tags: Tag[];
|
tags: Tag[];
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
import { SubscriptionType } from '@ghostfolio/common/types/subscription-type.type';
|
||||||
|
|
||||||
|
export interface SystemMessage {
|
||||||
|
message: string;
|
||||||
|
routerLink?: string[];
|
||||||
|
targetGroups: SubscriptionType[];
|
||||||
|
}
|
@ -2,6 +2,7 @@ import { SubscriptionOffer } from '@ghostfolio/common/types';
|
|||||||
import { SubscriptionType } from '@ghostfolio/common/types/subscription-type.type';
|
import { SubscriptionType } from '@ghostfolio/common/types/subscription-type.type';
|
||||||
import { Account, Tag } from '@prisma/client';
|
import { Account, Tag } from '@prisma/client';
|
||||||
|
|
||||||
|
import { SystemMessage } from './system-message.interface';
|
||||||
import { UserSettings } from './user-settings.interface';
|
import { UserSettings } from './user-settings.interface';
|
||||||
|
|
||||||
// TODO: Compare with UserWithSettings
|
// TODO: Compare with UserWithSettings
|
||||||
@ -14,6 +15,7 @@ export interface User {
|
|||||||
id: string;
|
id: string;
|
||||||
permissions: string[];
|
permissions: string[];
|
||||||
settings: UserSettings;
|
settings: UserSettings;
|
||||||
|
systemMessage?: SystemMessage;
|
||||||
subscription: {
|
subscription: {
|
||||||
expiresAt?: Date;
|
expiresAt?: Date;
|
||||||
offer: SubscriptionOffer;
|
offer: SubscriptionOffer;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user