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 @@ + +
+ + + + + {{ actionTitle }} + + + + +
+ + notification.button-text + + + {{ 'notification.button-text-required' | translate }} + + + {{ 'notification.button-text-max-length' | translate : + {length: actionButtonConfigForm.get('text').getError('maxlength').requiredLength} + }} + + +
+
+ + notification.action-type + + + {{ actionButtonLinkTypeTranslateMap.get(actionButtonLinkType) | translate }} + + + + + notification.link + + + {{ 'notification.link-required' | translate }} + + + + + + + + +
+ + {{ 'notification.set-entity-from-notification' | translate }} + +
+
+
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 @@ -
- - - - - {{ 'notification.action-button' | translate }} - - - - -
- - notification.button-text - - - {{ 'notification.button-text-required' | translate }} - - - {{ 'notification.button-text-max-length' | translate : - {length: templateConfigurationForm.get('WEB.additionalConfig.actionButtonConfig.text').getError('maxlength').requiredLength} - }} - - -
-
- - notification.action-type - - - {{ actionButtonLinkTypeTranslateMap.get(actionButtonLinkType) | translate }} - - - - - notification.link - - - {{ 'notification.link-required' | translate }} - - - - - - - - -
- - {{ 'notification.set-entity-from-notification' | translate }} - -
-
-
+ + @@ -172,35 +110,12 @@ {{ 'notification.message-required' | translate }} -
- - - - - {{ 'notification.open-dashboard-on-click-notification' | translate }} - - - - -
- - - - -
- - {{ 'notification.set-entity-from-notification' | translate }} - -
-
+
+ +
@@ -325,72 +240,10 @@
notification.theme-color
-
- - - - - {{ 'notification.action-button' | translate }} - - - - -
- - notification.button-text - - - {{ 'notification.button-text-required' | translate }} - - - {{'notification.button-text-max-length' | translate : - {length: templateConfigurationForm.get('MICROSOFT_TEAMS.button.text').getError('maxlength').requiredLength} - }} - - -
-
- - notification.action-type - - - {{ actionButtonLinkTypeTranslateMap.get(actionButtonLinkType) | translate }} - - - - - notification.link - - - {{ 'notification.link-required' | translate }} - - - - - - - - -
- - {{ 'notification.set-entity-from-notification' | 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",