-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Content 1 - Loaded
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Content 1 - Loaded
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
Notification settings
+
+
+
+
+
+
+
+
diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/notification-center.component.scss b/ui-ngx/src/app/modules/home/pages/notification-center/notification-center.component.scss
index e3726e4c02..dae717255b 100644
--- a/ui-ngx/src/app/modules/home/pages/notification-center/notification-center.component.scss
+++ b/ui-ngx/src/app/modules/home/pages/notification-center/notification-center.component.scss
@@ -20,11 +20,14 @@
height: 100%;
display: block;
.tb-notification-center {
- padding: 8px;
width: 100%;
height: 100%;
display: block;
+ .tb-notification-draw-container {
+ margin: 8px;
+ }
+
.tb-notification-center-content {
width: 100%;
height: 100%;
@@ -55,52 +58,34 @@
flex-direction: column;
flex: 1 1 100%;
}
+ }
+
+ .notification-settings {
+ width: 100%;
+ padding: 24px;
+
+ .title {
+ margin: 0;
+ line-height: 1.4rem;
+ }
- //.mat-toolbar-tools{
- // min-height: auto;
- //}
- //
- //.title-container{
- // overflow: hidden;
- //}
- //
- //.tb-entity-table-title {
- // padding-right: 20px;
- // white-space: nowrap;
- // overflow: hidden;
- // text-overflow: ellipsis;
- //}
- //
- //.table-container {
- // overflow: auto;
- //}
- //
- //.tb-entity-table-info{
- // white-space: nowrap;
- // overflow: hidden;
- // text-overflow: ellipsis;
- //}
- //
- //.button-widget-action{
- // margin-left: auto;
- // overflow: hidden;
- // text-overflow: ellipsis;
- //}
+ .fields-group {
+ padding: 8px 16px 0;
+ margin: 10px 0;
+ border: 1px groove rgba(0, 0, 0, .25);
+ border-radius: 4px;
+
+ legend {
+ color: rgba(0, 0, 0, .7);
+ }
+
+ .delivery-method {
+ margin-bottom: 8px;
+ }
+ }
}
}
- //@media #{$mat-xs} {
- // .mat-toolbar {
- // height: auto;
- // min-height: 100px;
- //
- // .tb-entity-table-title{
- // padding-bottom: 5px;
- // width: 100%;
- // }
- // }
- //}
-
@media #{$mat-xs} {
.tb-notification-center {
.tb-notification-center-content {
diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/notification-center.component.ts b/ui-ngx/src/app/modules/home/pages/notification-center/notification-center.component.ts
index 64635cb470..6eceb003c6 100644
--- a/ui-ngx/src/app/modules/home/pages/notification-center/notification-center.component.ts
+++ b/ui-ngx/src/app/modules/home/pages/notification-center/notification-center.component.ts
@@ -14,7 +14,7 @@
/// limitations under the License.
///
-import { Component, QueryList, ViewChild, ViewChildren } from '@angular/core';
+import { AfterViewInit, Component, QueryList, ViewChild, ViewChildren } from '@angular/core';
import { PageComponent } from '@shared/components/page.component';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
@@ -23,16 +23,30 @@ import {
NotificationTableComponent
} from '@home/pages/notification-center/notification-table/notification-table.component';
import { EntityType } from '@shared/models/entity-type.models';
+import { MatDrawer } from '@angular/material/sidenav';
+import { NotificationService } from '@core/http/notification.service';
+import {
+ NotificationDeliveryMethod,
+ NotificationDeliveryMethodTranslateMap,
+ NotificationTemplateTypeTranslateMap
+} from '@shared/models/notification.models';
+import { FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { deepTrim } from '@core/utils';
@Component({
selector: 'tb-notification-center',
templateUrl: './notification-center.component.html',
styleUrls: ['notification-center.component.scss']
})
-export class NotificationCenterComponent extends PageComponent {
+export class NotificationCenterComponent extends PageComponent implements AfterViewInit {
entityType = EntityType;
+ notificationSettingsForm: FormGroup;
+ notificationDeliveryMethods = Object.keys(NotificationDeliveryMethod) as NotificationDeliveryMethod[];
+ notificationDeliveryMethodTranslateMap = NotificationDeliveryMethodTranslateMap;
+
+ @ViewChild('notificationSettings', {static: true}) notificationSettings!: MatDrawer;
@ViewChild('matTabGroup', {static: true}) matTabs: MatTabGroup;
@ViewChild('requestTab', {static: true}) requestTab: MatTab;
@ViewChild('notificationRequest', {static: true}) notificationRequestTable: NotificationTableComponent;
@@ -40,8 +54,38 @@ export class NotificationCenterComponent extends PageComponent {
constructor(
- protected store: Store
) {
+ protected store: Store,
+ private notificationService: NotificationService,
+ private fb: FormBuilder) {
super(store);
+ this.notificationSettingsForm = this.fb.group({
+ deliveryMethodsConfigs: this.fb.group({})
+ });
+ this.notificationDeliveryMethods.forEach(method => {
+ (this.notificationSettingsForm.get('deliveryMethodsConfigs') as FormGroup)
+ .addControl(method, this.fb.group({method, enabled: method !== NotificationDeliveryMethod.SLACK}), {emitEvent: false});
+ });
+ (this.notificationSettingsForm.get('deliveryMethodsConfigs.SLACK') as FormGroup)
+ .addControl('botToken', this.fb.control({value: '', disabled: true}, Validators.required), {emitEvent: false});
+ this.notificationSettingsForm.get('deliveryMethodsConfigs.SLACK.enabled').valueChanges.subscribe(value => {
+ if (value) {
+ this.notificationSettingsForm.get('deliveryMethodsConfigs.SLACK.botToken').enable({emitEvent: true});
+ } else {
+ this.notificationSettingsForm.get('deliveryMethodsConfigs.SLACK.botToken').disable({emitEvent: true});
+
+ }
+ });
+ }
+
+ ngAfterViewInit() {
+ this.notificationSettings.openedStart.subscribe(() => {
+ this.notificationService.getNotificationSettings().subscribe(
+ value => {
+ this.notificationSettingsForm.patchValue(value, {emitEvent: false});
+ this.notificationSettingsForm.get('deliveryMethodsConfigs.SLACK.enabled').updateValueAndValidity({onlySelf: true});
+ }
+ );
+ });
}
updateData() {
@@ -59,4 +103,19 @@ export class NotificationCenterComponent extends PageComponent {
sendNotification($event: Event) {
this.notificationRequestTable.entityTableConfig.onEntityAction({event: $event, action: this.requestTab.isActive ? 'add' : 'add-without-update', entity: null});
}
+
+ toggleNotificationSettings() {
+ this.notificationSettings.toggle().then(() => {});
+ }
+
+ saveNotificationSettigs($event: Event) {
+ if ($event) {
+ $event.stopPropagation();
+ }
+ const formValue = deepTrim(this.notificationSettingsForm.getRawValue());
+ this.notificationService.saveNotificationSettings(formValue).subscribe(value => {
+ this.notificationSettingsForm.patchValue(value, {emitEvent: false});
+ this.notificationSettingsForm.markAsPristine();
+ });
+ }
}
diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/notification-table/inbox-table-config.ts b/ui-ngx/src/app/modules/home/pages/notification-center/notification-table/inbox-table-config.ts
index 482100b168..247206ff68 100644
--- a/ui-ngx/src/app/modules/home/pages/notification-center/notification-table/inbox-table-config.ts
+++ b/ui-ngx/src/app/modules/home/pages/notification-center/notification-table/inbox-table-config.ts
@@ -32,12 +32,14 @@ import { NotificationService } from '@core/http/notification.service';
import { InboxTableHeaderComponent } from '@home/pages/notification-center/inbox-table/inbox-table-header.component';
import { TranslateService } from '@ngx-translate/core';
import { take } from 'rxjs/operators';
+import { EventEmitter } from '@angular/core';
export class InboxTableConfig extends EntityTableConfig {
constructor(private notificationService: NotificationService,
private translate: TranslateService,
- private datePipe: DatePipe) {
+ private datePipe: DatePipe,
+ private toggleSettings: EventEmitter) {
super();
this.entitiesDeleteEnabled = false;
this.entityTranslations = {
@@ -58,12 +60,20 @@ export class InboxTableConfig extends EntityTableConfig {
this.headerComponent = InboxTableHeaderComponent;
- this.headerActionDescriptors = [{
- name: this.translate.instant('notification.mark-all-as-read'),
- icon: 'done_all',
- isEnabled: () => true,
- onAction: $event => this.markAllRead($event)
- }];
+ this.headerActionDescriptors = [
+ {
+ name: 'Notification setting',
+ icon: 'settings',
+ isEnabled: () => true,
+ onAction: $event => this.togleNotificationSettings($event)
+ },
+ {
+ name: this.translate.instant('notification.mark-all-as-read'),
+ icon: 'done_all',
+ isEnabled: () => true,
+ onAction: $event => this.markAllRead($event)
+ }
+ ];
this.columns.push(
new DateEntityTableColumn('createdTime', 'notification.created-time', this.datePipe, '150px'),
@@ -97,6 +107,13 @@ export class InboxTableConfig extends EntityTableConfig {
});
}
+ private togleNotificationSettings($event: Event) {
+ if ($event) {
+ $event.stopPropagation();
+ }
+ this.toggleSettings.emit();
+ }
+
private markAsRead($event, entity){
if ($event) {
$event.stopPropagation();
diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/notification-table/notification-table.component.ts b/ui-ngx/src/app/modules/home/pages/notification-center/notification-table/notification-table.component.ts
index a07b5dbb46..810b27481e 100644
--- a/ui-ngx/src/app/modules/home/pages/notification-center/notification-table/notification-table.component.ts
+++ b/ui-ngx/src/app/modules/home/pages/notification-center/notification-table/notification-table.component.ts
@@ -14,7 +14,7 @@
/// limitations under the License.
///
-import { Component, Input, OnInit, ViewChild } from '@angular/core';
+import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
import { EntitiesTableComponent } from '@home/components/entity/entities-table.component';
import { NotificationService } from '@core/http/notification.service';
import { TargetsTableConfig } from '@home/pages/notification-center/notification-table/targets-table-config';
@@ -36,6 +36,9 @@ export class NotificationTableComponent implements OnInit {
@Input()
notificationType = EntityType.NOTIFICATION;
+ @Output()
+ toggleSettings: EventEmitter = new EventEmitter();
+
@ViewChild(EntitiesTableComponent, {static: true}) entitiesTable: EntitiesTableComponent;
entityTableConfig: EntityTableConfig;
@@ -70,7 +73,8 @@ export class NotificationTableComponent implements OnInit {
return new InboxTableConfig(
this.notificationService,
this.translate,
- this.datePipe
+ this.datePipe,
+ this.toggleSettings
);
case EntityType.NOTIFICATION_TEMPLATE:
return new TemplateTableConfig(
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 31333546c0..ee9efcb0be 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
@@ -173,10 +173,6 @@ export class TemplateAutocompleteComponent implements ControlValueAccessor, OnIn
}
}
- reset() {
- this.selectTemplateFormGroup.get('templateName').patchValue('', {emitEvent: false});
- }
-
updateView(value: EntityId | null) {
if (!isEqual(this.modelValue, value)) {
this.modelValue = value;
@@ -184,8 +180,8 @@ export class TemplateAutocompleteComponent implements ControlValueAccessor, OnIn
}
}
- displayTemplateFn(queue?: NotificationTemplate): string | undefined {
- return queue ? queue.name : undefined;
+ displayTemplateFn(template?: NotificationTemplate): string | undefined {
+ return template ? template.name : undefined;
}
fetchTemplate(searchText?: string): Observable> {
@@ -202,14 +198,6 @@ export class TemplateAutocompleteComponent implements ControlValueAccessor, OnIn
);
}
- getDescription(value) {
- return value.additionalInfo?.description ? value.additionalInfo.description :
- this.translate.instant(
- 'queue.alt-description',
- {submitStrategy: value.submitStrategy.type, processingStrategy: value.processingStrategy.type}
- );
- }
-
clear() {
this.selectTemplateFormGroup.get('templateName').patchValue('', {emitEvent: true});
setTimeout(() => {
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 1325edb0c8..089243d242 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
@@ -162,22 +162,23 @@
{{ 'notification.slack-settings' | translate }}
-
diff --git a/ui-ngx/src/app/modules/home/pages/notification-center/template-table/template-notification-dialog.component.scss b/ui-ngx/src/app/modules/home/pages/notification-center/template-table/template-notification-dialog.component.scss
index 491796c817..4974d6f540 100644
--- a/ui-ngx/src/app/modules/home/pages/notification-center/template-table/template-notification-dialog.component.scss
+++ b/ui-ngx/src/app/modules/home/pages/notification-center/template-table/template-notification-dialog.component.scss
@@ -14,6 +14,7 @@
* limitations under the License.
*/
@import "../../../../../../scss/constants";
+@import "../../../../../../theme";
:host-context(.tb-fullscreen-dialog .mat-dialog-container) {
width: 720px;
@@ -110,6 +111,10 @@
&: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/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 ca20facc34..b451ddd811 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
@@ -20,7 +20,8 @@ import {
NotificationTemplate,
NotificationTemplateTypeTranslateMap,
NotificationType,
- SlackChanelType
+ SlackChanelType,
+ SlackChanelTypesTranslateMap
} from '@shared/models/notification.models';
import { Component, Inject, OnDestroy, ViewChild } from '@angular/core';
import { DialogComponent } from '@shared/components/dialog.component';
@@ -65,9 +66,11 @@ export class TemplateNotificationDialogComponent
saveButtonLabel = 'action.save';
notificationTypes = Object.keys(NotificationType) as NotificationType[];
+ slackChanelTypes = Object.keys(SlackChanelType) as SlackChanelType[];
notificationDeliveryMethods = Object.keys(NotificationDeliveryMethod) as NotificationDeliveryMethod[];
notificationTemplateTypeTranslateMap = NotificationTemplateTypeTranslateMap;
notificationDeliveryMethodTranslateMap = NotificationDeliveryMethodTranslateMap;
+ slackChanelTypesTranslateMap = SlackChanelTypesTranslateMap;
selectedIndex = 0;
diff --git a/ui-ngx/src/app/shared/models/notification-ws.models.ts b/ui-ngx/src/app/shared/models/notification-ws.models.ts
index ef077097d6..29581eddad 100644
--- a/ui-ngx/src/app/shared/models/notification-ws.models.ts
+++ b/ui-ngx/src/app/shared/models/notification-ws.models.ts
@@ -236,13 +236,14 @@ export class NotificationPluginCmdsWrapper {
unsubCmd: UnsubscribeCmd;
markAsReadCmd: MarkAsReadCmd;
markAllAsReadCmd: MarkAllAsReadCmd;
+ #hasSend = false;
public hasCommands(): boolean {
- return isDefinedAndNotNull(this.unreadCountSubCmd) ||
+ return !this.#hasSend && (isDefinedAndNotNull(this.unreadCountSubCmd) ||
isDefinedAndNotNull(this.unreadSubCmd) ||
isDefinedAndNotNull(this.unsubCmd) ||
isDefinedAndNotNull(this.markAsReadCmd) ||
- isDefinedAndNotNull(this.markAllAsReadCmd);
+ isDefinedAndNotNull(this.markAllAsReadCmd));
}
public clear() {
@@ -251,6 +252,7 @@ export class NotificationPluginCmdsWrapper {
this.unsubCmd = null;
this.markAsReadCmd = null;
this.markAllAsReadCmd = null;
+ this.#hasSend = false;
}
public preparePublishCommands(): NotificationPluginCmdsWrapper {
@@ -260,6 +262,7 @@ export class NotificationPluginCmdsWrapper {
preparedWrapper.unsubCmd = this.unsubCmd || undefined;
preparedWrapper.markAsReadCmd = this.markAsReadCmd || undefined;
preparedWrapper.markAllAsReadCmd = this.markAllAsReadCmd || undefined;
+ this.#hasSend = true;
return preparedWrapper;
}
}
diff --git a/ui-ngx/src/app/shared/models/notification.models.ts b/ui-ngx/src/app/shared/models/notification.models.ts
index 83aa994c3c..ab6ae3a6c6 100644
--- a/ui-ngx/src/app/shared/models/notification.models.ts
+++ b/ui-ngx/src/app/shared/models/notification.models.ts
@@ -80,14 +80,18 @@ export interface NotificationRequestConfig {
}
export interface NotificationSettings {
- deliveryMethodsConfigs: Map;
+ deliveryMethodsConfigs: { [key in NotificationDeliveryMethod]: NotificationDeliveryMethodConfig };
}
-export interface NotificationDeliveryMethodConfig {
+export interface NotificationDeliveryMethodConfig extends Partial{
enabled: boolean;
method: NotificationDeliveryMethod;
}
+interface SlackNotificationDeliveryMethodConfig {
+ botToken: string;
+}
+
export interface SlackConversation {
id: string;
name: string;
@@ -226,6 +230,12 @@ export enum SlackChanelType {
PRIVATE_CHANNEL = 'PRIVATE_CHANNEL'
}
+export const SlackChanelTypesTranslateMap = new Map([
+ [SlackChanelType.DIRECT, 'notification.slack-chanel-types.direct'],
+ [SlackChanelType.PUBLIC_CHANNEL, 'notification.slack-chanel-types.public-channel'],
+ [SlackChanelType.PRIVATE_CHANNEL, 'notification.slack-chanel-types.private-channel']
+]);
+
export enum NotificationTargetConfigType {
USER_LIST = 'USER_LIST',
CUSTOMER_USERS = 'CUSTOMER_USERS',
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 d3c415f278..bbc70552c6 100644
--- a/ui-ngx/src/assets/locale/locale.constant-en_US.json
+++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json
@@ -2680,6 +2680,8 @@
"button-text": "Button text",
"button-text-required": "Button text is required",
"compose": "Compose",
+ "conversation": "Conversation",
+ "conversation-required": "Conversation is required",
"copy-notification-template": "Copy notification template",
"create-target": "Create recipient",
"created-time": "Created time",
@@ -2716,6 +2718,7 @@
"no-notification-templates": "No notification templates",
"no-notifications-yet": "No notifications yet",
"no-targets-notification": "No recipients notification",
+ "not-found-slack-recipient": "Not found slack recipient",
"notification": "Notification",
"notification-center": "Notification center",
"notification-target": "Notification recipient",
@@ -2734,6 +2737,12 @@
"send-test-notification": "Send test notification",
"sent": "Sent",
"settings": "Notification settings",
+ "slack-chanel-type": "Slack chanel type",
+ "slack-chanel-types": {
+ "direct": "Direct message",
+ "private-channel": "Private Channel",
+ "public-channel": "Public Channel"
+ },
"slack-settings": "Slack settings",
"sms-settings": "SMS settings",
"status": "Status",