diff --git a/ui-ngx/src/app/core/http/entity.service.ts b/ui-ngx/src/app/core/http/entity.service.ts index 744245ca19..e9ad2612e8 100644 --- a/ui-ngx/src/app/core/http/entity.service.ts +++ b/ui-ngx/src/app/core/http/entity.service.ts @@ -252,7 +252,7 @@ export class EntityService { entityIds); break; case EntityType.NOTIFICATION_TARGET: - observable = of([]); + observable = this.notificationService.getNotificationTargetsByIds(entityIds, config); break; } return observable; diff --git a/ui-ngx/src/app/core/http/notification.service.ts b/ui-ngx/src/app/core/http/notification.service.ts index 348ba7f6ef..9f18b59bc2 100644 --- a/ui-ngx/src/app/core/http/notification.service.ts +++ b/ui-ngx/src/app/core/http/notification.service.ts @@ -122,6 +122,11 @@ export class NotificationService { return this.http.delete(`/api/notification/target/${id}`, defaultHttpOptionsFromConfig(config)); } + public getNotificationTargetsByIds(ids: string[], config?: RequestConfig): Observable> { + return this.http.get>(`/api/notification/targets?ids=${ids.join(',')}`, + defaultHttpOptionsFromConfig(config)); + } + public getNotificationTargets(pageLink: PageLink, config?: RequestConfig): Observable> { return this.http.get>(`/api/notification/targets${pageLink.toQuery()}`, defaultHttpOptionsFromConfig(config)); diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/notification-table/targets-table-config.ts b/ui-ngx/src/app/modules/home/pages/notification-center/notification-table/targets-table-config.ts index 827d811f5d..16cb1fa1e6 100644 --- a/ui-ngx/src/app/modules/home/pages/notification-center/notification-table/targets-table-config.ts +++ b/ui-ngx/src/app/modules/home/pages/notification-center/notification-table/targets-table-config.ts @@ -21,7 +21,7 @@ import { } from '@home/models/entity/entities-table-config.models'; import { EntityTypeResource } from '@shared/models/entity-type.models'; import { Direction } from '@shared/models/page/sort-order'; -import { NotificationTarget, NotificationTargetConfigTypeTranslateMap } from '@shared/models/notification.models'; +import { NotificationTarget, NotificationTargetTypeTranslationMap } from '@shared/models/notification.models'; import { NotificationService } from '@core/http/notification.service'; import { TranslateService } from '@ngx-translate/core'; import { @@ -62,9 +62,8 @@ export class TargetsTableConfig extends EntityTableConfig { this.columns.push( new EntityTableColumn('name', 'notification.notification-target', '20%'), - new EntityTableColumn('configuration.type', 'notification.type', '40%', - (target) => this.translate.instant(NotificationTargetConfigTypeTranslateMap.get(target.configuration.type)), - () => ({}), false), + new EntityTableColumn('type', 'notification.type', '40%', + (target) => this.translate.instant(NotificationTargetTypeTranslationMap.get(target.type))), new EntityTableColumn('configuration.description', 'notification.description', '40%', (target) => target.configuration.description || '', () => ({}), false) diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/targets-table/target-notification-dialog.component.html b/ui-ngx/src/app/modules/home/pages/notification-center/targets-table/target-notification-dialog.component.html index 7d03645d31..9bbf2a9829 100644 --- a/ui-ngx/src/app/modules/home/pages/notification-center/targets-table/target-notification-dialog.component.html +++ b/ui-ngx/src/app/modules/home/pages/notification-center/targets-table/target-notification-dialog.component.html @@ -36,35 +36,45 @@ {{ 'notification.target-name-required' | translate }} + + +
+
{{ notificationTargetTypeTranslationMap.get(notificationTargetType) | translate }}
+
+
+
- - notification.target-type.type - - - {{ notificationTargetConfigTypeTranslateMap.get(type) | translate }} - - - - - -
- - {{ 'notification.get-customer-id-from-originator' | translate }} - - + + notification.target-type.type + + + {{ notificationTargetConfigTypeTranslateMap.get(type) | translate }} + + + + - + formControlName="usersIds" + [entityType]="entityType.USER" + labelText="user.user-list" + placeholderText="user.user" + requiredText="user.user-list-required" + *ngIf="targetNotificationForm.get('configuration.usersFilter.type').value === notificationTargetConfigType.USER_LIST"> + +
+ + {{ 'notification.get-customer-id-from-originator' | translate }} + + + +
notification.description diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/targets-table/target-notification-dialog.componet.scss b/ui-ngx/src/app/modules/home/pages/notification-center/targets-table/target-notification-dialog.componet.scss new file mode 100644 index 0000000000..18a5bf0ba9 --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/notification-center/targets-table/target-notification-dialog.componet.scss @@ -0,0 +1,39 @@ +/** + * 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 "../../../../../../theme"; + +:host ::ng-deep { + .mat-radio-group { + display: flex; + flex-direction: row; + margin-bottom: 8px; + + .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; + } + + &.mat-radio-checked { + border-color: map_get($tb-accent, 500); + } + } + } +} 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 0eb6f7d6fe..6d69db61aa 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 @@ -17,7 +17,9 @@ import { NotificationTarget, NotificationTargetConfigType, - NotificationTargetConfigTypeTranslateMap + NotificationTargetConfigTypeTranslateMap, + NotificationTargetType, + NotificationTargetTypeTranslationMap } from '@shared/models/notification.models'; import { Component, Inject, OnDestroy } from '@angular/core'; import { DialogComponent } from '@shared/components/dialog.component'; @@ -40,12 +42,15 @@ export interface TargetsNotificationDialogData { @Component({ selector: 'tb-target-notification-dialog', templateUrl: './target-notification-dialog.component.html', - styleUrls: [] + styleUrls: ['target-notification-dialog.componet.scss'] }) export class TargetNotificationDialogComponent extends DialogComponent implements OnDestroy { targetNotificationForm: FormGroup; + notificationTargetType = NotificationTargetType; + notificationTargetTypes: NotificationTargetType[] = Object.values(NotificationTargetType); + notificationTargetTypeTranslationMap = NotificationTargetTypeTranslationMap; notificationTargetConfigType = NotificationTargetConfigType; notificationTargetConfigTypes: NotificationTargetConfigType[] = Object.values(NotificationTargetConfigType); notificationTargetConfigTypeTranslateMap = NotificationTargetConfigTypeTranslateMap; @@ -68,44 +73,46 @@ export class TargetNotificationDialogComponent extends this.targetNotificationForm = this.fb.group({ name: [null, Validators.required], + type: [NotificationTargetType.PLATFORM_USERS], 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}], + usersFilter: this.fb.group({ + type: [NotificationTargetConfigType.ALL_USERS], + usersIds: [{value: null, disabled: true}, Validators.required], + customerId: [{value: null, disabled: true}, Validators.required], + getCustomerIdFromOriginatorEntity: [{value: false, disabled: true}] + }) }) }); - this.targetNotificationForm.get('configuration.type').valueChanges.pipe( + this.targetNotificationForm.get('configuration.usersFilter.type').valueChanges.pipe( takeUntil(this.destroy$) ).subscribe((type: NotificationTargetConfigType) => { - this.targetNotificationForm.get('configuration').disable({emitEvent: false}); + this.targetNotificationForm.get('configuration.usersFilter').disable({emitEvent: false}); switch (type) { case NotificationTargetConfigType.USER_LIST: - this.targetNotificationForm.get('configuration.usersIds').enable({emitEvent: false}); + this.targetNotificationForm.get('configuration.usersFilter.usersIds').enable({emitEvent: false}); break; case NotificationTargetConfigType.CUSTOMER_USERS: - this.targetNotificationForm.get('configuration.getCustomerIdFromOriginatorEntity').enable({emitEvent: false}); - this.targetNotificationForm.get('configuration.getCustomerIdFromOriginatorEntity').updateValueAndValidity({onlySelf: true}); + this.targetNotificationForm.get('configuration.usersFilter.getCustomerIdFromOriginatorEntity').enable({onlySelf: true}); break; } - this.targetNotificationForm.get('configuration.type').enable({emitEvent: false}); - this.targetNotificationForm.get('configuration.description').enable({emitEvent: false}); + this.targetNotificationForm.get('configuration.usersFilter.type').enable({emitEvent: false}); }); - this.targetNotificationForm.get('configuration.getCustomerIdFromOriginatorEntity').valueChanges.pipe( + this.targetNotificationForm.get('configuration.usersFilter.getCustomerIdFromOriginatorEntity').valueChanges.pipe( takeUntil(this.destroy$) ).subscribe((value: boolean) => { if (value) { - this.targetNotificationForm.get('configuration.customerId').disable({emitEvent: false}); + this.targetNotificationForm.get('configuration.usersFilter.customerId').disable({emitEvent: false}); } else { - this.targetNotificationForm.get('configuration.customerId').enable({emitEvent: false}); + this.targetNotificationForm.get('configuration.usersFilter.customerId').enable({emitEvent: false}); } }); if (isDefined(data.target)) { this.targetNotificationForm.patchValue(data.target, {emitEvent: false}); - this.targetNotificationForm.get('configuration.type').updateValueAndValidity({onlySelf: true}); + this.targetNotificationForm.get('type').updateValueAndValidity({onlySelf: true}); + this.targetNotificationForm.get('configuration.usersFilter.type').updateValueAndValidity({onlySelf: true}); } } @@ -124,6 +131,7 @@ export class TargetNotificationDialogComponent extends if (isDefined(this.data.target)) { formValue = Object.assign({}, this.data.target, formValue); } + formValue.configuration.type = formValue.type; this.notificationService.saveNotificationTarget(formValue).subscribe( (target) => this.dialogRef.close(target) ); diff --git a/ui-ngx/src/app/shared/models/notification.models.ts b/ui-ngx/src/app/shared/models/notification.models.ts index ab6ae3a6c6..4fe90210a5 100644 --- a/ui-ngx/src/app/shared/models/notification.models.ts +++ b/ui-ngx/src/app/shared/models/notification.models.ts @@ -120,13 +120,21 @@ export interface NonConfirmedNotificationEscalation { export interface NotificationTarget extends Omit, 'label'>{ tenantId: TenantId; + type: NotificationTargetType; configuration: NotificationTargetConfig; } -export interface NotificationTargetConfig extends +export interface NotificationTargetConfig extends Partial { + description?: string; + type: NotificationTargetType; +} +export interface PlatformUsersNotificationTargetConfig { + usersFilter: UsersFilter; +} + +export interface UsersFilter extends Partial{ type: NotificationTargetConfigType; - description?: string; } interface UserListNotificationTargetConfig { @@ -138,6 +146,21 @@ interface CustomerUsersNotificationTargetConfig { getCustomerIdFromOriginatorEntity: boolean; } +export interface SlackNotificationTargetConfig { + conversationType: SlackConversation; + conversationId: string; + conversationName: string; +} +export enum NotificationTargetType { + PLATFORM_USERS = 'PLATFORM_USERS', + SLACK = 'SLACK' +} + +export const NotificationTargetTypeTranslationMap = new Map([ + [NotificationTargetType.PLATFORM_USERS, 'notification.platform-users'], + [NotificationTargetType.SLACK, 'notification.slack'] +]); + export interface NotificationTemplate extends Omit, 'label'>{ tenantId: TenantId; notificationType: NotificationType; 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 e0c0e452e6..5e61277fde 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -2733,6 +2733,7 @@ }, "review": "Review", "rules": "Rules", + "platform-users": "Platform users", "search-notification": "Search notification", "search-targets": "Search recipients", "search-templates": "Search templates", @@ -2740,6 +2741,7 @@ "send-test-notification": "Send test notification", "sent": "Sent", "settings": "Notification settings", + "slack": "Slack", "slack-chanel-type": "Slack chanel type", "slack-chanel-types": { "direct": "Direct message",