diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/request-table/request-notification-dialog.component.html b/ui-ngx/src/app/modules/home/pages/notification-center/request-table/request-notification-dialog.component.html index be1f917129..c425d62686 100644 --- a/ui-ngx/src/app/modules/home/pages/notification-center/request-table/request-notification-dialog.component.html +++ b/ui-ngx/src/app/modules/home/pages/notification-center/request-table/request-notification-dialog.component.html @@ -37,11 +37,54 @@ {{ 'notification.compose' | translate }}
+
+ + {{ 'notification.use-template' | translate }} + {{ 'notification.start-from-scratch' | translate }} + +
+ allowCreate + formControlName="templateId" + [notificationTypes]="notificationType.GENERAL"> + +
+
+ + notification.subject + + + {{ 'notification.subject-required' | translate }} + + + + notification.message + + + {{ 'notification.message-required' | translate }} + + + +
+
+ + {{ notificationDeliveryMethodTranslateMap.get(deliveryMethods) | translate }} + +
+
+
notification.at-least-one-should-be-selected
+
+
+
-
- - {{ 'notification.scheduler-later' | translate }} - -
- - - - notification.time - - - - -
+ + + + {{ 'notification.web-settings' | translate }} +
+ + notification.subject + + + + notification.message + + +
+
+ + {{ 'icon.icon' | translate }} + +
+ + + + +
+
+
+ + {{ 'notification.action-button' | translate }} + +
+
+ + notification.button-text + + + {{ 'notification.button-text-required' | translate }} + + + + +
+ + notification.link + + + {{ 'notification.link-required' | translate }} + + +
+
- + + {{ 'notification.email-settings' | translate }} + +
+ + notification.subject + + + notification.message + +
+
+
+ + {{ 'notification.sms-settings' | translate }} +
+ + notification.message + + +
+
+ + {{ 'notification.slack-settings' | translate }} +
+ + notification.message + + +
+
+ {{ 'notification.review' | translate }} -
+
@@ -100,6 +234,23 @@
+
+ + {{ 'notification.scheduler-later' | translate }} + +
+ + + + notification.time + + + + +
+
diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/request-table/request-notification-dialog.component.scss b/ui-ngx/src/app/modules/home/pages/notification-center/request-table/request-notification-dialog.component.scss index 00aab7c880..2c51b0aa5d 100644 --- a/ui-ngx/src/app/modules/home/pages/notification-center/request-table/request-notification-dialog.component.scss +++ b/ui-ngx/src/app/modules/home/pages/notification-center/request-table/request-notification-dialog.component.scss @@ -19,6 +19,22 @@ :host-context(.tb-fullscreen-dialog .mat-dialog-container) { width: 640px; + .delivery-method-container { + padding-bottom: 8px; + + &.even { + padding-right: 8px; + } + + .delivery-method { + padding: 16px 12px; + border: 1px solid rgba(0, 0, 0, 0.12); + border-radius: 6px; + width: 100%; + height: 100%; + } + } + .additional-config-group { padding: 16px 16px 4px; margin-bottom: 12px; @@ -129,4 +145,57 @@ } } } + + .mat-button-toggle-group.tb-notification-use-template-toggle-group { + &.mat-button-toggle-group-appearance-standard { + border: none; + border-radius: 18px; + + .mat-button-toggle + .mat-button-toggle { + border-left: none; + } + } + + .mat-button-toggle { + background: rgba(0, 0, 0, 0.06); + height: 36px; + align-items: center; + display: flex; + + .mat-button-toggle-ripple { + top: 2px; + left: 2px; + right: 2px; + bottom: 2px; + border-radius: 18px; + } + } + + .mat-button-toggle-button { + color: #959595; + } + + .mat-button-toggle-focus-overlay { + border-radius: 18px; + margin: 2px; + } + + .mat-button-toggle-checked .mat-button-toggle-button { + background-color: $tb-primary-color; + color: #fff; + border-radius: 18px; + margin-left: 2px; + margin-right: 2px; + } + + .mat-button-toggle-appearance-standard .mat-button-toggle-label-content { + line-height: 34px; + font-size: 16px; + font-weight: 500; + } + + .mat-button-toggle-checked.mat-button-toggle-appearance-standard:not(.mat-button-toggle-disabled):hover .mat-button-toggle-focus-overlay { + opacity: .01; + } + } } diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/request-table/request-notification-dialog.componet.ts b/ui-ngx/src/app/modules/home/pages/notification-center/request-table/request-notification-dialog.componet.ts index b616eb81e5..9f9e144314 100644 --- a/ui-ngx/src/app/modules/home/pages/notification-center/request-table/request-notification-dialog.componet.ts +++ b/ui-ngx/src/app/modules/home/pages/notification-center/request-table/request-notification-dialog.componet.ts @@ -15,13 +15,14 @@ /// import { + NotificationDeliveryMethod, + NotificationDeliveryMethodTranslateMap, NotificationRequest, NotificationRequestPreview, NotificationTarget, NotificationType } from '@shared/models/notification.models'; import { Component, Inject, OnDestroy, ViewChild } from '@angular/core'; -import { DialogComponent } from '@shared/components/dialog.component'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { Router } from '@angular/router'; @@ -29,7 +30,7 @@ import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dial import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { NotificationService } from '@core/http/notification.service'; import { deepTrim } from '@core/utils'; -import { Observable, Subject } from 'rxjs'; +import { Observable } from 'rxjs'; import { EntityType } from '@shared/models/entity-type.models'; import { BreakpointObserver } from '@angular/cdk/layout'; import { MatStepper } from '@angular/material/stepper'; @@ -42,6 +43,7 @@ import { TargetsNotificationDialogData } from '@home/pages/notification-center/targets-table/target-notification-dialog.componet'; import { MatButton } from '@angular/material/button'; +import { TemplateConfiguration } from '@home/pages/notification-center/template-table/template-configuration'; export interface RequestNotificationDialogData { request?: NotificationRequest; @@ -54,54 +56,76 @@ export interface RequestNotificationDialogData { styleUrls: ['./request-notification-dialog.component.scss'] }) export class RequestNotificationDialogComponent extends - DialogComponent implements OnDestroy { + TemplateConfiguration implements OnDestroy { @ViewChild('createNotification', {static: true}) createNotification: MatStepper; stepperOrientation: Observable; isAdd = true; entityType = EntityType; notificationType = NotificationType; + notificationRequestForm: FormGroup; + notificationRequestAdditionalConfigForm: FormGroup; + + notificationDeliveryMethods = Object.keys(NotificationDeliveryMethod) as NotificationDeliveryMethod[]; + notificationDeliveryMethodTranslateMap = NotificationDeliveryMethodTranslateMap; selectedIndex = 0; preview: NotificationRequestPreview = null; dialogTitle = 'notification.notify-again'; - private readonly destroy$ = new Subject(); - constructor(protected store: Store, protected router: Router, protected dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public data: RequestNotificationDialogData, private breakpointObserver: BreakpointObserver, - private fb: FormBuilder, + protected fb: FormBuilder, private notificationService: NotificationService, private dialog: MatDialog) { - super(store, router, dialogRef); + super(store, router, dialogRef, fb); this.stepperOrientation = this.breakpointObserver.observe(MediaBreakpoints['gt-xs']) .pipe(map(({matches}) => matches ? 'horizontal' : 'vertical')); this.notificationRequestForm = this.fb.group({ + useTemplate: [true], templateId: [null, Validators.required], targets: [null, Validators.required], - additionalConfig: this.fb.group({ - enabled: [false], - timezone: [{value: '', disabled: true}, Validators.required], - time: [{value: 0, disabled: true}, Validators.required] - }) + template: this.templateNotificationForm + }); + + this.notificationRequestForm.get('template').disable({emitEvent: false}); + this.notificationRequestForm.get('template.name').removeValidators(Validators.required); + this.notificationRequestForm.get('template.name').updateValueAndValidity({emitEvent: false}); + + this.notificationRequestForm.get('useTemplate').valueChanges.pipe( + takeUntil(this.destroy$) + ).subscribe(value => { + if (value) { + this.notificationRequestForm.get('templateId').enable({emitEvent: false}); + this.notificationRequestForm.get('template').disable({emitEvent: false}); + } else { + this.notificationRequestForm.get('templateId').disable({emitEvent: false}); + this.notificationRequestForm.get('template').enable({emitEvent: false}); + } + }); + + this.notificationRequestAdditionalConfigForm = this.fb.group({ + enabled: [false], + timezone: [{value: '', disabled: true}, Validators.required], + time: [{value: 0, disabled: true}, Validators.required] }); - this.notificationRequestForm.get('additionalConfig.enabled').valueChanges.pipe( + this.notificationRequestAdditionalConfigForm.get('enabled').valueChanges.pipe( takeUntil(this.destroy$) ).subscribe(value => { if (value) { - this.notificationRequestForm.get('additionalConfig.timezone').enable({emitEvent: false}); - this.notificationRequestForm.get('additionalConfig.time').enable({emitEvent: false}); + this.notificationRequestAdditionalConfigForm.get('timezone').enable({emitEvent: false}); + this.notificationRequestAdditionalConfigForm.get('time').enable({emitEvent: false}); } else { - this.notificationRequestForm.get('additionalConfig.timezone').disable({emitEvent: false}); - this.notificationRequestForm.get('additionalConfig.time').disable({emitEvent: false}); + this.notificationRequestAdditionalConfigForm.get('timezone').disable({emitEvent: false}); + this.notificationRequestAdditionalConfigForm.get('time').disable({emitEvent: false}); } }); @@ -115,8 +139,6 @@ export class RequestNotificationDialogComponent extends ngOnDestroy() { super.ngOnDestroy(); - this.destroy$.next(); - this.destroy$.complete(); } cancel(): void { @@ -179,9 +201,11 @@ export class RequestNotificationDialogComponent extends private get notificationFormValue(): NotificationRequest { const formValue = deepTrim(this.notificationRequestForm.value); + delete formValue.useTemplate; + delete formValue.template; let delay = 0; - if (formValue.additionalConfig.enabled) { - delay = (this.notificationRequestForm.value.additionalConfig.time.valueOf() - this.minDate().valueOf()) / 1000; + if (this.notificationRequestAdditionalConfigForm.value.enabled) { + delay = (this.notificationRequestAdditionalConfigForm.value.time.valueOf() - this.minDate().valueOf()) / 1000; } formValue.additionalConfig = { sendingDelayInSec: delay > 0 ? delay : 0 @@ -202,7 +226,7 @@ export class RequestNotificationDialogComponent extends } minDate(): Date { - return new Date(getCurrentTime(this.notificationRequestForm.get('additionalConfig.timezone').value).format('lll')); + return new Date(getCurrentTime(this.notificationRequestAdditionalConfigForm.get('timezone').value).format('lll')); } maxDate(): Date { diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.html b/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.html index 141822f55c..43554f128e 100644 --- a/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.html +++ b/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.html @@ -58,9 +58,7 @@ required allowCreate formControlName="templateId" - [notificationTypes]="ruleNotificationForm.get('triggerType').value" - labelText="notification.template-name" - requiredText="notification.template-required"> + [notificationTypes]="ruleNotificationForm.get('triggerType').value">
diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/template-table/template-autocomplete.component.html b/ui-ngx/src/app/modules/home/pages/notification-center/template-table/template-autocomplete.component.html index 4ffa5d8812..1a119359c3 100644 --- a/ui-ngx/src/app/modules/home/pages/notification-center/template-table/template-autocomplete.component.html +++ b/ui-ngx/src/app/modules/home/pages/notification-center/template-table/template-autocomplete.component.html @@ -52,7 +52,7 @@ notification.no-notification-templates - Not template matching {{ truncate.transform(searchText, true, 6, '...') }} + {{ 'notification.no-template-matching' | translate : {template: truncate.transform(searchText, true, 6, '...')} }} diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/template-table/template-autocomplete.component.ts b/ui-ngx/src/app/modules/home/pages/notification-center/template-table/template-autocomplete.component.ts index 54937247d4..ae452e9060 100644 --- a/ui-ngx/src/app/modules/home/pages/notification-center/template-table/template-autocomplete.component.ts +++ b/ui-ngx/src/app/modules/home/pages/notification-center/template-table/template-autocomplete.component.ts @@ -57,12 +57,6 @@ export class TemplateAutocompleteComponent implements ControlValueAccessor, OnIn notificationDeliveryMethodTranslateMap = NotificationDeliveryMethodTranslateMap; selectTemplateFormGroup: FormGroup; - @Input() - labelText: string; - - @Input() - requiredText: string; - private requiredValue: boolean; get required(): boolean { return this.requiredValue; diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/template-table/template-configuration.ts b/ui-ngx/src/app/modules/home/pages/notification-center/template-table/template-configuration.ts new file mode 100644 index 0000000000..303affe35a --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/notification-center/template-table/template-configuration.ts @@ -0,0 +1,172 @@ +/// +/// Copyright © 2016-2022 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 { FormBuilder, FormGroup, ValidationErrors, Validators } from '@angular/forms'; +import { + NotificationDeliveryMethod, + NotificationDeliveryMethodTranslateMap, + NotificationTemplate, + NotificationType +} from '@shared/models/notification.models'; +import { takeUntil } from 'rxjs/operators'; +import { Subject } from 'rxjs'; +import { Directive, OnDestroy } from '@angular/core'; +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'; + +@Directive() +// tslint:disable-next-line:directive-class-suffix +export abstract class TemplateConfiguration extends DialogComponent implements OnDestroy{ + + templateNotificationForm: FormGroup; + pushTemplateForm: FormGroup; + emailTemplateForm: FormGroup; + smsTemplateForm: FormGroup; + slackTemplateForm: FormGroup; + + notificationDeliveryMethods = Object.keys(NotificationDeliveryMethod) as NotificationDeliveryMethod[]; + notificationDeliveryMethodTranslateMap = NotificationDeliveryMethodTranslateMap; + + 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', + height: 400, + autofocus: false, + branding: false + }; + + protected readonly destroy$ = new Subject(); + + protected deliveryMethodFormsMap: Map; + + protected constructor(protected store: Store, + protected router: Router, + protected dialogRef: MatDialogRef, + protected fb: FormBuilder) { + super(store, router, dialogRef); + + this.templateNotificationForm = this.fb.group({ + name: ['', Validators.required], + notificationType: [NotificationType.GENERAL], + configuration: this.fb.group({ + notificationSubject: ['', Validators.required], + defaultTextTemplate: ['', Validators.required], + deliveryMethodsTemplates: this.fb.group({}, {validators: this.atLeastOne()}) + }) + }); + + this.notificationDeliveryMethods.forEach(method => { + (this.templateNotificationForm.get('configuration.deliveryMethodsTemplates') as FormGroup) + .addControl(method, this.fb.group({enabled: method === NotificationDeliveryMethod.PUSH}), {emitEvent: false}); + }); + + this.pushTemplateForm = this.fb.group({ + subject: [''], + body: [''], + additionalConfig: this.fb.group({ + icon: this.fb.group({ + enabled: [false], + icon: [{value: '', disabled: true}, Validators.required], + color: ['#757575'] + }), + actionButtonConfig: this.fb.group({ + enabled: [false], + text: [{value: '', disabled: true}, Validators.required], + color: ['#305680'], + link: [{value: '', disabled: true}, Validators.required] + }), + }) + }); + + this.pushTemplateForm.get('additionalConfig.icon.enabled').valueChanges.pipe( + takeUntil(this.destroy$) + ).subscribe((value) => { + if (value) { + this.pushTemplateForm.get('additionalConfig.icon.icon').enable({emitEvent: false}); + } else { + this.pushTemplateForm.get('additionalConfig.icon.icon').disable({emitEvent: false}); + } + }); + + this.pushTemplateForm.get('additionalConfig.actionButtonConfig.enabled').valueChanges.pipe( + takeUntil(this.destroy$) + ).subscribe((value) => { + if (value) { + this.pushTemplateForm.get('additionalConfig.actionButtonConfig.text').enable({emitEvent: false}); + this.pushTemplateForm.get('additionalConfig.actionButtonConfig.link').enable({emitEvent: false}); + } else { + this.pushTemplateForm.get('additionalConfig.actionButtonConfig.text').disable({emitEvent: false}); + this.pushTemplateForm.get('additionalConfig.actionButtonConfig.link').disable({emitEvent: false}); + } + }); + + this.emailTemplateForm = this.fb.group({ + subject: [''], + body: [''] + }); + + this.smsTemplateForm = this.fb.group({ + body: [''] + }); + + this.slackTemplateForm = this.fb.group({ + body: [''] + }); + + this.deliveryMethodFormsMap = new Map([ + [NotificationDeliveryMethod.PUSH, this.pushTemplateForm], + [NotificationDeliveryMethod.EMAIL, this.emailTemplateForm], + [NotificationDeliveryMethod.SMS, this.smsTemplateForm], + [NotificationDeliveryMethod.SLACK, this.slackTemplateForm] + ]); + } + + ngOnDestroy() { + this.destroy$.next(); + this.destroy$.complete(); + } + + private atLeastOne() { + return (group: FormGroup): ValidationErrors | null => { + let hasAtLeastOne = true; + if (group?.controls) { + const controlsFormValue: FormGroup[] = Object.entries(group.controls).map(method => method[1]) as any; + hasAtLeastOne = controlsFormValue.some(value => value.controls.enabled.value); + } + return hasAtLeastOne ? null : {atLeastOne: true}; + }; + } + + protected getNotificationTemplateValue(): NotificationTemplate { + const template: NotificationTemplate = 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]; + } + }); + return template; + } +} diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/template-table/template-notification-dialog.component.ts b/ui-ngx/src/app/modules/home/pages/notification-center/template-table/template-notification-dialog.component.ts index 94f207104a..0064900e66 100644 --- a/ui-ngx/src/app/modules/home/pages/notification-center/template-table/template-notification-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/pages/notification-center/template-table/template-notification-dialog.component.ts @@ -22,21 +22,21 @@ import { NotificationType } from '@shared/models/notification.models'; import { Component, Inject, OnDestroy, ViewChild } from '@angular/core'; -import { DialogComponent } from '@shared/components/dialog.component'; 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, FormGroup, ValidationErrors, Validators } from '@angular/forms'; +import { FormBuilder, FormGroup } from '@angular/forms'; import { NotificationService } from '@core/http/notification.service'; import { deepClone, deepTrim, isDefinedAndNotNull } from '@core/utils'; -import { Observable, Subject } from 'rxjs'; -import { map, takeUntil } from 'rxjs/operators'; +import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; import { StepperOrientation, StepperSelectionEvent } from '@angular/cdk/stepper'; import { MatStepper } from '@angular/material/stepper'; import { BreakpointObserver } from '@angular/cdk/layout'; import { MediaBreakpoints } from '@shared/models/constants'; import { TranslateService } from '@ngx-translate/core'; +import { TemplateConfiguration } from '@home/pages/notification-center/template-table/template-configuration'; export interface TemplateNotificationDialogData { template?: NotificationTemplate; @@ -51,7 +51,7 @@ export interface TemplateNotificationDialogData { styleUrls: ['./template-notification-dialog.component.scss'] }) export class TemplateNotificationDialogComponent - extends DialogComponent implements OnDestroy { + extends TemplateConfiguration implements OnDestroy { @ViewChild('notificationTemplateStepper', {static: true}) notificationTemplateStepper: MatStepper; @@ -72,114 +72,26 @@ export class TemplateNotificationDialogComponent selectedIndex = 0; hideSelectType = false; - 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', - height: 400, - autofocus: false, - branding: false - }; - - private readonly destroy$ = new Subject(); private readonly templateNotification: NotificationTemplate; - private deliveryMethodFormsMap: Map; constructor(protected store: Store, protected router: Router, protected dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public data: TemplateNotificationDialogData, private breakpointObserver: BreakpointObserver, - private fb: FormBuilder, + protected fb: FormBuilder, private notificationService: NotificationService, private translate: TranslateService) { - super(store, router, dialogRef); + super(store, router, dialogRef, fb); this.stepperOrientation = this.breakpointObserver.observe(MediaBreakpoints['gt-xs']) .pipe(map(({matches}) => matches ? 'horizontal' : 'vertical')); if (isDefinedAndNotNull(this.data?.predefinedType)) { this.hideSelectType = true; + this.templateNotificationForm.get('notificationType').setValue(this.data.predefinedType, {emitEvents: false}); } - this.templateNotificationForm = this.fb.group({ - name: ['', Validators.required], - notificationType: [this.hideSelectType ? this.data.predefinedType : NotificationType.GENERAL], - configuration: this.fb.group({ - notificationSubject: ['', Validators.required], - defaultTextTemplate: ['', Validators.required], - deliveryMethodsTemplates: this.fb.group({}, {validators: this.atLeastOne()}) - }) - }); - this.notificationDeliveryMethods.forEach(method => { - (this.templateNotificationForm.get('configuration.deliveryMethodsTemplates') as FormGroup) - .addControl(method, this.fb.group({enabled: method === NotificationDeliveryMethod.PUSH}), {emitEvent: false}); - }); - - this.pushTemplateForm = this.fb.group({ - subject: [''], - body: [''], - additionalConfig: this.fb.group({ - icon: this.fb.group({ - enabled: [false], - icon: [{value: '', disabled: true}, Validators.required], - color: ['#757575'] - }), - actionButtonConfig: this.fb.group({ - enabled: [false], - text: [{value: '', disabled: true}, Validators.required], - color: ['#305680'], - link: [{value: '', disabled: true}, Validators.required] - }), - }) - }); - - this.pushTemplateForm.get('additionalConfig.icon.enabled').valueChanges.pipe( - takeUntil(this.destroy$) - ).subscribe((value) => { - if (value) { - this.pushTemplateForm.get('additionalConfig.icon.icon').enable({emitEvent: false}); - } else { - this.pushTemplateForm.get('additionalConfig.icon.icon').disable({emitEvent: false}); - } - }); - - this.pushTemplateForm.get('additionalConfig.actionButtonConfig.enabled').valueChanges.pipe( - takeUntil(this.destroy$) - ).subscribe((value) => { - if (value) { - this.pushTemplateForm.get('additionalConfig.actionButtonConfig.text').enable({emitEvent: false}); - this.pushTemplateForm.get('additionalConfig.actionButtonConfig.link').enable({emitEvent: false}); - } else { - this.pushTemplateForm.get('additionalConfig.actionButtonConfig.text').disable({emitEvent: false}); - this.pushTemplateForm.get('additionalConfig.actionButtonConfig.link').disable({emitEvent: false}); - } - }); - - this.emailTemplateForm = this.fb.group({ - subject: [''], - body: [''] - }); - - this.smsTemplateForm = this.fb.group({ - body: [''] - }); - - this.slackTemplateForm = this.fb.group({ - body: [''] - }); - - this.deliveryMethodFormsMap = new Map([ - [NotificationDeliveryMethod.PUSH, this.pushTemplateForm], - [NotificationDeliveryMethod.EMAIL, this.emailTemplateForm], - [NotificationDeliveryMethod.SMS, this.smsTemplateForm], - [NotificationDeliveryMethod.SLACK, this.slackTemplateForm] - ]); - if (data.isAdd || data.isCopy) { this.dialogTitle = 'notification.add-notification-template'; } @@ -241,14 +153,7 @@ export class TemplateNotificationDialogComponent private add(): void { if (this.allValid()) { - let template: NotificationTemplate = 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]; - } - }); + let template = this.getNotificationTemplateValue(); if (this.templateNotification && !this.data.isCopy) { template = {...this.templateNotification, ...template}; } @@ -269,15 +174,4 @@ export class TemplateNotificationDialogComponent } }); } - - private atLeastOne() { - return (group: FormGroup): ValidationErrors | null => { - let hasAtLeastOne = true; - if (group?.controls) { - const controlsFormValue: FormGroup[] = Object.entries(group.controls).map(method => method[1]) as any; - hasAtLeastOne = controlsFormValue.some(value => value.controls.enabled.value); - } - return hasAtLeastOne ? null : {atLeastOne: true}; - }; - } } 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 8a99967f57..b0fbcb3b52 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -2709,8 +2709,8 @@ "copy-notification-template": "Copy notification template", "copy-rule": "Copy rule", "copy-template": "Copy template", - "create-target": "Create recipient", "create-new": "Create new", + "create-target": "Create recipient", "created": "Created", "created-time": "Created time", "delete-request-text": "Be careful, after the confirmation the notification request will become unrecoverable.", @@ -2767,6 +2767,7 @@ "no-severity-found": "No severity found", "no-severity-matching": "'{{severity}}' not found.", "no-targets-notification": "No recipients notification", + "no-template-matching": "No resource matching '{{template}}' were found.", "not-found-slack-recipient": "Not found slack recipient", "notification": "Notification", "notification-center": "Notification center", @@ -2805,6 +2806,7 @@ }, "slack-settings": "Slack settings", "sms-settings": "SMS settings", + "start-from-scratch": "Start from scratch", "status": "Status", "subject": "Subject", "subject-required": "Subject is required", @@ -2851,6 +2853,7 @@ "type": "Type", "unread": "Unread", "updated": "Updated", + "use-template": "Use template", "view-all": "View all", "web-settings": "Web settings" },