Browse Source

UI: Refactoring notification center and added notification template

pull/7980/head
Vladyslav_Prykhodko 4 years ago
parent
commit
154aa30b4c
  1. 2
      ui-ngx/src/app/modules/home/components/entity/entities-table.component.html
  2. 1
      ui-ngx/src/app/modules/home/models/entity/entities-table-config.models.ts
  3. 34
      ui-ngx/src/app/modules/home/pages/notification-center/notification-center.component.html
  4. 8
      ui-ngx/src/app/modules/home/pages/notification-center/notification-center.component.scss
  5. 4
      ui-ngx/src/app/modules/home/pages/notification-center/notification-center.component.ts
  6. 16
      ui-ngx/src/app/modules/home/pages/notification-center/notification-center.module.ts
  7. 15
      ui-ngx/src/app/modules/home/pages/notification-center/notification-table/notification-table.component.ts
  8. 15
      ui-ngx/src/app/modules/home/pages/notification-center/notification-table/targets-table-config.ts
  9. 72
      ui-ngx/src/app/modules/home/pages/notification-center/notification-table/template-table-config.ts
  10. 4
      ui-ngx/src/app/modules/home/pages/notification-center/targets-table/target-notification-dialog.component.html
  11. 2
      ui-ngx/src/app/modules/home/pages/notification-center/targets-table/target-notification-dialog.componet.ts
  12. 24
      ui-ngx/src/app/modules/home/pages/notification-center/targets-table/target-table-header.component.html
  13. 18
      ui-ngx/src/app/modules/home/pages/notification-center/targets-table/target-table-header.component.scss
  14. 38
      ui-ngx/src/app/modules/home/pages/notification-center/targets-table/target-table-header.component.ts
  15. 74
      ui-ngx/src/app/modules/home/pages/notification-center/template-dialog/template-notification-dialog.component.html
  16. 25
      ui-ngx/src/app/modules/home/pages/notification-center/template-dialog/template-notification-dialog.component.scss
  17. 95
      ui-ngx/src/app/modules/home/pages/notification-center/template-dialog/template-notification-dialog.component.ts
  18. 24
      ui-ngx/src/app/modules/home/pages/notification-center/template-dialog/template-table-header.component.html
  19. 18
      ui-ngx/src/app/modules/home/pages/notification-center/template-dialog/template-table-header.component.scss
  20. 38
      ui-ngx/src/app/modules/home/pages/notification-center/template-dialog/template-table-header.component.ts
  21. 22
      ui-ngx/src/app/shared/models/notification.models.ts
  22. 55
      ui-ngx/src/assets/locale/locale.constant-en_US.json

2
ui-ngx/src/app/modules/home/components/entity/entities-table.component.html

@ -35,7 +35,7 @@
<mat-drawer-content>
<div class="mat-padding tb-entity-table tb-absolute-fill">
<div fxLayout="column" class="mat-elevation-z1 tb-entity-table-content">
<mat-toolbar class="mat-table-toolbar" [fxShow]="!textSearchMode && dataSource.selection.isEmpty() && entitiesTableConfig.showTitle">
<mat-toolbar class="mat-table-toolbar" [fxShow]="!textSearchMode && dataSource.selection.isEmpty()">
<div class="mat-toolbar-tools">
<div fxLayout="row" fxLayoutAlign="start center" fxLayout.xs="column" fxLayoutAlign.xs="center start" class="title-container">
<span *ngIf="entitiesTableConfig.tableTitle" class="tb-entity-table-title">{{ entitiesTableConfig.tableTitle }}</span>

1
ui-ngx/src/app/modules/home/models/entity/entities-table-config.models.ts

@ -148,7 +148,6 @@ export class EntityTableConfig<T extends BaseData<HasId>, P extends PageLink = P
useTimePageLink = false;
defaultTimewindowInterval = historyInterval(DAY);
entityType: EntityType = null;
showTitle = true;
tableTitle = '';
selectionEnabled = true;
searchEnabled = true;

34
ui-ngx/src/app/modules/home/pages/notification-center/notification-center.component.html

@ -17,21 +17,21 @@
-->
<div class="tb-notification-center">
<div class="tb-notification-center-content">
<section fxLayout="row" fxLayoutAlign="space-between center" class="title-container">
<h2 translate class="title">notification.notification-center</h2>
<section class="action-buttons" fxLayoutAlign="end center">
<button mat-icon-button [disabled]="isLoading$ | async" (click)="openSetting()"
matTooltip="{{ 'notification.settings' | translate }}"
matTooltipPosition="above">
<mat-icon>settings</mat-icon>
</button>
<button mat-icon-button [disabled]="isLoading$ | async" (click)="updateData()"
matTooltip="{{ 'action.refresh' | translate }}"
matTooltipPosition="above">
<mat-icon>refresh</mat-icon>
</button>
</section>
</section>
<!-- <section fxLayout="row" fxLayoutAlign="space-between center" class="title-container">-->
<!-- <h2 translate class="title">notification.notification-center</h2>-->
<!-- <section class="action-buttons" fxLayoutAlign="end center">-->
<!-- <button mat-icon-button [disabled]="isLoading$ | async" (click)="openSetting()"-->
<!-- matTooltip="{{ 'notification.settings' | translate }}"-->
<!-- matTooltipPosition="above">-->
<!-- <mat-icon>settings</mat-icon>-->
<!-- </button>-->
<!-- <button mat-icon-button [disabled]="isLoading$ | async" (click)="updateData()"-->
<!-- matTooltip="{{ 'action.refresh' | translate }}"-->
<!-- matTooltipPosition="above">-->
<!-- <mat-icon>refresh</mat-icon>-->
<!-- </button>-->
<!-- </section>-->
<!-- </section>-->
<div class="tabs-container">
<mat-tab-group #matTabGroup (selectedIndexChange)="updateData()">
<mat-tab label="{{ 'notification.inbox' | translate }}" #inboxTab="matTab">
@ -62,9 +62,9 @@
<mat-tab disabled>
<ng-template mat-tab-label>
<div fxFlex="100" fxLayout="row" fxLayoutAlign="end center">
<button mat-flat-button color="primary" *ngIf="targetsTab.isActive" (click)="createTarget($event)">
<button mat-flat-button color="primary">
<div fxLayout="row" fxLayoutAlign="start center">
<mat-icon>add</mat-icon>{{ 'notification.create-target' | translate }}
<mat-icon>send</mat-icon>{{ 'notification.send-notification' | translate }}
</div>
</button>
</div>

8
ui-ngx/src/app/modules/home/pages/notification-center/notification-center.component.scss

@ -144,6 +144,14 @@
.tb-entity-table {
padding: 0;
.mat-toolbar-single-row, .mat-toolbar-tools {
height: 56px;
}
.title-container {
width: 100%;
}
}
}
}

4
ui-ngx/src/app/modules/home/pages/notification-center/notification-center.component.ts

@ -53,8 +53,4 @@ export class NotificationCenterComponent extends PageComponent {
private get currentTableComponent(): NotificationTableComponent {
return this.tableComponent.get(this.matTabs.selectedIndex);
}
createTarget($event: Event) {
this.currentTableComponent?.onEntityAction({event: $event, action: 'add', entity: null});
}
}

16
ui-ngx/src/app/modules/home/pages/notification-center/notification-center.module.ts

@ -23,12 +23,26 @@ import { HomeComponentsModule } from '@home/components/home-components.module';
import {
TargetNotificationDialogComponent
} from '@home/pages/notification-center/targets-table/target-notification-dialog.componet';
import { NotificationTableComponent } from '@home/pages/notification-center/notification-table/notification-table.component';
import {
NotificationTableComponent
} from '@home/pages/notification-center/notification-table/notification-table.component';
import {
TemplateNotificationDialogComponent
} from '@home/pages/notification-center/template-dialog/template-notification-dialog.component';
import {
TargetTableHeaderComponent
} from '@home/pages/notification-center/targets-table/target-table-header.component';
import {
TemplateTableHeaderComponent
} from '@home/pages/notification-center/template-dialog/template-table-header.component';
@NgModule({
declarations: [
NotificationCenterComponent,
TargetNotificationDialogComponent,
TemplateNotificationDialogComponent,
TargetTableHeaderComponent,
TemplateTableHeaderComponent,
NotificationTableComponent
],
imports: [

15
ui-ngx/src/app/modules/home/pages/notification-center/notification-table/notification-table.component.ts

@ -25,7 +25,6 @@ import { EntityTableConfig } from '@home/models/entity/entities-table-config.mod
import { InboxTableConfig } from '@home/pages/notification-center/notification-table/inbox-table-config';
import { DatePipe } from '@angular/common';
import { TemplateTableConfig } from '@home/pages/notification-center/notification-table/template-table-config';
import { EntityAction } from '@home/models/entity/entity-component.models';
@Component({
selector: 'tb-notification-table',
@ -49,10 +48,8 @@ export class NotificationTableComponent implements OnInit {
ngOnInit() {
this.entityTableConfig = this.getTableConfig();
this.entityTableConfig.pageMode = false;
this.entityTableConfig.showTitle = false;
this.entityTableConfig.detailsPanelEnabled = false;
this.entityTableConfig.selectionEnabled = false;
this.entityTableConfig.searchEnabled = false;
this.entityTableConfig.addEnabled = false;
}
@ -60,12 +57,6 @@ export class NotificationTableComponent implements OnInit {
this.entitiesTable.updateData();
}
onEntityAction(action: EntityAction<any>) {
if (this.entityTableConfig.onEntityAction) {
this.entityTableConfig.onEntityAction(action);
}
}
private getTableConfig(): EntityTableConfig<any> {
switch (this.notificationType) {
case EntityType.NOTIFICATION_TARGET:
@ -82,12 +73,14 @@ export class NotificationTableComponent implements OnInit {
case EntityType.NOTIFICATION_TEMPLATE:
return new TemplateTableConfig(
this.notificationService,
this.datePipe
this.translate,
this.dialog
);
case EntityType.NOTIFICATION_REQUEST:
return new TemplateTableConfig(
this.notificationService,
this.datePipe
this.translate,
this.dialog
);
}
}

15
ui-ngx/src/app/modules/home/pages/notification-center/notification-table/targets-table-config.ts

@ -30,6 +30,9 @@ import {
} from '@home/pages/notification-center/targets-table/target-notification-dialog.componet';
import { MatDialog } from '@angular/material/dialog';
import { EntityAction } from '@home/models/entity/entity-component.models';
import {
TargetTableHeaderComponent
} from '@home/pages/notification-center/targets-table/target-table-header.component';
export class TargetsTableConfig extends EntityTableConfig<NotificationTarget> {
@ -39,7 +42,8 @@ export class TargetsTableConfig extends EntityTableConfig<NotificationTarget> {
super();
this.loadDataOnInit = false;
this.entityTranslations = {
noEntities: 'notification.no-targets-notification'
noEntities: 'notification.no-targets-notification',
search: 'notification.search-targets'
};
this.entityResources = {} as EntityTypeResource<NotificationTarget>;
@ -50,15 +54,20 @@ export class TargetsTableConfig extends EntityTableConfig<NotificationTarget> {
this.deleteEntity = id => this.notificationService.deleteNotificationTarget(id.id);
this.cellActionDescriptors = this.configureCellActions();
this.headerComponent = TargetTableHeaderComponent;
this.onEntityAction = action => this.onTargetAction(action);
this.defaultSortOrder = {property: 'name', direction: Direction.ASC};
this.columns.push(
new EntityTableColumn<NotificationTarget>('name', 'notification.notification-target', '30%'),
new EntityTableColumn<NotificationTarget>('name', 'notification.notification-target', '20%'),
new EntityTableColumn<NotificationTarget>('configuration.type', 'notification.type', '40%',
(target) => this.translate.instant(NotificationTargetConfigTypeTranslateMap.get(target.configuration.type)),
() => ({}), false)
() => ({}), false),
new EntityTableColumn<NotificationTarget>('configuration.description', 'notification.description', '40%',
(target) => target.configuration.description || '',
() => ({}), false)
);
}

72
ui-ngx/src/app/modules/home/pages/notification-center/notification-table/template-table-config.ts

@ -15,39 +15,91 @@
///
import {
DateEntityTableColumn,
CellActionDescriptor,
EntityTableColumn,
EntityTableConfig
} from '@home/models/entity/entities-table-config.models';
import { EntityTypeResource } from '@shared/models/entity-type.models';
import { DatePipe } from '@angular/common';
import { Direction } from '@shared/models/page/sort-order';
import { NotificationTemplate } from '@shared/models/notification.models';
import { NotificationService } from '@core/http/notification.service';
import { EntityAction } from '@home/models/entity/entity-component.models';
import { MatDialog } from '@angular/material/dialog';
import {
TemplateNotificationDialogComponent,
TemplateNotificationDialogData
} from '@home/pages/notification-center/template-dialog/template-notification-dialog.component';
import { TranslateService } from '@ngx-translate/core';
import {
TemplateTableHeaderComponent
} from '@home/pages/notification-center/template-dialog/template-table-header.component';
export class TemplateTableConfig extends EntityTableConfig<NotificationTemplate> {
constructor(private notificationService: NotificationService,
private datePipe: DatePipe) {
private translate: TranslateService,
private dialog: MatDialog) {
super();
this.loadDataOnInit = false;
this.entitiesDeleteEnabled = false;
this.entityTranslations = {
noEntities: 'notification.no-inbox-notification'
noEntities: 'notification.no-notification-templates',
search: 'notification.search-templates'
};
this.entityResources = {} as EntityTypeResource<NotificationTemplate>;
this.entitiesFetchFunction = pageLink => this.notificationService.getNotificationTemplates(pageLink);
this.defaultSortOrder = {property: 'createdTime', direction: Direction.DESC};
this.deleteEntityTitle = template => this.translate.instant('notification.delete-template-title', {templateName: template.name});
this.deleteEntityContent = () => this.translate.instant('notification.delete-template-text');
this.deleteEntity = id => this.notificationService.deleteNotificationTemplate(id.id);
this.cellActionDescriptors = this.configureCellActions();
this.headerComponent = TemplateTableHeaderComponent;
this.onEntityAction = action => this.onTemplateAction(action);
this.defaultSortOrder = {property: 'notificationType', direction: Direction.ASC};
this.columns.push(
new DateEntityTableColumn<NotificationTemplate>('createdTime', 'notification.created-time', this.datePipe, '150px'),
new EntityTableColumn<NotificationTemplate>('type', 'notification.type', '10%'),
new EntityTableColumn<NotificationTemplate>('text', 'notification.text', '40%'),
new EntityTableColumn<NotificationTemplate>('info.description', 'notification.description', '50%')
new EntityTableColumn<NotificationTemplate>('notificationType', 'notification.type', '15%'),
new EntityTableColumn<NotificationTemplate>('name', 'notification.template', '25%'),
new EntityTableColumn<NotificationTemplate>('subject', 'notification.subject', '25%'),
new EntityTableColumn<NotificationTemplate>('configuration.defaultTextTemplate', 'notification.message', '35%',
(template) => template.configuration.defaultTextTemplate, () => ({}), false)
);
}
private configureCellActions(): Array<CellActionDescriptor<NotificationTemplate>> {
return [];
}
private editTemplate($event: Event, template: NotificationTemplate, isAdd = false) {
if ($event) {
$event.stopPropagation();
}
this.dialog.open<TemplateNotificationDialogComponent, TemplateNotificationDialogData,
NotificationTemplate>(TemplateNotificationDialogComponent, {
disableClose: true,
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
data: {
isAdd,
template
}
}).afterClosed()
.subscribe((res) => {
if (res) {
this.updateData();
}
});
}
private onTemplateAction(action: EntityAction<NotificationTemplate>): boolean {
switch (action.action) {
case 'add':
this.editTemplate(action.event, action.entity, true);
return true;
}
return false;
}
}

4
ui-ngx/src/app/modules/home/pages/notification-center/targets-table/target-notification-dialog.component.html

@ -63,6 +63,10 @@
*ngIf="!targetNotificationForm.get('configuration.getCustomerIdFromOriginatorEntity').value">
</tb-entity-autocomplete>
</section>
<mat-form-field class="mat-block">
<mat-label translate>notification.description</mat-label>
<input matInput formControlName="description">
</mat-form-field>
</section>
</div>
<mat-divider></mat-divider>

2
ui-ngx/src/app/modules/home/pages/notification-center/targets-table/target-notification-dialog.componet.ts

@ -70,6 +70,7 @@ export class TargetNotificationDialogComponent extends
name: [null, Validators.required],
configuration: this.fb.group({
type: [NotificationTargetConfigType.ALL_USERS],
description: [null],
usersIds: [{value: null, disabled: true}, Validators.required],
customerId: [{value: null, disabled: true}, Validators.required],
getCustomerIdFromOriginatorEntity: [{value: false, disabled: true}],
@ -90,6 +91,7 @@ export class TargetNotificationDialogComponent extends
break;
}
this.targetNotificationForm.get('configuration.type').enable({emitEvent: false});
this.targetNotificationForm.get('configuration.description').enable({emitEvent: false});
});
this.targetNotificationForm.get('configuration.getCustomerIdFromOriginatorEntity').valueChanges.pipe(
takeUntil(this.destroy$)

24
ui-ngx/src/app/modules/home/pages/notification-center/targets-table/target-table-header.component.html

@ -0,0 +1,24 @@
<!--
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.
-->
<div fxFlex="100" fxLayout="row" fxLayoutAlign="end center">
<button mat-stroked-button color="primary" (click)="createTarget($event)">
<div fxLayout="row" fxLayoutAlign="start center">
<mat-icon>add</mat-icon>{{ 'notification.add-target' | translate }}
</div>
</button>
</div>

18
ui-ngx/src/app/modules/home/pages/notification-center/targets-table/target-table-header.component.scss

@ -0,0 +1,18 @@
/**
* 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.
*/
:host{
width: 100%;
}

38
ui-ngx/src/app/modules/home/pages/notification-center/targets-table/target-table-header.component.ts

@ -0,0 +1,38 @@
///
/// 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 { Component } from '@angular/core';
import { EntityTableHeaderComponent } from '@home/components/entity/entity-table-header.component';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { NotificationTarget } from '@shared/models/notification.models';
@Component({
selector: 'tb-target-table-header',
templateUrl: './target-table-header.component.html',
styleUrls: ['target-table-header.component.scss']
})
export class TargetTableHeaderComponent extends EntityTableHeaderComponent<NotificationTarget> {
constructor(protected store: Store<AppState>) {
super(store);
}
createTarget($event: Event) {
this.entitiesTableConfig.onEntityAction({event: $event, action: 'add', entity: null});
}
}

74
ui-ngx/src/app/modules/home/pages/notification-center/template-dialog/template-notification-dialog.component.html

@ -0,0 +1,74 @@
<!--
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.
-->
<mat-toolbar color="primary">
<h2>{{ dialogTitle | translate }}</h2>
<span fxFlex></span>
<button mat-icon-button
(click)="cancel()"
type="button">
<mat-icon class="material-icons">close</mat-icon>
</button>
</mat-toolbar>
<mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async">
</mat-progress-bar>
<div style="height: 4px;" *ngIf="!(isLoading$ | async)"></div>
<form mat-dialog-content [formGroup]="templateNotificationForm">
<mat-form-field class="mat-block">
<mat-label translate>notification.target-name</mat-label>
<input matInput formControlName="name" required>
<mat-error *ngIf="templateNotificationForm.get('name').hasError('required')">
{{ 'notification.target-name-required' | translate }}
</mat-error>
</mat-form-field>
<label style="margin-bottom: 8px">{{ 'notification.type' | translate }}<sup> *</sup></label>
<mat-radio-group formControlName="type">
<mat-radio-button [value]="NotificationType.GENERIC">
<div fxLayout="column">
<div>Generic</div>
<div class="tb-hint">hint</div>
</div>
</mat-radio-button>
<mat-radio-button [value]="NotificationType.ALARM">
<div>Alarm</div>
<div class="tb-hint">hint</div>
</mat-radio-button>
</mat-radio-group>
<section formGroupName="configuration">
<mat-form-field class="mat-block">
<mat-label translate>notification.message</mat-label>
<input matInput formControlName="defaultTextTemplate" required>
<mat-error *ngIf="templateNotificationForm.get('configuration.defaultTextTemplate').hasError('required')">
{{ 'notification.message-required' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field class="mat-block">
<mat-label translate>notification.subject</mat-label>
<input matInput required>
</mat-form-field>
</section>
</form>
<mat-divider></mat-divider>
<div mat-dialog-actions fxLayout="row" fxLayoutGap="8px" fxLayoutAlign="end">
<button mat-button
[disabled]="(isLoading$ | async)"
(click)="cancel()">{{ 'action.cancel' | translate }}</button>
<button mat-raised-button
[disabled]="(isLoading$ | async) || templateNotificationForm.invalid || !templateNotificationForm.dirty"
color="primary"
(click)="save()">{{ saveButtonLabel | translate }}</button>
</div>

25
ui-ngx/src/app/modules/home/pages/notification-center/template-dialog/template-notification-dialog.component.scss

@ -0,0 +1,25 @@
:host {
width: 600px;
.tb-hint {
padding: 0;
}
}
:host ::ng-deep {
.mat-radio-group {
display: flex;
flex-direction: row;
.mat-radio-button {
flex: 1 1 100%;
padding: 14px;
border: 1px solid rgba(0, 0, 0, 0.12);
border-radius: 6px;
&:not(:last-child){
margin-right: 8px;
}
}
}
}

95
ui-ngx/src/app/modules/home/pages/notification-center/template-dialog/template-notification-dialog.component.ts

@ -0,0 +1,95 @@
///
/// 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 { NotificationTemplate, NotificationType } from '@shared/models/notification.models';
import { Component, Inject, 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 { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { NotificationService } from '@core/http/notification.service';
import { deepTrim, isDefined } from '@core/utils';
import { Subject } from 'rxjs';
export interface TemplateNotificationDialogData {
template?: NotificationTemplate;
isAdd?: boolean;
isCopy?: boolean;
}
@Component({
selector: 'tb-template-notification-dialog',
templateUrl: './template-notification-dialog.component.html',
styleUrls: ['./template-notification-dialog.component.scss']
})
export class TemplateNotificationDialogComponent
extends DialogComponent<TemplateNotificationDialogComponent, NotificationTemplate> implements OnDestroy {
templateNotificationForm: FormGroup;
dialogTitle = 'notification.edit-notification-template';
saveButtonLabel = 'action.save';
NotificationType = NotificationType;
private readonly destroy$ = new Subject<void>();
constructor(protected store: Store<AppState>,
protected router: Router,
protected dialogRef: MatDialogRef<TemplateNotificationDialogComponent, NotificationTemplate>,
@Inject(MAT_DIALOG_DATA) public data: TemplateNotificationDialogData,
private fb: FormBuilder,
private notificationService: NotificationService) {
super(store, router, dialogRef);
if (data.isAdd) {
this.dialogTitle = 'notification.add-notification-template';
this.saveButtonLabel = 'action.add';
}
if (data.isCopy) {
this.dialogTitle = 'notification.copy-notification-template';
}
this.templateNotificationForm = this.fb.group({
name: [null, Validators.required],
type: [NotificationType.GENERIC],
configuration: this.fb.group({
defaultTextTemplate: [null, Validators.required]
})
});
}
ngOnDestroy() {
super.ngOnDestroy();
this.destroy$.next();
this.destroy$.complete();
}
cancel(): void {
this.dialogRef.close(null);
}
save() {
let formValue = deepTrim(this.templateNotificationForm.value);
if (isDefined(this.data.template)) {
formValue = Object.assign({}, this.data.template, formValue);
}
this.notificationService.saveNotificationTemplate(formValue).subscribe(
(target) => this.dialogRef.close(target)
);
}
}

24
ui-ngx/src/app/modules/home/pages/notification-center/template-dialog/template-table-header.component.html

@ -0,0 +1,24 @@
<!--
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.
-->
<div fxFlex="100" fxLayout="row" fxLayoutAlign="end center">
<button mat-stroked-button color="primary" (click)="createTemplate($event)">
<div fxLayout="row" fxLayoutAlign="start center">
<mat-icon>add</mat-icon>{{ 'notification.add-template' | translate }}
</div>
</button>
</div>

18
ui-ngx/src/app/modules/home/pages/notification-center/template-dialog/template-table-header.component.scss

@ -0,0 +1,18 @@
/**
* 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.
*/
:host{
width: 100%;
}

38
ui-ngx/src/app/modules/home/pages/notification-center/template-dialog/template-table-header.component.ts

@ -0,0 +1,38 @@
///
/// 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 { Component } from '@angular/core';
import { EntityTableHeaderComponent } from '@home/components/entity/entity-table-header.component';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { NotificationTemplate } from '@shared/models/notification.models';
@Component({
selector: 'tb-template-table-header',
templateUrl: './template-table-header.component.html',
styleUrls: ['template-table-header.component.scss']
})
export class TemplateTableHeaderComponent extends EntityTableHeaderComponent<NotificationTemplate> {
constructor(protected store: Store<AppState>) {
super(store);
}
createTemplate($event: Event) {
this.entitiesTableConfig.onEntityAction({event: $event, action: 'add', entity: null});
}
}

22
ui-ngx/src/app/shared/models/notification.models.ts

@ -108,6 +108,7 @@ export interface NotificationTarget extends Omit<BaseData<NotificationTargetId>,
export interface NotificationTargetConfig extends
Partial<UserListNotificationTargetConfig & CustomerUsersNotificationTargetConfig>{
type: NotificationTargetConfigType;
description?: string;
}
interface UserListNotificationTargetConfig {
@ -121,21 +122,27 @@ interface CustomerUsersNotificationTargetConfig {
export interface NotificationTemplate extends Omit<BaseData<NotificationTemplateId>, 'label'>{
tenantId: TenantId;
notificationType: string;
notificationType: NotificationType;
configuration: NotificationTemplateConfig;
}
interface NotificationTemplateConfig {
defaultTextTemplate: string;
templates: Map<NotificationDeliveryMethod, DeliveryMethodNotificationTemplate>;
deliveryMethodsTemplates: Map<NotificationDeliveryMethod, DeliveryMethodNotificationTemplate>;
}
interface DeliveryMethodNotificationTemplate extends
Partial<EmailDeliveryMethodNotificationTemplate & SlackDeliveryMethodNotificationTemplate>{
body: string;
Partial<PushDeliveryMethodNotificationTemplate & EmailDeliveryMethodNotificationTemplate & SlackDeliveryMethodNotificationTemplate>{
body?: string;
method: NotificationDeliveryMethod;
}
interface PushDeliveryMethodNotificationTemplate {
subject?: string;
icon?: string;
actionButtonConfig?: string;
}
interface EmailDeliveryMethodNotificationTemplate {
subject: string;
}
@ -157,7 +164,7 @@ export enum NotificationStatus {
}
export enum NotificationDeliveryMethod {
WEBSOCKET = 'WEBSOCKET',
PUSH = 'PUSH',
SMS = 'SMS',
EMAIL = 'EMAIL',
SLACK = 'SLACK'
@ -185,3 +192,8 @@ export const NotificationTargetConfigTypeTranslateMap = new Map<NotificationTarg
[NotificationTargetConfigType.USER_LIST, 'notification.target-type.user-list'],
[NotificationTargetConfigType.CUSTOMER_USERS, 'notification.target-type.customer-users'],
]);
export enum NotificationType {
GENERIC = 'GENERIC',
ALARM = 'ALARM'
}

55
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -2666,35 +2666,50 @@
"copied": "Copied!"
},
"notification": {
"notification-center": "Notification center",
"management": "Notification management",
"settings": "Notification settings",
"inbox": "Inbox",
"sent": "Sent",
"templates": "Templates",
"targets": "Targets",
"rules": "Rules",
"add-notification-target": "Add notification target",
"add-notification-template": "Add notification template",
"add-target": "Add target",
"add-template": "Add template",
"copy-notification-template": "Copy notification template",
"create-target": "Create target",
"created-time": "Created time",
"type": "Type",
"delete-target-text": "Be careful, after the confirmation the notification target will become unrecoverable.",
"delete-target-title": "Are you sure you want to delete the notification target '{{targetName}}'?",
"delete-template-text": "Be careful, after the confirmation the notification template will become unrecoverable.",
"delete-template-title": "Are you sure you want to delete the notification template '{{templateName}}'?",
"description": "Description",
"edit-notification-target": "Edit notification target",
"edit-notification-template": "Edit notification template",
"get-customer-id-from-originator": "Get Customer id from originator",
"inbox": "Inbox",
"management": "Notification management",
"message": "Message",
"message-required": "Message is required",
"no-inbox-notification": "No notification found",
"no-notification-templates": "No notification templates",
"no-targets-notification": "No targets notification",
"text": "Text",
"description": "Description",
"notification-center": "Notification center",
"notification-target": "Notification target",
"create-target": "Create target",
"add-notification-target": "Add notification target",
"edit-notification-target": "Edit notification target",
"rules": "Rules",
"search-targets": "Search targets",
"search-templates": "Search templates",
"send-notification": "Send notification",
"sent": "Sent",
"settings": "Notification settings",
"subject": "Subject",
"target-name": "Name",
"target-name-required": "Name is required",
"target-type": {
"type": "Type",
"all-users": "All users",
"user-list": "User list",
"customer-users": "Customer users"
"customer-users": "Customer users",
"type": "Type",
"user-list": "User list"
},
"get-customer-id-from-originator": "Get Customer id from originator",
"delete-target-title": "Are you sure you want to delete the notification target '{{targetName}}'?",
"delete-target-text": "Be careful, after the confirmation the notification target will become unrecoverable."
"targets": "Targets",
"template": "Template",
"templates": "Templates",
"text": "Text",
"type": "Type"
},
"ota-update": {
"add": "Add package",

Loading…
Cancel
Save