diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/notification-center.module.ts b/ui-ngx/src/app/modules/home/pages/notification-center/notification-center.module.ts index bbd8d2f939..c2ef2cb42c 100644 --- a/ui-ngx/src/app/modules/home/pages/notification-center/notification-center.module.ts +++ b/ui-ngx/src/app/modules/home/pages/notification-center/notification-center.module.ts @@ -49,7 +49,9 @@ import { import { EscalationsComponent } from '@home/pages/notification-center/rule-table/escalations.component'; import { EscalationFormComponent } from '@home/pages/notification-center/rule-table/escalation-form.component'; import { AlarmTypeListComponent } from '@home/pages/notification-center/rule-table/alarm-type-list.component'; -import { AlarmSeveritiesListComponent } from '@home/pages/notification-center/rule-table/alarm-severities-list.component'; +import { + AlarmSeveritiesListComponent +} from '@home/pages/notification-center/rule-table/alarm-severities-list.component'; @NgModule({ declarations: [ 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 48de10d5d1..be1f917129 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 @@ -49,6 +49,11 @@ placeholderText="{{ 'notification.target' | translate }}" requiredText="{{ 'notification.targets-required' | translate }}" [entityType]="entityType.NOTIFICATION_TARGET"> +
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 ce8f7645d3..b616eb81e5 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 @@ -14,13 +14,18 @@ /// limitations under the License. /// -import { NotificationRequest, NotificationRequestPreview, NotificationType } from '@shared/models/notification.models'; +import { + 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'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { NotificationService } from '@core/http/notification.service'; import { deepTrim } from '@core/utils'; @@ -32,6 +37,11 @@ import { StepperOrientation, StepperSelectionEvent } from '@angular/cdk/stepper' import { MediaBreakpoints } from '@shared/models/constants'; import { map, takeUntil } from 'rxjs/operators'; import { getCurrentTime } from '@shared/models/time/time.models'; +import { + TargetNotificationDialogComponent, + TargetsNotificationDialogData +} from '@home/pages/notification-center/targets-table/target-notification-dialog.componet'; +import { MatButton } from '@angular/material/button'; export interface RequestNotificationDialogData { request?: NotificationRequest; @@ -66,7 +76,8 @@ export class RequestNotificationDialogComponent extends @Inject(MAT_DIALOG_DATA) public data: RequestNotificationDialogData, private breakpointObserver: BreakpointObserver, private fb: FormBuilder, - private notificationService: NotificationService) { + private notificationService: NotificationService, + private dialog: MatDialog) { super(store, router, dialogRef); this.stepperOrientation = this.breakpointObserver.observe(MediaBreakpoints['gt-xs']) @@ -199,4 +210,27 @@ export class RequestNotificationDialogComponent extends date.setDate(date.getDate() + 7); return date; } + + createTarget($event: Event, button: MatButton) { + if ($event) { + $event.stopPropagation(); + } + button._elementRef.nativeElement.blur(); + this.dialog.open(TargetNotificationDialogComponent, { + disableClose: true, + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], + data: {} + }).afterClosed() + .subscribe((res) => { + if (res) { + let formValue: string[] = this.notificationRequestForm.get('targets').value; + if (!formValue) { + formValue = []; + } + formValue.push(res.id.id); + this.notificationRequestForm.get('targets').patchValue(formValue); + } + }); + } } diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/escalation-form.component.html b/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/escalation-form.component.html index 430e3a07d4..83f6aba051 100644 --- a/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/escalation-form.component.html +++ b/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/escalation-form.component.html @@ -19,8 +19,9 @@
-
notification.first-recipient
-
+
notification.first-recipient
+ +
After notification.notify
+
-
+
+
diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/escalation-form.component.scss b/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/escalation-form.component.scss index f80a0a7cef..1ce2454b8c 100644 --- a/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/escalation-form.component.scss +++ b/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/escalation-form.component.scss @@ -32,3 +32,13 @@ padding: 0 10px; } } + +:host ::ng-deep { + tb-timeinterval { + min-width: 100px; + + .mat-form-field-infix { + width: 100%; + } + } +} diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/escalation-form.component.ts b/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/escalation-form.component.ts index e5c638ba3c..57510e8d3a 100644 --- a/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/escalation-form.component.ts +++ b/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/escalation-form.component.ts @@ -25,12 +25,17 @@ import { Validator, Validators } from '@angular/forms'; -import { UtilsService } from '@core/services/utils.service'; import { isDefinedAndNotNull } from '@core/utils'; import { Subject } from 'rxjs'; -import { NonConfirmedNotificationEscalation } from '@shared/models/notification.models'; +import { NonConfirmedNotificationEscalation, NotificationTarget } from '@shared/models/notification.models'; import { EntityType } from '@shared/models/entity-type.models'; import { takeUntil } from 'rxjs/operators'; +import { + TargetNotificationDialogComponent, + TargetsNotificationDialogData +} from '@home/pages/notification-center/targets-table/target-notification-dialog.componet'; +import { MatDialog } from '@angular/material/dialog'; +import { MatButton } from '@angular/material/button'; @Component({ selector: 'tb-escalation-form', @@ -66,8 +71,8 @@ export class EscalationFormComponent implements ControlValueAccessor, OnInit, On private propagateChangePending = false; private destroy$ = new Subject(); - constructor(private utils: UtilsService, - private fb: FormBuilder) { + constructor(private fb: FormBuilder, + private dialog: MatDialog) { } registerOnChange(fn: any): void { @@ -120,6 +125,29 @@ export class EscalationFormComponent implements ControlValueAccessor, OnInit, On } } + createTarget($event: Event, button: MatButton) { + if ($event) { + $event.stopPropagation(); + } + button._elementRef.nativeElement.blur(); + this.dialog.open(TargetNotificationDialogComponent, { + disableClose: true, + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], + data: {} + }).afterClosed() + .subscribe((res) => { + if (res) { + let formValue: string[] = this.escalationFormGroup.get('targets').value; + if (!formValue) { + formValue = []; + } + formValue.push(res.id.id); + this.escalationFormGroup.get('targets').patchValue(formValue); + } + }); + } + public validate(c: FormControl) { return (this.escalationFormGroup.valid) ? null : { escalation: { diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/escalations.component.html b/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/escalations.component.html index e11a1227f7..971832300b 100644 --- a/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/escalations.component.html +++ b/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/escalations.component.html @@ -21,7 +21,10 @@ *ngFor="let escalationControl of escalationsFormArray.controls; let $index = index; last as isLast;" [ngStyle]="!isLast ? {paddingBottom: '8px'} : {}"> - + + + +
+ +
+ notification.hierarchy-of-receiving + +
+
- -
- notification.hierarchy-of-receiving - -
@@ -143,14 +159,6 @@
notification.device-profiles-list-rule-hint
-
- - -
@@ -180,14 +188,6 @@ {{ 'notification.deleted' | translate }}
-
- - -
@@ -203,14 +203,7 @@ [stepControl]="alarmCommentTemplateForm"> {{ 'notification.alarm-comment-trigger-settings' | translate }} -
- - -
+
; diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.ts b/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.ts index b87e915e4e..ed6bcb0183 100644 --- a/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.ts @@ -14,13 +14,18 @@ /// limitations under the License. /// -import { NotificationRule, TriggerType, TriggerTypeTranslationMap } from '@shared/models/notification.models'; +import { + NotificationRule, + NotificationTarget, + TriggerType, + TriggerTypeTranslationMap +} 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 { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { NotificationService } from '@core/http/notification.service'; import { EntityType } from '@shared/models/entity-type.models'; @@ -33,6 +38,11 @@ import { MediaBreakpoints } from '@shared/models/constants'; import { BreakpointObserver } from '@angular/cdk/layout'; import { AlarmStatus, alarmStatusTranslations } from '@shared/models/alarm.models'; import { TranslateService } from '@ngx-translate/core'; +import { + TargetNotificationDialogComponent, + TargetsNotificationDialogData +} from '@home/pages/notification-center/targets-table/target-notification-dialog.componet'; +import { MatButton } from '@angular/material/button'; export interface RuleNotificationDialogData { rule?: NotificationRule; @@ -86,7 +96,8 @@ export class RuleNotificationDialogComponent extends private breakpointObserver: BreakpointObserver, private fb: FormBuilder, public translate: TranslateService, - private notificationService: NotificationService) { + private notificationService: NotificationService, + private dialog: MatDialog) { super(store, router, dialogRef); if (isDefined(data.isAdd)) { @@ -100,13 +111,28 @@ export class RuleNotificationDialogComponent extends name: [null, Validators.required], templateId: [null, Validators.required], triggerType: [TriggerType.ALARM, Validators.required], - recipientsConfig: [null], + recipientsConfig: this.fb.group({ + targets: [{value: null, disabled: true}, Validators.required], + escalationTable: [null, Validators.required] + }), triggerConfig: [null], additionalConfig: this.fb.group({ description: [''] }) }); + this.ruleNotificationForm.get('triggerType').valueChanges.pipe( + takeUntil(this.destroy$) + ).subscribe(value => { + if (value === TriggerType.ALARM) { + this.ruleNotificationForm.get('recipientsConfig.escalationTable').enable({emitEvent: false}); + this.ruleNotificationForm.get('recipientsConfig.targets').disable({emitEvent: false}); + } else { + this.ruleNotificationForm.get('recipientsConfig.escalationTable').disable({emitEvent: false}); + this.ruleNotificationForm.get('recipientsConfig.targets').enable({emitEvent: false}); + } + }); + this.alarmTemplateForm = this.fb.group({ triggerConfig: this.fb.group({ alarmTypes: [null], @@ -114,9 +140,6 @@ export class RuleNotificationDialogComponent extends clearRule: this.fb.group({ alarmStatus: [null] }) - }), - recipientsConfig: this.fb.group({ - escalationTable: [] }) }); @@ -125,9 +148,6 @@ export class RuleNotificationDialogComponent extends filterByDevice: [true], devices: [null], deviceProfiles: [{value: null, disabled: true}] - }), - recipientsConfig: this.fb.group({ - targets: [[], Validators.required] }) }); @@ -149,17 +169,10 @@ export class RuleNotificationDialogComponent extends created: [false], updated: [false], deleted: [false] - }), - recipientsConfig: this.fb.group({ - targets: [[], Validators.required] }) }); - this.alarmCommentTemplateForm = this.fb.group({ - recipientsConfig: this.fb.group({ - targets: [[], Validators.required] - }) - }); + this.alarmCommentTemplateForm = this.fb.group({ }); this.triggerTypeFormsMap = new Map([ [TriggerType.ALARM, this.alarmTemplateForm], @@ -179,6 +192,7 @@ export class RuleNotificationDialogComponent extends } this.ruleNotificationForm.reset({}, {emitEvent: false}); this.ruleNotificationForm.patchValue(this.ruleNotification, {emitEvent: false}); + this.ruleNotificationForm.get('triggerType').updateValueAndValidity({onlySelf: true}); const currentForm = this.triggerTypeFormsMap.get(this.ruleNotification.triggerType); currentForm.patchValue(this.ruleNotification, {emitEvent: false}); if (this.ruleNotification.triggerType === TriggerType.DEVICE_INACTIVITY) { @@ -188,6 +202,12 @@ export class RuleNotificationDialogComponent extends } } + ngOnDestroy() { + super.ngOnDestroy(); + this.destroy$.next(); + this.destroy$.complete(); + } + changeStep($event: StepperSelectionEvent) { this.selectedIndex = $event.selectedIndex; } @@ -247,13 +267,30 @@ export class RuleNotificationDialogComponent extends }); } - ngOnDestroy() { - super.ngOnDestroy(); - this.destroy$.next(); - this.destroy$.complete(); - } - cancel(): void { this.dialogRef.close(null); } + + createTarget($event: Event, button: MatButton) { + if ($event) { + $event.stopPropagation(); + } + button._elementRef.nativeElement.blur(); + this.dialog.open(TargetNotificationDialogComponent, { + disableClose: true, + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], + data: {} + }).afterClosed() + .subscribe((res) => { + if (res) { + let formValue: string[] = this.ruleNotificationForm.get('recipientsConfig.targets').value; + if (!formValue) { + formValue = []; + } + formValue.push(res.id.id); + this.ruleNotificationForm.get('recipientsConfig.targets').patchValue(formValue); + } + }); + } } diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/targets-table/target-notification-dialog.componet.ts b/ui-ngx/src/app/modules/home/pages/notification-center/targets-table/target-notification-dialog.componet.ts index f77400fddf..651fd85dfe 100644 --- a/ui-ngx/src/app/modules/home/pages/notification-center/targets-table/target-notification-dialog.componet.ts +++ b/ui-ngx/src/app/modules/home/pages/notification-center/targets-table/target-notification-dialog.componet.ts @@ -145,7 +145,6 @@ export class TargetNotificationDialogComponent extends if (isDefined(this.data.target)) { formValue = Object.assign({}, this.data.target, formValue); } - formValue.type = formValue.configuration.type; this.notificationService.saveNotificationTarget(formValue).subscribe( (target) => this.dialogRef.close(target) ); 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 0c2a692cc7..4ffa5d8812 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 @@ -28,6 +28,12 @@ (click)="clear()"> close + (TemplateNotificationDialogComponent, { + disableClose: true, + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], + data: { + predefinedType: this.notificationTypes + } + }).afterClosed() + .subscribe((res) => { + if (res) { + this.selectTemplateFormGroup.get('templateName').patchValue(res); + } + }); + } + private updateView(value: EntityId | null) { if (!isEqual(this.modelValue, value)) { this.modelValue = value; diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/template-table/template-notification-dialog.component.html b/ui-ngx/src/app/modules/home/pages/notification-center/template-table/template-notification-dialog.component.html index 0810138e59..2b597c32b0 100644 --- a/ui-ngx/src/app/modules/home/pages/notification-center/template-table/template-notification-dialog.component.html +++ b/ui-ngx/src/app/modules/home/pages/notification-center/template-table/template-notification-dialog.component.html @@ -43,7 +43,7 @@ {{ 'notification.target-name-required' | translate }} - + notification.type 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 f09d8d67ca..94f207104a 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 @@ -29,7 +29,7 @@ import { Router } from '@angular/router'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { FormBuilder, FormGroup, ValidationErrors, Validators } from '@angular/forms'; import { NotificationService } from '@core/http/notification.service'; -import { deepClone, deepTrim } from '@core/utils'; +import { deepClone, deepTrim, isDefinedAndNotNull } from '@core/utils'; import { Observable, Subject } from 'rxjs'; import { map, takeUntil } from 'rxjs/operators'; import { StepperOrientation, StepperSelectionEvent } from '@angular/cdk/stepper'; @@ -40,6 +40,7 @@ import { TranslateService } from '@ngx-translate/core'; export interface TemplateNotificationDialogData { template?: NotificationTemplate; + predefinedType?: NotificationType; isAdd?: boolean; isCopy?: boolean; } @@ -69,6 +70,7 @@ export class TemplateNotificationDialogComponent notificationDeliveryMethodTranslateMap = NotificationDeliveryMethodTranslateMap; selectedIndex = 0; + hideSelectType = false; tinyMceOptions: Record = { base_url: '/assets/tinymce', @@ -100,9 +102,13 @@ export class TemplateNotificationDialogComponent this.stepperOrientation = this.breakpointObserver.observe(MediaBreakpoints['gt-xs']) .pipe(map(({matches}) => matches ? 'horizontal' : 'vertical')); + if (isDefinedAndNotNull(this.data?.predefinedType)) { + this.hideSelectType = true; + } + this.templateNotificationForm = this.fb.group({ name: ['', Validators.required], - notificationType: [NotificationType.GENERAL], + notificationType: [this.hideSelectType ? this.data.predefinedType : NotificationType.GENERAL], configuration: this.fb.group({ notificationSubject: ['', Validators.required], defaultTextTemplate: ['', Validators.required], diff --git a/ui-ngx/src/app/shared/components/entity/entity-list.component.html b/ui-ngx/src/app/shared/components/entity/entity-list.component.html index 7b89fb8999..2a14cea563 100644 --- a/ui-ngx/src/app/shared/components/entity/entity-list.component.html +++ b/ui-ngx/src/app/shared/components/entity/entity-list.component.html @@ -52,4 +52,7 @@ {{ requiredText }} +
+ +
diff --git a/ui-ngx/src/app/shared/models/notification.models.ts b/ui-ngx/src/app/shared/models/notification.models.ts index cf907dfe70..90e6cb93b3 100644 --- a/ui-ngx/src/app/shared/models/notification.models.ts +++ b/ui-ngx/src/app/shared/models/notification.models.ts @@ -131,7 +131,6 @@ export interface NonConfirmedNotificationEscalation { export interface NotificationTarget extends Omit, 'label'>{ tenantId: TenantId; - type: NotificationTargetType; configuration: NotificationTargetConfig; } diff --git a/ui-ngx/src/app/shared/pipe/date-ago.pipe.ts b/ui-ngx/src/app/shared/pipe/date-ago.pipe.ts index 6cfdc2d9bd..e746296355 100644 --- a/ui-ngx/src/app/shared/pipe/date-ago.pipe.ts +++ b/ui-ngx/src/app/shared/pipe/date-ago.pipe.ts @@ -39,14 +39,14 @@ export class DateAgoPipe implements PipeTransform { transform(value: number): string { if (value) { - const seconds = Math.floor((+new Date() - +new Date(value)) / 1000); - if (seconds < 29) { // less than 30 seconds ago will show as 'Just now' + const ms = Math.floor((+new Date() - +new Date(value))); + if (ms < 29 * SECOND) { // less than 30 seconds ago will show as 'Just now' return this.translate.instant('timewindow.just-now'); } let counter; // tslint:disable-next-line:forin for (const i in intervals) { - counter = Math.floor(seconds / intervals[i]); + counter = Math.floor(ms / intervals[i]); if (counter > 0) { return this.translate.instant(`timewindow.${i}`, {[i]: counter}); } 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 d6d6cb55ab..8a99967f57 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -2710,6 +2710,7 @@ "copy-rule": "Copy rule", "copy-template": "Copy template", "create-target": "Create recipient", + "create-new": "Create new", "created": "Created", "created-time": "Created time", "delete-request-text": "Be careful, after the confirmation the notification request will become unrecoverable.",