diff --git a/ui-ngx/src/app/modules/home/pages/notification/sent/sent-error-dialog.component.ts b/ui-ngx/src/app/modules/home/pages/notification/sent/sent-error-dialog.component.ts
index ef5bb27610..312dd5a6fc 100644
--- a/ui-ngx/src/app/modules/home/pages/notification/sent/sent-error-dialog.component.ts
+++ b/ui-ngx/src/app/modules/home/pages/notification/sent/sent-error-dialog.component.ts
@@ -22,7 +22,7 @@ import { Router } from '@angular/router';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import {
NotificationDeliveryMethod,
- NotificationDeliveryMethodTranslateMap,
+ NotificationDeliveryMethodInfoMap,
NotificationRequest
} from '@shared/models/notification.models';
@@ -39,7 +39,7 @@ export class SentErrorDialogComponent extends DialogComponent,
protected router: Router,
diff --git a/ui-ngx/src/app/modules/home/pages/notification/sent/sent-notification-dialog.component.html b/ui-ngx/src/app/modules/home/pages/notification/sent/sent-notification-dialog.component.html
index edb294bba8..71daee5343 100644
--- a/ui-ngx/src/app/modules/home/pages/notification/sent/sent-notification-dialog.component.html
+++ b/ui-ngx/src/app/modules/home/pages/notification/sent/sent-notification-dialog.component.html
@@ -29,7 +29,7 @@
@@ -88,7 +88,7 @@
[matTooltip]="getDeliveryMethodsTooltip(deliveryMethods)"
matTooltipPosition="above">
- {{ notificationDeliveryMethodTranslateMap.get(deliveryMethods) | translate }}
+ {{ notificationDeliveryMethodInfoMap.get(deliveryMethods).name | translate }}
chevron_right
@@ -101,7 +101,7 @@
[matTooltipDisabled]="getDeliveryMethodsTemplatesControl(deliveryMethods).enabled"
matTooltipPosition="above">
- {{ notificationDeliveryMethodTranslateMap.get(deliveryMethods) | translate }}
+ {{ notificationDeliveryMethodInfoMap.get(deliveryMethods).name | translate }}
@@ -145,338 +145,16 @@
-
- {{ 'notification.delivery-method.web' | translate }}
-
- {{ 'notification.input-fields-support-templatization' | translate}}
-
-
-
-
-
- {{ 'notification.delivery-method.email' | translate }}
-
-
- {{ 'notification.input-fields-support-templatization' | translate}}
-
-
-
-
-
-
- {{ 'notification.delivery-method.sms' | translate }}
-
- {{ 'notification.input-field-support-templatization' | translate}}
-
-
-
-
-
- {{ 'notification.delivery-method.slack' | translate }}
-
- {{ 'notification.input-field-support-templatization' | translate}}
-
-
-
-
-
- {{ 'notification.delivery-method.microsoft-teams' | translate }}
-
- {{ 'notification.input-fields-support-templatization' | translate}}
-
-
-
-
-
- {{ 'notification.delivery-method.mobile-app' | translate }}
-
- {{ 'notification.input-field-support-templatization' | translate}}
-
-
-
diff --git a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.ts b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.ts
index 4d839541c8..c2d3afe890 100644
--- a/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.ts
+++ b/ui-ngx/src/app/modules/home/pages/notification/settings/notification-settings.component.ts
@@ -25,7 +25,7 @@ import { ActivatedRoute } from '@angular/router';
import { deepClone, isDefinedAndNotNull } from '@core/utils';
import {
NotificationDeliveryMethod,
- NotificationDeliveryMethodTranslateMap,
+ NotificationDeliveryMethodInfoMap,
NotificationUserSettings
} from '@shared/models/notification.models';
import { NotificationService } from '@core/http/notification.service';
@@ -41,7 +41,7 @@ export class NotificationSettingsComponent extends PageComponent implements OnIn
notificationSettings: UntypedFormGroup;
notificationDeliveryMethods: NotificationDeliveryMethod[];
- notificationDeliveryMethodTranslateMap = NotificationDeliveryMethodTranslateMap;
+ notificationDeliveryMethodInfoMap = NotificationDeliveryMethodInfoMap;
private deliveryMethods = new Set([
NotificationDeliveryMethod.SLACK,
diff --git a/ui-ngx/src/app/modules/home/pages/notification/template/notification-template-configuration.component.html b/ui-ngx/src/app/modules/home/pages/notification/template/notification-template-configuration.component.html
new file mode 100644
index 0000000000..a856f1eb7d
--- /dev/null
+++ b/ui-ngx/src/app/modules/home/pages/notification/template/notification-template-configuration.component.html
@@ -0,0 +1,398 @@
+
+
+
diff --git a/ui-ngx/src/app/modules/home/pages/notification/template/notification-template-configuration.component.scss b/ui-ngx/src/app/modules/home/pages/notification/template/notification-template-configuration.component.scss
new file mode 100644
index 0000000000..b69b950a42
--- /dev/null
+++ b/ui-ngx/src/app/modules/home/pages/notification/template/notification-template-configuration.component.scss
@@ -0,0 +1,66 @@
+/**
+ * Copyright © 2016-2024 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+:host {
+ .tb-template-header {
+ margin-bottom: 12px;
+ .tb-hint-available-params {
+ color: rgba(0,0,0,0.54);
+ letter-spacing: 0.4px;
+
+ .content {
+ vertical-align: middle;
+ }
+ }
+ }
+
+ .template-tittle {
+ gap: 12px;
+ font-weight: normal;
+ tb-icon {
+ color: rgba(0, 0, 0, .38);
+ }
+ }
+
+ .tb-mat-error {
+ font-size: 13px;
+ }
+
+ .tb-title {
+ font-size: 16px;
+ line-height: 24px;
+
+ &.tb-required::after {
+ font-size: initial;
+ content: "*";
+ }
+
+ &.tb-error {
+ color: var(--mdc-theme-error, #f44336);
+
+ &.tb-required::after {
+ color: var(--mdc-theme-error, #f44336);
+ }
+ }
+ }
+}
+
+:host ::ng-deep {
+ .tb-form-panel .mat-expansion-panel.tb-settings {
+ & > .mat-expansion-panel-content > .mat-expansion-panel-body {
+ gap: 0;
+ }
+ }
+}
diff --git a/ui-ngx/src/app/modules/home/pages/notification/template/notification-template-configuration.component.ts b/ui-ngx/src/app/modules/home/pages/notification/template/notification-template-configuration.component.ts
new file mode 100644
index 0000000000..5be07216d5
--- /dev/null
+++ b/ui-ngx/src/app/modules/home/pages/notification/template/notification-template-configuration.component.ts
@@ -0,0 +1,312 @@
+///
+/// Copyright © 2016-2024 The Thingsboard Authors
+///
+/// Licensed under the Apache License, Version 2.0 (the "License");
+/// you may not use this file except in compliance with the License.
+/// You may obtain a copy of the License at
+///
+/// http://www.apache.org/licenses/LICENSE-2.0
+///
+/// Unless required by applicable law or agreed to in writing, software
+/// distributed under the License is distributed on an "AS IS" BASIS,
+/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+/// See the License for the specific language governing permissions and
+/// limitations under the License.
+///
+
+import { Component, forwardRef, Input, OnDestroy } from '@angular/core';
+import {
+ ControlValueAccessor,
+ FormBuilder,
+ FormGroup,
+ NG_VALIDATORS,
+ NG_VALUE_ACCESSOR,
+ ValidationErrors,
+ Validator,
+ Validators
+} from '@angular/forms';
+import {
+ ActionButtonLinkType,
+ ActionButtonLinkTypeTranslateMap,
+ DeliveryMethodsTemplates,
+ NotificationDeliveryMethod,
+ NotificationDeliveryMethodInfoMap,
+ NotificationTemplateTypeTranslateMap,
+ NotificationType
+} from '@shared/models/notification.models';
+import { takeUntil } from 'rxjs/operators';
+import { Subject } from 'rxjs';
+import { isDefinedAndNotNull } from '@core/utils';
+import { coerceBoolean } from '@shared/decorators/coercion';
+
+@Component({
+ selector: 'tb-template-configuration',
+ templateUrl: './notification-template-configuration.component.html',
+ styleUrls: ['./notification-template-configuration.component.scss'],
+ providers: [
+ {
+ provide: NG_VALUE_ACCESSOR,
+ useExisting: forwardRef(() => NotificationTemplateConfigurationComponent),
+ multi: true
+ },
+ {
+ provide: NG_VALIDATORS,
+ useExisting: forwardRef(() => NotificationTemplateConfigurationComponent),
+ multi: true,
+ }
+ ]
+})
+export class NotificationTemplateConfigurationComponent implements OnDestroy, ControlValueAccessor, Validator {
+
+ templateConfigurationForm: FormGroup;
+
+ NotificationDeliveryMethodInfoMap = NotificationDeliveryMethodInfoMap;
+
+ @Input()
+ set predefinedDeliveryMethodsTemplate(value: Partial) {
+ if (isDefinedAndNotNull(value)) {
+ this.templateConfigurationForm.patchValue(value, {emitEvent: false});
+ this.updateDisabledForms();
+ this.templateConfigurationForm.updateValueAndValidity();
+ }
+ }
+
+ @Input()
+ notificationType: NotificationType;
+
+ @Input()
+ @coerceBoolean()
+ interacted: boolean;
+
+ readonly NotificationDeliveryMethod = NotificationDeliveryMethod;
+ readonly NotificationTemplateTypeTranslateMap = NotificationTemplateTypeTranslateMap;
+
+ readonly actionButtonLinkType = ActionButtonLinkType;
+ readonly actionButtonLinkTypes = Object.keys(ActionButtonLinkType) as ActionButtonLinkType[];
+ readonly actionButtonLinkTypeTranslateMap = ActionButtonLinkTypeTranslateMap;
+
+ tinyMceOptions: Record = {
+ base_url: '/assets/tinymce',
+ suffix: '.min',
+ plugins: ['link table image imagetools code fullscreen'],
+ menubar: 'edit insert tools view format table',
+ toolbar: 'fontselect fontsizeselect | formatselect | bold italic strikethrough forecolor backcolor ' +
+ '| link | table | image | alignleft aligncenter alignright alignjustify ' +
+ '| numlist bullist outdent indent | removeformat | code | fullscreen',
+ toolbar_mode: 'sliding',
+ height: 400,
+ autofocus: false,
+ branding: false
+ };
+
+ private propagateChange = (v: any) => { };
+ private readonly destroy$ = new Subject();
+
+ constructor(private fb: FormBuilder) {
+ this.templateConfigurationForm = this.buildForm();
+ this.templateConfigurationForm.valueChanges.pipe(
+ takeUntil(this.destroy$)
+ ).subscribe((value) => {
+ this.propagateChange(value);
+ });
+ }
+
+ ngOnDestroy() {
+ this.destroy$.next();
+ this.destroy$.complete();
+ }
+
+ writeValue(value: any) {
+ this.templateConfigurationForm.patchValue(value, {emitEvent: false});
+ }
+
+ registerOnChange(fn: any): void {
+ this.propagateChange = fn;
+ }
+
+ registerOnTouched(fn: any): void {
+ }
+
+ setDisabledState(isDisabled: boolean) {
+ if (isDisabled) {
+ this.templateConfigurationForm.disable({emitEvent: false});
+ } else {
+ this.updateDisabledForms();
+ }
+ }
+
+ validate(): ValidationErrors {
+ return this.templateConfigurationForm.valid ? null : {
+ templateConfiguration: {
+ valid: false,
+ },
+ };
+ }
+
+ private updateDisabledForms(){
+ Object.values(NotificationDeliveryMethod).forEach((method) => {
+ const form = this.templateConfigurationForm.get(method);
+ if (!form.get('enabled').value) {
+ form.disable({emitEvent: false});
+ } else {
+ form.enable({emitEvent: false});
+ switch (method) {
+ case NotificationDeliveryMethod.WEB:
+ form.get('additionalConfig.icon.enabled').updateValueAndValidity({onlySelf: true});
+ form.get('additionalConfig.actionButtonConfig.enabled').updateValueAndValidity({onlySelf: true});
+ break;
+ case NotificationDeliveryMethod.MICROSOFT_TEAMS:
+ form.get('button.enabled').updateValueAndValidity({onlySelf: true});
+ break;
+ case NotificationDeliveryMethod.MOBILE_APP:
+ form.get('additionalConfig.onClick.enabled').updateValueAndValidity({onlySelf: true});
+ }
+ }
+ });
+ }
+
+ private buildForm(): FormGroup {
+ const form = this.fb.group({});
+
+ Object.values(NotificationDeliveryMethod).forEach((method) => {
+ form.addControl(method, this.buildDeliveryMethodControl(method), {emitEvent: false});
+ });
+
+ return form;
+ }
+
+ private buildDeliveryMethodControl(deliveryMethod: NotificationDeliveryMethod): FormGroup {
+ let deliveryMethodForm: FormGroup;
+ switch (deliveryMethod) {
+ case NotificationDeliveryMethod.WEB:
+ deliveryMethodForm = this.fb.group({
+ subject: ['', Validators.required],
+ body: ['', Validators.required],
+ additionalConfig: this.fb.group({
+ icon: this.fb.group({
+ enabled: [false],
+ icon: [{value: 'notifications', disabled: true}, Validators.required],
+ color: [{value: '#757575', disabled: true}]
+ }),
+ actionButtonConfig: this.createButtonConfigForm()
+ })
+ });
+
+ deliveryMethodForm.get('additionalConfig.icon.enabled').valueChanges.pipe(
+ takeUntil(this.destroy$)
+ ).subscribe((value) => {
+ if (value) {
+ deliveryMethodForm.get('additionalConfig.icon.icon').enable({emitEvent: false});
+ deliveryMethodForm.get('additionalConfig.icon.color').enable({emitEvent: false});
+ } else {
+ deliveryMethodForm.get('additionalConfig.icon.icon').disable({emitEvent: false});
+ deliveryMethodForm.get('additionalConfig.icon.color').disable({emitEvent: false});
+ }
+ });
+ break;
+ case NotificationDeliveryMethod.EMAIL:
+ deliveryMethodForm = this.fb.group({
+ subject: ['', Validators.required],
+ body: ['', Validators.required]
+ });
+ break;
+ case NotificationDeliveryMethod.SMS:
+ deliveryMethodForm = this.fb.group({
+ body: ['', [Validators.required, Validators.maxLength(320)]]
+ });
+ break;
+ case NotificationDeliveryMethod.SLACK:
+ deliveryMethodForm = this.fb.group({
+ body: ['', Validators.required]
+ });
+ break;
+ case NotificationDeliveryMethod.MOBILE_APP:
+ deliveryMethodForm = this.fb.group({
+ subject: ['', Validators.required],
+ body: ['', Validators.required],
+ additionalConfig: this.fb.group({
+ onClick: this.fb.group({
+ enabled: [false],
+ linkType: [{value: ActionButtonLinkType.DASHBOARD, disabled: true}],
+ dashboardId: [{value: null, disabled: true}, Validators.required],
+ dashboardState: [{value: null, disabled: true}],
+ setEntityIdInState: [{value: true, disabled: true}]
+ })
+ })
+ });
+ deliveryMethodForm.get('additionalConfig.onClick.enabled').valueChanges.pipe(
+ takeUntil(this.destroy$)
+ ).subscribe((value) => {
+ if (value) {
+ deliveryMethodForm.get('additionalConfig.onClick.linkType').enable({emitEvent: false});
+ deliveryMethodForm.get('additionalConfig.onClick.dashboardId').enable({emitEvent: false});
+ deliveryMethodForm.get('additionalConfig.onClick.dashboardState').enable({emitEvent: false});
+ deliveryMethodForm.get('additionalConfig.onClick.setEntityIdInState').enable({emitEvent: false});
+ } else {
+ deliveryMethodForm.get('additionalConfig.onClick.linkType').disable({emitEvent: false});
+ deliveryMethodForm.get('additionalConfig.onClick.dashboardId').disable({emitEvent: false});
+ deliveryMethodForm.get('additionalConfig.onClick.dashboardState').disable({emitEvent: false});
+ deliveryMethodForm.get('additionalConfig.onClick.setEntityIdInState').disable({emitEvent: false});
+ }
+ });
+ break;
+ case NotificationDeliveryMethod.MICROSOFT_TEAMS:
+ deliveryMethodForm = this.fb.group({
+ subject: [''],
+ body: ['', Validators.required],
+ themeColor: [''],
+ button: this.createButtonConfigForm()
+ });
+ break;
+ default:
+ throw new Error(`Not configured templated for notification delivery method: ${deliveryMethod}`);
+ }
+ deliveryMethodForm.addControl('enabled', this.fb.control(false), {emitEvent: false});
+ deliveryMethodForm.addControl('method', this.fb.control(deliveryMethod), {emitEvent: false});
+ return deliveryMethodForm;
+ }
+
+ private createButtonConfigForm(): FormGroup {
+ const form = this.fb.group({
+ enabled: [false],
+ text: [{value: '', disabled: true}, [Validators.required, Validators.maxLength(50)]],
+ linkType: [ActionButtonLinkType.LINK],
+ link: [{value: '', disabled: true}, Validators.required],
+ dashboardId: [{value: null, disabled: true}, Validators.required],
+ dashboardState: [{value: null, disabled: true}],
+ setEntityIdInState: [{value: true, disabled: true}]
+ });
+
+ form.get('enabled').valueChanges.pipe(
+ takeUntil(this.destroy$)
+ ).subscribe((value) => {
+ if (value) {
+ form.enable({emitEvent: false});
+ form.get('linkType').updateValueAndValidity({onlySelf: true});
+ } else {
+ form.disable({emitEvent: false});
+ form.get('enabled').enable({emitEvent: false});
+ }
+ });
+
+ form.get('linkType').valueChanges.pipe(
+ takeUntil(this.destroy$)
+ ).subscribe((value) => {
+ const isEnabled = form.get('enabled').value;
+ if (isEnabled) {
+ if (value === ActionButtonLinkType.LINK) {
+ form.get('link').enable({emitEvent: false});
+ form.get('dashboardId').disable({emitEvent: false});
+ form.get('dashboardState').disable({emitEvent: false});
+ form.get('setEntityIdInState').disable({emitEvent: false});
+ } else {
+ form.get('link').disable({emitEvent: false});
+ form.get('dashboardId').enable({emitEvent: false});
+ form.get('dashboardState').enable({emitEvent: false});
+ form.get('setEntityIdInState').enable({emitEvent: false});
+ }
+ }
+ });
+ return form;
+ }
+}
diff --git a/ui-ngx/src/app/modules/home/pages/notification/template/template-configuration.ts b/ui-ngx/src/app/modules/home/pages/notification/template/template-configuration.ts
index a53a3eada5..3da842661d 100644
--- a/ui-ngx/src/app/modules/home/pages/notification/template/template-configuration.ts
+++ b/ui-ngx/src/app/modules/home/pages/notification/template/template-configuration.ts
@@ -16,10 +16,9 @@
import { FormBuilder, FormGroup, ValidationErrors, Validators } from '@angular/forms';
import {
- ActionButtonLinkType,
- ActionButtonLinkTypeTranslateMap,
+ DeliveryMethodsTemplates,
NotificationDeliveryMethod,
- NotificationDeliveryMethodTranslateMap,
+ NotificationDeliveryMethodInfoMap,
NotificationTemplate,
NotificationTemplateTypeTranslateMap,
NotificationType
@@ -27,47 +26,25 @@ import {
import { takeUntil } from 'rxjs/operators';
import { Subject } from 'rxjs';
import { Directive, OnDestroy } from '@angular/core';
+import { deepClone, deepTrim } from '@core/utils';
import { DialogComponent } from '@shared/components/dialog.component';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { Router } from '@angular/router';
import { MatDialogRef } from '@angular/material/dialog';
-import { deepClone, deepTrim } from '@core/utils';
-import tinymce from 'tinymce';
@Directive()
// tslint:disable-next-line:directive-class-suffix
export abstract class TemplateConfiguration extends DialogComponent implements OnDestroy{
templateNotificationForm: FormGroup;
- webTemplateForm: FormGroup;
- emailTemplateForm: FormGroup;
- smsTemplateForm: FormGroup;
- slackTemplateForm: FormGroup;
- microsoftTeamsTemplateForm: FormGroup;
- mobileTemplateForm: FormGroup;
+ notificationTemplateConfigurationForm: FormGroup;
notificationDeliveryMethods = Object.keys(NotificationDeliveryMethod) as NotificationDeliveryMethod[];
- notificationDeliveryMethodTranslateMap = NotificationDeliveryMethodTranslateMap;
+ notificationDeliveryMethodInfoMap = NotificationDeliveryMethodInfoMap;
notificationTemplateTypeTranslateMap = NotificationTemplateTypeTranslateMap;
- actionButtonLinkType = ActionButtonLinkType;
- actionButtonLinkTypes = Object.keys(ActionButtonLinkType) as ActionButtonLinkType[];
- actionButtonLinkTypeTranslateMap = ActionButtonLinkTypeTranslateMap;
-
- tinyMceOptions: Record = {
- base_url: '/assets/tinymce',
- suffix: '.min',
- plugins: ['link table image imagetools code fullscreen'],
- menubar: 'edit insert tools view format table',
- toolbar: 'fontselect fontsizeselect | formatselect | bold italic strikethrough forecolor backcolor ' +
- '| link | table | image | alignleft aligncenter alignright alignjustify ' +
- '| numlist bullist outdent indent | removeformat | code | fullscreen',
- toolbar_mode: 'sliding',
- height: 400,
- autofocus: false,
- branding: false
- };
+ deliveryConfiguration: Partial;
protected readonly destroy$ = new Subject();
@@ -87,69 +64,22 @@ export abstract class TemplateConfiguration extends DialogComponent<
})
});
- this.notificationDeliveryMethods.forEach(method => {
- (this.templateNotificationForm.get('configuration.deliveryMethodsTemplates') as FormGroup)
- .addControl(method, this.fb.group({enabled: method === NotificationDeliveryMethod.WEB}), {emitEvent: false});
- });
-
- this.webTemplateForm = this.fb.group({
- subject: ['', Validators.required],
- body: ['', Validators.required],
- additionalConfig: this.fb.group({
- icon: this.fb.group({
- enabled: [false],
- icon: [{value: 'notifications', disabled: true}, Validators.required],
- color: [{value: '#757575', disabled: true}]
- }),
- actionButtonConfig: this.createButtonConfigForm()
- })
- });
-
- this.webTemplateForm.get('additionalConfig.icon.enabled').valueChanges.pipe(
+ this.templateNotificationForm.get('configuration.deliveryMethodsTemplates').valueChanges.pipe(
takeUntil(this.destroy$)
).subscribe((value) => {
- if (value) {
- this.webTemplateForm.get('additionalConfig.icon.icon').enable({emitEvent: false});
- this.webTemplateForm.get('additionalConfig.icon.color').enable({emitEvent: false});
- } else {
- this.webTemplateForm.get('additionalConfig.icon.icon').disable({emitEvent: false});
- this.webTemplateForm.get('additionalConfig.icon.color').disable({emitEvent: false});
- }
+ this.deliveryConfiguration = value;
});
- this.emailTemplateForm = this.fb.group({
- subject: ['', Validators.required],
- body: ['', Validators.required]
+ this.notificationTemplateConfigurationForm = this.fb.group({
+ deliveryMethodsTemplates: null
});
- this.smsTemplateForm = this.fb.group({
- body: ['', [Validators.required, Validators.maxLength(320)]]
- });
-
- this.slackTemplateForm = this.fb.group({
- body: ['', Validators.required]
- });
-
- this.mobileTemplateForm = this.fb.group({
- subject: ['', Validators.required],
- body: ['', Validators.required]
- });
-
- this.microsoftTeamsTemplateForm = this.fb.group({
- subject: [''],
- body: ['', Validators.required],
- themeColor: [''],
- button: this.createButtonConfigForm()
+ this.notificationDeliveryMethods.forEach(method => {
+ (this.templateNotificationForm.get('configuration.deliveryMethodsTemplates') as FormGroup)
+ .addControl(method, this.fb.group({enabled: method === NotificationDeliveryMethod.WEB}), {emitEvent: false});
});
- this.deliveryMethodFormsMap = new Map([
- [NotificationDeliveryMethod.WEB, this.webTemplateForm],
- [NotificationDeliveryMethod.EMAIL, this.emailTemplateForm],
- [NotificationDeliveryMethod.SMS, this.smsTemplateForm],
- [NotificationDeliveryMethod.SLACK, this.slackTemplateForm],
- [NotificationDeliveryMethod.MICROSOFT_TEAMS, this.microsoftTeamsTemplateForm],
- [NotificationDeliveryMethod.MOBILE_APP, this.mobileTemplateForm]
- ]);
+ this.deliveryConfiguration = this.templateNotificationForm.get('configuration.deliveryMethodsTemplates').value;
}
ngOnDestroy() {
@@ -169,58 +99,8 @@ export abstract class TemplateConfiguration extends DialogComponent<
}
protected getNotificationTemplateValue(): NotificationTemplate {
- const template: NotificationTemplate = deepClone(this.templateNotificationForm.value);
- this.notificationDeliveryMethods.forEach(method => {
- if (template.configuration.deliveryMethodsTemplates[method]?.enabled) {
- Object.assign(template.configuration.deliveryMethodsTemplates[method], this.deliveryMethodFormsMap.get(method).value, {method});
- } else {
- delete template.configuration.deliveryMethodsTemplates[method];
- }
- });
+ const template = deepClone(this.templateNotificationForm.value);
+ template.configuration = deepClone(this.notificationTemplateConfigurationForm.value);
return deepTrim(template);
}
-
- private createButtonConfigForm(): FormGroup {
- const form = this.fb.group({
- enabled: [false],
- text: [{value: '', disabled: true}, [Validators.required, Validators.maxLength(50)]],
- linkType: [ActionButtonLinkType.LINK],
- link: [{value: '', disabled: true}, Validators.required],
- dashboardId: [{value: null, disabled: true}, Validators.required],
- dashboardState: [{value: null, disabled: true}],
- setEntityIdInState: [{value: true, disabled: true}],
- });
-
- form.get('enabled').valueChanges.pipe(
- takeUntil(this.destroy$)
- ).subscribe((value) => {
- if (value) {
- form.enable({emitEvent: false});
- form.get('linkType').updateValueAndValidity({onlySelf: true});
- } else {
- form.disable({emitEvent: false});
- form.get('enabled').enable({emitEvent: false});
- }
- });
-
- form.get('linkType').valueChanges.pipe(
- takeUntil(this.destroy$)
- ).subscribe((value) => {
- const isEnabled = form.get('enabled').value;
- if (isEnabled) {
- if (value === ActionButtonLinkType.LINK) {
- form.get('link').enable({emitEvent: false});
- form.get('dashboardId').disable({emitEvent: false});
- form.get('dashboardState').disable({emitEvent: false});
- form.get('setEntityIdInState').disable({emitEvent: false});
- } else {
- form.get('link').disable({emitEvent: false});
- form.get('dashboardId').enable({emitEvent: false});
- form.get('dashboardState').enable({emitEvent: false});
- form.get('setEntityIdInState').enable({emitEvent: false});
- }
- }
- });
- return form;
- }
}
diff --git a/ui-ngx/src/app/modules/home/pages/notification/template/template-notification-dialog.component.html b/ui-ngx/src/app/modules/home/pages/notification/template/template-notification-dialog.component.html
index 3df482f633..09e673bb4b 100644
--- a/ui-ngx/src/app/modules/home/pages/notification/template/template-notification-dialog.component.html
+++ b/ui-ngx/src/app/modules/home/pages/notification/template/template-notification-dialog.component.html
@@ -29,14 +29,14 @@
check
- {{ 'notification.basic-settings' | translate }}
+ {{ 'notification.setup' | translate }}
notification.name
@@ -62,339 +62,22 @@
class="delivery-method-container"
[formGroupName]="deliveryMethods">
- {{ notificationDeliveryMethodTranslateMap.get(deliveryMethods) | translate }}
+ {{ notificationDeliveryMethodInfoMap.get(deliveryMethods).name | translate }}
-
- {{ 'notification.delivery-method.web' | translate }}
-
- {{ 'notification.input-fields-support-templatization' | translate}}
-
-
-
-
- notification.subject
-
-
- {{ 'notification.subject-required' | translate }}
-
-
-
- notification.message
-
-
- {{ 'notification.message-required' | translate }}
-
-
-
-
-
-
- {{ 'notification.delivery-method.email' | translate }}
-
-
- {{ 'notification.input-fields-support-templatization' | translate}}
-
-
-
-
- notification.subject
-
-
- {{ 'notification.subject-required' | translate }}
-
-
- notification.message
-
-
- {{ 'notification.message-required' | translate }}
-
-
-
-
-
- {{ 'notification.delivery-method.sms' | translate }}
-
- {{ 'notification.input-field-support-templatization' | translate}}
-
-
-
-
- notification.message
-
-
- {{ 'notification.message-required' | translate }}
-
-
- {{ 'notification.message-max-length' | translate :
- {length: smsTemplateForm.get('body').getError('maxlength').requiredLength}
- }}
-
-
-
-
-
- {{ 'notification.delivery-method.slack' | translate }}
-
- {{ 'notification.input-field-support-templatization' | translate}}
-
-
-
-
- notification.message
-
-
- {{ 'notification.message-required' | translate }}
-
-
-
-
-
- {{ 'notification.delivery-method.microsoft-teams' | translate }}
-
- {{ 'notification.input-fields-support-templatization' | translate}}
-
-
-
-
- notification.subject
-
-
-
- notification.message
-
-
- {{ 'notification.message-required' | translate }}
-
-
-
-
-
-
- {{ 'notification.delivery-method.mobile-app' | translate }}
-
- {{ 'notification.input-field-support-templatization' | translate}}
-
-
-
-
- notification.subject
-
-
- {{ 'notification.subject-required' | translate }}
-
-
-
- notification.message
-
-
- {{ 'notification.message-required' | translate }}
-
-
+
+ {{ 'notification.compose' | translate }}
+
+
+
diff --git a/ui-ngx/src/app/modules/home/pages/notification/template/template-notification-dialog.component.scss b/ui-ngx/src/app/modules/home/pages/notification/template/template-notification-dialog.component.scss
index 51afcfbe33..0e28d5d5e3 100644
--- a/ui-ngx/src/app/modules/home/pages/notification/template/template-notification-dialog.component.scss
+++ b/ui-ngx/src/app/modules/home/pages/notification/template/template-notification-dialog.component.scss
@@ -17,7 +17,7 @@
@import "../../../../../../theme";
:host {
- width: 840px;
+ width: 775px;
height: 100%;
max-width: 100%;
max-height: 100vh;
@@ -62,25 +62,10 @@
}
}
- .tb-mat-error {
- font-size: 13px;
- }
-
.tb-hint {
padding: 0 0 8px;
}
- .tb-hint-available-params {
- border-radius: 6px;
- background-color: rgba(48, 86, 128, 0.04);
- margin-bottom: 8px;
- padding: 8px 16px;
-
- .content {
- vertical-align: middle;
- }
- }
-
.delivery-methods-container {
margin-bottom: 20px;
display: flex;
@@ -125,13 +110,5 @@
}
}
}
-
- .tb-form-panel .mat-expansion-panel.tb-settings {
- padding: 11px 16px;
-
- & > .mat-expansion-panel-content > .mat-expansion-panel-body {
- gap: 0;
- }
- }
}
}
diff --git a/ui-ngx/src/app/modules/home/pages/notification/template/template-notification-dialog.component.ts b/ui-ngx/src/app/modules/home/pages/notification/template/template-notification-dialog.component.ts
index cda2309ffd..a2d62c023a 100644
--- a/ui-ngx/src/app/modules/home/pages/notification/template/template-notification-dialog.component.ts
+++ b/ui-ngx/src/app/modules/home/pages/notification/template/template-notification-dialog.component.ts
@@ -14,13 +14,13 @@
/// limitations under the License.
///
-import { NotificationDeliveryMethod, NotificationTemplate, NotificationType } from '@shared/models/notification.models';
+import { NotificationTemplate, NotificationType } from '@shared/models/notification.models';
import { Component, Inject, OnDestroy, ViewChild } from '@angular/core';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { Router } from '@angular/router';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
-import { FormBuilder } from '@angular/forms';
+import { FormBuilder, FormGroup } from '@angular/forms';
import { NotificationService } from '@core/http/notification.service';
import { deepClone, isDefinedAndNotNull } from '@core/utils';
import { Observable } from 'rxjs';
@@ -31,8 +31,7 @@ import { BreakpointObserver } from '@angular/cdk/layout';
import { MediaBreakpoints } from '@shared/models/constants';
import { TranslateService } from '@ngx-translate/core';
import { TemplateConfiguration } from '@home/pages/notification/template/template-configuration';
-import { AuthState } from '@core/auth/auth.models';
-import { getCurrentAuthState } from '@core/auth/auth.selectors';
+import { getCurrentAuthUser } from '@core/auth/auth.selectors';
import { AuthUser } from '@shared/models/user.model';
import { Authority } from '@shared/models/authority.enum';
@@ -62,9 +61,10 @@ export class TemplateNotificationDialogComponent
selectedIndex = 0;
hideSelectType = false;
+ notificationTemplateConfigurationForm: FormGroup;
+
private readonly templateNotification: NotificationTemplate;
- private authState: AuthState = getCurrentAuthState(this.store);
- private authUser: AuthUser = this.authState.authUser;
+ private authUser: AuthUser = getCurrentAuthUser(this.store);
constructor(protected store: Store ,
protected router: Router,
@@ -78,7 +78,7 @@ export class TemplateNotificationDialogComponent
this.notificationTypes = this.allowNotificationType();
- this.stepperOrientation = this.breakpointObserver.observe(MediaBreakpoints['gt-sm'])
+ this.stepperOrientation = this.breakpointObserver.observe(MediaBreakpoints['gt-xs'])
.pipe(map(({matches}) => matches ? 'horizontal' : 'vertical'));
if (isDefinedAndNotNull(this.data?.predefinedType)) {
@@ -99,11 +99,9 @@ export class TemplateNotificationDialogComponent
}
this.templateNotificationForm.reset({}, {emitEvent: false});
this.templateNotificationForm.patchValue(this.templateNotification, {emitEvent: false});
- // eslint-disable-next-line guard-for-in
- for (const method in this.templateNotification.configuration.deliveryMethodsTemplates) {
- this.deliveryMethodFormsMap.get(NotificationDeliveryMethod[method])
- .patchValue(this.templateNotification.configuration.deliveryMethodsTemplates[method]);
- }
+ this.notificationTemplateConfigurationForm.patchValue({
+ deliveryMethodsTemplates: this.templateNotification.configuration.deliveryMethodsTemplates
+ }, {emitEvent: false});
}
}
@@ -119,6 +117,9 @@ export class TemplateNotificationDialogComponent
changeStep($event: StepperSelectionEvent) {
this.selectedIndex = $event.selectedIndex;
+ if ($event.previouslySelectedIndex > $event.selectedIndex) {
+ $event.previouslySelectedStep.interacted = false;
+ }
}
backStep() {
diff --git a/ui-ngx/src/app/shared/components/notification/template-autocomplete.component.html b/ui-ngx/src/app/shared/components/notification/template-autocomplete.component.html
index 4298cef045..97a17f07a2 100644
--- a/ui-ngx/src/app/shared/components/notification/template-autocomplete.component.html
+++ b/ui-ngx/src/app/shared/components/notification/template-autocomplete.component.html
@@ -51,7 +51,7 @@
- {{ notificationDeliveryMethodTranslateMap.get(method.key) | translate }}
+ {{ notificationDeliveryMethodInfoMap.get(method.key).name | translate }}
diff --git a/ui-ngx/src/app/shared/components/notification/template-autocomplete.component.ts b/ui-ngx/src/app/shared/components/notification/template-autocomplete.component.ts
index 9c83b3443c..12fcae7693 100644
--- a/ui-ngx/src/app/shared/components/notification/template-autocomplete.component.ts
+++ b/ui-ngx/src/app/shared/components/notification/template-autocomplete.component.ts
@@ -28,7 +28,7 @@ import { PageLink } from '@shared/models/page/page-link';
import { Direction } from '@shared/models/page/sort-order';
import { emptyPageData } from '@shared/models/page/page-data';
import {
- NotificationDeliveryMethodTranslateMap,
+ NotificationDeliveryMethodInfoMap,
NotificationTemplate,
NotificationType
} from '@shared/models/notification.models';
@@ -55,7 +55,7 @@ import { coerceBoolean } from '@shared/decorators/coercion';
})
export class TemplateAutocompleteComponent implements ControlValueAccessor, OnInit {
- notificationDeliveryMethodTranslateMap = NotificationDeliveryMethodTranslateMap;
+ notificationDeliveryMethodInfoMap = NotificationDeliveryMethodInfoMap;
selectTemplateFormGroup: FormGroup;
@Input()
diff --git a/ui-ngx/src/app/shared/components/slack-conversation-autocomplete.component.ts b/ui-ngx/src/app/shared/components/slack-conversation-autocomplete.component.ts
index 0d73933c8f..39da44a13c 100644
--- a/ui-ngx/src/app/shared/components/slack-conversation-autocomplete.component.ts
+++ b/ui-ngx/src/app/shared/components/slack-conversation-autocomplete.component.ts
@@ -24,11 +24,7 @@ import { TranslateService } from '@ngx-translate/core';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { EntityService } from '@core/http/entity.service';
import { TruncatePipe } from '@shared/pipe/truncate.pipe';
-import {
- NotificationDeliveryMethodTranslateMap,
- SlackChanelType,
- SlackConversation
-} from '@shared/models/notification.models';
+import { SlackChanelType, SlackConversation } from '@shared/models/notification.models';
import { NotificationService } from '@core/http/notification.service';
import { isEqual } from '@core/utils';
@@ -44,7 +40,6 @@ import { isEqual } from '@core/utils';
})
export class SlackConversationAutocompleteComponent implements ControlValueAccessor, OnInit, OnChanges {
- notificationDeliveryMethodTranslateMap = NotificationDeliveryMethodTranslateMap;
conversationSlackFormGroup: FormGroup;
@Input()
diff --git a/ui-ngx/src/app/shared/models/notification.models.ts b/ui-ngx/src/app/shared/models/notification.models.ts
index 4d352d352d..44451bc800 100644
--- a/ui-ngx/src/app/shared/models/notification.models.ts
+++ b/ui-ngx/src/app/shared/models/notification.models.ts
@@ -311,9 +311,11 @@ export interface NotificationTemplate extends Omit([
- [NotificationDeliveryMethod.WEB, 'notification.delivery-method.web'],
- [NotificationDeliveryMethod.SMS, 'notification.delivery-method.sms'],
- [NotificationDeliveryMethod.EMAIL, 'notification.delivery-method.email'],
- [NotificationDeliveryMethod.SLACK, 'notification.delivery-method.slack'],
- [NotificationDeliveryMethod.MOBILE_APP, 'notification.delivery-method.mobile-app'],
- [NotificationDeliveryMethod.MICROSOFT_TEAMS, 'notification.delivery-method.microsoft-teams']
+export const NotificationDeliveryMethodInfoMap = new Map([
+ [NotificationDeliveryMethod.WEB,
+ {
+ name: 'notification.delivery-method.web',
+ icon: 'mdi:bell-badge'
+ }
+ ],
+ [NotificationDeliveryMethod.SMS,
+ {
+ name: 'notification.delivery-method.sms',
+ icon: 'mdi:message-processing'
+ }
+ ],
+ [NotificationDeliveryMethod.EMAIL,
+ {
+ name: 'notification.delivery-method.email',
+ icon: 'mdi:email'
+ }],
+ [NotificationDeliveryMethod.SLACK,
+ {
+ name: 'notification.delivery-method.slack',
+ icon: 'mdi:slack'
+ }
+ ],
+ [NotificationDeliveryMethod.MOBILE_APP,
+ {
+ name: 'notification.delivery-method.mobile-app',
+ icon: 'mdi:cellphone-text'
+ }],
+ [NotificationDeliveryMethod.MICROSOFT_TEAMS,
+ {
+ name: 'notification.delivery-method.microsoft-teams',
+ icon: 'mdi:microsoft-teams'
+ }]
]);
export enum NotificationRequestStatus {
diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json
index 47d6d97556..f22a599aa8 100644
--- a/ui-ngx/src/assets/locale/locale.constant-en_US.json
+++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json
@@ -3233,7 +3233,6 @@
"new-platform-version-trigger-settings": "New platform version trigger settings",
"rate-limits-trigger-settings": "Exceeded rate limits trigger settings",
"at-least-one-should-be-selected": "At least one should be selected",
- "basic-settings": "Basic settings",
"button-text": "Button text",
"button-text-required": "Button text is required",
"button-text-max-length": "Button text should be less than or equal to {{ length }} characters",
@@ -3245,6 +3244,7 @@
"copy-template": "Copy template",
"create-new": "Create new",
"created": "Created",
+ "customize-messages": "Customize messages",
"delete-notification-text": "Be careful, after the confirmation the notification will become unrecoverable.",
"delete-notification-title": "Are you sure you want to delete the notification?",
"delete-notifications-text": "Be careful, after the confirmation notifications will become unrecoverable.",
@@ -3353,6 +3353,7 @@
"notify-only-user-comments": "Notify only user comments",
"only-rule-chain-lifecycle-failures": "Only rule chain lifecycle failures",
"only-rule-node-lifecycle-failures": "Only rule node lifecycle failures",
+ "open-dashboard-on-click-notification": "Open dashboard on click notification",
"platform-users": "Platform users",
"rate-limits": "Rate limits",
"rate-limits-hint": "If the field is empty, the trigger will be applied to all rate limits",
@@ -3405,6 +3406,7 @@
"selected-template": "{ count, plural, =1 {1 template} other {# templates} } selected",
"send-notification": "Send notification",
"sent": "Sent",
+ "setup": "Setup",
"notification-sent": "Notifications / Sent",
"set-entity-from-notification": "Set entity from notification to dashboard state",
"slack-chanel-type": "Slack channel type",
|