diff --git a/ui-ngx/src/app/modules/home/pages/notification/notification.module.ts b/ui-ngx/src/app/modules/home/pages/notification/notification.module.ts
index 5e29010035..e5588ecf31 100644
--- a/ui-ngx/src/app/modules/home/pages/notification/notification.module.ts
+++ b/ui-ngx/src/app/modules/home/pages/notification/notification.module.ts
@@ -39,7 +39,12 @@ import { NotificationSettingsComponent } from '@home/pages/notification/settings
import {
NotificationSettingFormComponent
} from '@home/pages/notification/settings/notification-setting-form.component';
-import { NotificationTemplateConfigurationComponent } from '@home/pages/notification/template/notification-template-configuration.component';
+import {
+ NotificationTemplateConfigurationComponent
+} from '@home/pages/notification/template/configuration/notification-template-configuration.component';
+import {
+ NotificationActionButtonConfigurationComponent
+} from '@home/pages/notification/template/configuration/notification-action-button-configuration.component';
@NgModule({
declarations: [
@@ -57,7 +62,8 @@ import { NotificationTemplateConfigurationComponent } from '@home/pages/notifica
RuleTableHeaderComponent,
NotificationSettingsComponent,
NotificationSettingFormComponent,
- NotificationTemplateConfigurationComponent
+ NotificationTemplateConfigurationComponent,
+ NotificationActionButtonConfigurationComponent
],
imports: [
CommonModule,
diff --git a/ui-ngx/src/app/modules/home/pages/notification/sent/sent-notification-dialog.component.scss b/ui-ngx/src/app/modules/home/pages/notification/sent/sent-notification-dialog.component.scss
index 8a42cc47b0..1dfbd7518b 100644
--- a/ui-ngx/src/app/modules/home/pages/notification/sent/sent-notification-dialog.component.scss
+++ b/ui-ngx/src/app/modules/home/pages/notification/sent/sent-notification-dialog.component.scss
@@ -16,7 +16,7 @@
@import "../../../../../../scss/constants";
:host {
- width: 775px;
+ width: 850px;
height: 100%;
max-width: 100%;
max-height: 100vh;
diff --git a/ui-ngx/src/app/modules/home/pages/notification/template/configuration/notification-action-button-configuration.component.html b/ui-ngx/src/app/modules/home/pages/notification/template/configuration/notification-action-button-configuration.component.html
new file mode 100644
index 0000000000..b195775d48
--- /dev/null
+++ b/ui-ngx/src/app/modules/home/pages/notification/template/configuration/notification-action-button-configuration.component.html
@@ -0,0 +1,83 @@
+
+
diff --git a/ui-ngx/src/app/modules/home/pages/notification/template/configuration/notification-action-button-configuration.component.ts b/ui-ngx/src/app/modules/home/pages/notification/template/configuration/notification-action-button-configuration.component.ts
new file mode 100644
index 0000000000..af7e0a997b
--- /dev/null
+++ b/ui-ngx/src/app/modules/home/pages/notification/template/configuration/notification-action-button-configuration.component.ts
@@ -0,0 +1,168 @@
+///
+/// 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, OnInit } from '@angular/core';
+import {
+ ControlValueAccessor,
+ FormBuilder,
+ FormGroup,
+ NG_VALIDATORS,
+ NG_VALUE_ACCESSOR,
+ ValidationErrors,
+ Validator,
+ Validators
+} from '@angular/forms';
+import { ActionButtonLinkType, ActionButtonLinkTypeTranslateMap } 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-notification-action-button-configuration',
+ templateUrl: './notification-action-button-configuration.component.html',
+ providers: [
+ {
+ provide: NG_VALUE_ACCESSOR,
+ useExisting: forwardRef(() => NotificationActionButtonConfigurationComponent),
+ multi: true
+ },
+ {
+ provide: NG_VALIDATORS,
+ useExisting: forwardRef(() => NotificationActionButtonConfigurationComponent),
+ multi: true,
+ }
+ ]
+})
+export class NotificationActionButtonConfigurationComponent implements ControlValueAccessor, Validator, OnInit, OnDestroy {
+
+ @Input()
+ actionTitle: string;
+
+ private hideButtonTextValue = false;
+
+ get hideButtonText(): boolean {
+ return this.hideButtonTextValue;
+ }
+
+ @Input()
+ @coerceBoolean()
+ set hideButtonText(hideButtonText: boolean) {
+ this.hideButtonTextValue = hideButtonText;
+ if (this.hideButtonTextValue) {
+ this.actionButtonConfigForm.removeControl('text');
+ }
+ }
+
+ actionButtonConfigForm: FormGroup;
+
+ readonly actionButtonLinkType = ActionButtonLinkType;
+ readonly actionButtonLinkTypes = Object.keys(ActionButtonLinkType) as ActionButtonLinkType[];
+ readonly actionButtonLinkTypeTranslateMap = ActionButtonLinkTypeTranslateMap;
+
+ private propagateChange = (v: any) => { };
+ private readonly destroy$ = new Subject();
+
+ constructor(private fb: FormBuilder) {
+ this.actionButtonConfigForm = 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}]
+ });
+
+
+ this.actionButtonConfigForm.get('enabled').valueChanges.pipe(
+ takeUntil(this.destroy$)
+ ).subscribe((value) => {
+ if (value) {
+ if (!this.hideButtonText) {
+ this.actionButtonConfigForm.get('text').enable({emitEvent: false});
+ }
+ this.actionButtonConfigForm.get('linkType').enable({onlySelf: false});
+ } else {
+ this.actionButtonConfigForm.disable({emitEvent: false});
+ this.actionButtonConfigForm.get('enabled').enable({emitEvent: false});
+ }
+ });
+
+ this.actionButtonConfigForm.get('linkType').valueChanges.pipe(
+ takeUntil(this.destroy$)
+ ).subscribe((value) => {
+ const isEnabled = this.actionButtonConfigForm.get('enabled').value;
+ if (isEnabled) {
+ if (value === ActionButtonLinkType.LINK) {
+ this.actionButtonConfigForm.get('link').enable({emitEvent: false});
+ this.actionButtonConfigForm.get('dashboardId').disable({emitEvent: false});
+ this.actionButtonConfigForm.get('dashboardState').disable({emitEvent: false});
+ this.actionButtonConfigForm.get('setEntityIdInState').disable({emitEvent: false});
+ } else {
+ this.actionButtonConfigForm.get('link').disable({emitEvent: false});
+ this.actionButtonConfigForm.get('dashboardId').enable({emitEvent: false});
+ this.actionButtonConfigForm.get('dashboardState').enable({emitEvent: false});
+ this.actionButtonConfigForm.get('setEntityIdInState').enable({emitEvent: false});
+ }
+ }
+ });
+
+ this.actionButtonConfigForm.valueChanges.pipe(
+ takeUntil(this.destroy$)
+ ).subscribe(value => this.propagateChange(value));
+ }
+
+ ngOnInit() {
+ }
+
+ ngOnDestroy() {
+ this.destroy$.next();
+ this.destroy$.complete();
+ }
+
+ registerOnChange(fn: any) {
+ this.propagateChange = fn;
+ }
+
+ registerOnTouched(fn: any) {
+ }
+
+ setDisabledState(isDisabled: boolean) {
+ if (isDisabled) {
+ this.actionButtonConfigForm.disable({emitEvent: false});
+ } else {
+ this.actionButtonConfigForm.enable({emitEvent: false});
+ this.actionButtonConfigForm.get('enabled').updateValueAndValidity({onlySelf: true});
+ }
+ }
+
+ validate(): ValidationErrors | null {
+ return this.actionButtonConfigForm.valid ? null : {
+ actionButtonConfigForm: {
+ valid: false
+ }
+ };
+ }
+
+ writeValue(obj) {
+ if (isDefinedAndNotNull(obj)) {
+ this.actionButtonConfigForm.patchValue(obj, {emitEvent: false});
+ this.actionButtonConfigForm.get('enabled').updateValueAndValidity({onlySelf: true});
+ }
+ }
+
+}
diff --git a/ui-ngx/src/app/modules/home/pages/notification/template/configuration/notification-template-configuration.component.html b/ui-ngx/src/app/modules/home/pages/notification/template/configuration/notification-template-configuration.component.html
index f8c138f809..9ed015aa95 100644
--- a/ui-ngx/src/app/modules/home/pages/notification/template/configuration/notification-template-configuration.component.html
+++ b/ui-ngx/src/app/modules/home/pages/notification/template/configuration/notification-template-configuration.component.html
@@ -72,72 +72,10 @@
-
+
+
@@ -172,35 +110,12 @@
{{ 'notification.message-required' | translate }}
-
-
+
+
diff --git a/ui-ngx/src/app/modules/home/pages/notification/template/configuration/notification-template-configuration.component.ts b/ui-ngx/src/app/modules/home/pages/notification/template/configuration/notification-template-configuration.component.ts
index 5be07216d5..6941215d9f 100644
--- a/ui-ngx/src/app/modules/home/pages/notification/template/configuration/notification-template-configuration.component.ts
+++ b/ui-ngx/src/app/modules/home/pages/notification/template/configuration/notification-template-configuration.component.ts
@@ -26,8 +26,6 @@ import {
Validators
} from '@angular/forms';
import {
- ActionButtonLinkType,
- ActionButtonLinkTypeTranslateMap,
DeliveryMethodsTemplates,
NotificationDeliveryMethod,
NotificationDeliveryMethodInfoMap,
@@ -81,10 +79,6 @@ export class NotificationTemplateConfigurationComponent implements OnDestroy, Co
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',
@@ -153,13 +147,7 @@ export class NotificationTemplateConfigurationComponent implements OnDestroy, Co
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});
}
}
});
@@ -188,7 +176,7 @@ export class NotificationTemplateConfigurationComponent implements OnDestroy, Co
icon: [{value: 'notifications', disabled: true}, Validators.required],
color: [{value: '#757575', disabled: true}]
}),
- actionButtonConfig: this.createButtonConfigForm()
+ actionButtonConfig: [null]
})
});
@@ -225,37 +213,16 @@ export class NotificationTemplateConfigurationComponent implements OnDestroy, Co
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}]
- })
+ onClick: [null]
})
});
- 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()
+ button: [null]
});
break;
default:
@@ -265,48 +232,4 @@ export class NotificationTemplateConfigurationComponent implements OnDestroy, Co
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-notification-dialog.component.scss b/ui-ngx/src/app/modules/home/pages/notification/template/template-notification-dialog.component.scss
index c8ed234490..536c5842a9 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: 775px;
+ width: 850px;
height: 100%;
max-width: 100%;
max-height: 100vh;
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 f22a599aa8..8a5678e2ae 100644
--- a/ui-ngx/src/assets/locale/locale.constant-en_US.json
+++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json
@@ -3214,6 +3214,7 @@
},
"notification": {
"action-button": "Action button",
+ "action-on-click-notification": "Action on click notification",
"action-type": "Action type",
"active": "Active",
"add-notification-recipients-group": "Add notification recipients group",
@@ -3353,7 +3354,6 @@
"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",