Browse Source

UI: Add support in web notification action open dashboard

pull/7911/head
Vladyslav_Prykhodko 3 years ago
parent
commit
902cd73000
  1. 1
      ui-ngx/src/app/modules/home/pages/notification-center/notification-center.module.ts
  2. 56
      ui-ngx/src/app/modules/home/pages/notification-center/request-table/request-notification-dialog.component.html
  3. 11
      ui-ngx/src/app/modules/home/pages/notification-center/rule-table/escalations.component.ts
  4. 1
      ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.html
  5. 1
      ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.scss
  6. 3
      ui-ngx/src/app/modules/home/pages/notification-center/template-table/template-autocomplete.component.html
  7. 20
      ui-ngx/src/app/modules/home/pages/notification-center/template-table/template-autocomplete.component.ts
  8. 31
      ui-ngx/src/app/modules/home/pages/notification-center/template-table/template-configuration.ts
  9. 48
      ui-ngx/src/app/modules/home/pages/notification-center/template-table/template-notification-dialog.component.html
  10. 38
      ui-ngx/src/app/shared/components/dashboard-state-autocomplete.component.html
  11. 24
      ui-ngx/src/app/shared/components/dashboard-state-autocomplete.component.ts
  12. 25
      ui-ngx/src/app/shared/components/notification/notification.component.ts
  13. 1
      ui-ngx/src/app/shared/components/string-items-list.component.html
  14. 13
      ui-ngx/src/app/shared/components/string-items-list.component.ts
  15. 35
      ui-ngx/src/app/shared/decorators/coerce-boolean.ts
  16. 15
      ui-ngx/src/app/shared/models/notification.models.ts
  17. 5
      ui-ngx/src/assets/locale/locale.constant-en_US.json

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

@ -51,7 +51,6 @@ import { EscalationFormComponent } from '@home/pages/notification-center/rule-ta
import {
AlarmSeveritiesListComponent
} from '@home/pages/notification-center/rule-table/alarm-severities-list.component';
import { TemplateConfiguration } from '@home/pages/notification-center/template-table/template-configuration';
@NgModule({
declarations: [

56
ui-ngx/src/app/modules/home/pages/notification-center/request-table/request-notification-dialog.component.html

@ -112,15 +112,15 @@
<mat-form-field>
<mat-label translate>notification.time</mat-label>
<mat-datetimepicker-toggle [for]="startTimePicker" matPrefix></mat-datetimepicker-toggle>
<mat-datetimepicker #startTimePicker type="datetime" openOnFocus="true"></mat-datetimepicker>
<mat-datetimepicker #startTimePicker type="datetime" openOnFocus="true" timeInterval="1"></mat-datetimepicker>
<input required matInput fxFlex formControlName="time" [min]="minDate()" [max]="maxDate()" [matDatetimepicker]="startTimePicker">
</mat-form-field>
</div>
</section>
</form>
</mat-step>
<mat-step optional *ngIf="!notificationRequestForm.get('useTemplate').value &&
notificationRequestForm.get('template.configuration.deliveryMethodsTemplates.PUSH.enabled').value"
<mat-step *ngIf="!notificationRequestForm.get('useTemplate').value &&
notificationRequestForm.get('template.configuration.deliveryMethodsTemplates.PUSH.enabled').value"
[stepControl]="pushTemplateForm">
<ng-template matStepLabel>{{ 'notification.web-settings' | translate }}</ng-template>
<div class="tb-hint tb-hint-available-params">
@ -158,7 +158,7 @@
{{ 'notification.action-button' | translate }}
</mat-slide-toggle>
<div *ngIf="pushTemplateForm.get('additionalConfig.actionButtonConfig.enabled').value">
<div fxLayout="row" fxLayoutGap="12px">
<div fxLayout="row" fxLayoutGap="8px">
<mat-form-field class="mat-block" fxFlex>
<mat-label translate>notification.button-text</mat-label>
<input matInput formControlName="text" required>
@ -169,20 +169,42 @@
<tb-color-input formControlName="color" fxFlex>
</tb-color-input>
</div>
<mat-form-field class="mat-block">
<mat-label translate>notification.link</mat-label>
<input matInput formControlName="link" required>
<mat-error *ngIf="pushTemplateForm.get('additionalConfig.actionButtonConfig.link').hasError('required')">
{{ 'notification.link-required' | translate }}
</mat-error>
</mat-form-field>
<div fxLayout="row" fxLayoutGap="8px">
<mat-form-field fxFlex="30">
<mat-label translate>notification.action-type</mat-label>
<mat-select formControlName="linkType">
<mat-option *ngFor="let actionButtonLinkType of actionButtonLinkTypes" [value]="actionButtonLinkType">
{{ actionButtonLinkTypeTranslateMap.get(actionButtonLinkType) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field fxFlex
*ngIf="pushTemplateForm.get('additionalConfig.actionButtonConfig.linkType').value === actionButtonLinkType.LINK; else dashboardSelector">
<mat-label translate>notification.link</mat-label>
<input matInput formControlName="link" required>
<mat-error *ngIf="pushTemplateForm.get('additionalConfig.actionButtonConfig.link').hasError('required')">
{{ 'notification.link-required' | translate }}
</mat-error>
</mat-form-field>
<ng-template #dashboardSelector>
<tb-dashboard-autocomplete
fxFlex="35"
required
formControlName="dashboardId">
</tb-dashboard-autocomplete>
<tb-dashboard-state-autocomplete fxFlex="35"
[dashboardId]="pushTemplateForm.get('additionalConfig.actionButtonConfig.dashboardId').value"
formControlName="dashboardState">
</tb-dashboard-state-autocomplete>
</ng-template>
</div>
</div>
</section>
</section>
</form>
</mat-step>
<mat-step optional *ngIf="!notificationRequestForm.get('useTemplate').value &&
notificationRequestForm.get('template.configuration.deliveryMethodsTemplates.EMAIL.enabled').value"
<mat-step *ngIf="!notificationRequestForm.get('useTemplate').value &&
notificationRequestForm.get('template.configuration.deliveryMethodsTemplates.EMAIL.enabled').value"
[stepControl]="emailTemplateForm">
<ng-template matStepLabel>{{ 'notification.email-settings' | translate }}</ng-template>
<ng-template matStepContent>
@ -199,8 +221,8 @@
</form>
</ng-template>
</mat-step>
<mat-step optional *ngIf="!notificationRequestForm.get('useTemplate').value &&
notificationRequestForm.get('template.configuration.deliveryMethodsTemplates.SMS.enabled').value"
<mat-step *ngIf="!notificationRequestForm.get('useTemplate').value &&
notificationRequestForm.get('template.configuration.deliveryMethodsTemplates.SMS.enabled').value"
[stepControl]="smsTemplateForm">
<ng-template matStepLabel>{{ 'notification.sms-settings' | translate }}</ng-template>
<div class="tb-hint tb-hint-available-params">
@ -219,8 +241,8 @@
</mat-form-field>
</form>
</mat-step>
<mat-step optional *ngIf="!notificationRequestForm.get('useTemplate').value &&
notificationRequestForm.get('template.configuration.deliveryMethodsTemplates.SLACK.enabled').value"
<mat-step *ngIf="!notificationRequestForm.get('useTemplate').value &&
notificationRequestForm.get('template.configuration.deliveryMethodsTemplates.SLACK.enabled').value"
[stepControl]="slackTemplateForm">
<ng-template matStepLabel>{{ 'notification.slack-settings' | translate }}</ng-template>
<div class="tb-hint tb-hint-available-params">

11
ui-ngx/src/app/modules/home/pages/notification-center/rule-table/escalations.component.ts

@ -29,10 +29,10 @@ import {
} from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@app/core/core.state';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { Subject } from 'rxjs';
import { NonConfirmedNotificationEscalation } from '@shared/models/notification.models';
import { takeUntil } from 'rxjs/operators';
import { coerceBoolean } from '@shared/decorators/coerce-boolean';
@Component({
selector: 'tb-escalations-component',
@ -56,14 +56,9 @@ export class EscalationsComponent implements ControlValueAccessor, Validator, On
escalationsFormGroup: FormGroup;
newEscalation = false;
private requiredValue: boolean;
get required(): boolean {
return this.requiredValue;
}
@Input()
set required(value: boolean) {
this.requiredValue = coerceBooleanProperty(value);
}
@coerceBoolean()
required: boolean;
@Input()
disabled: boolean;

1
ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.html

@ -90,6 +90,7 @@
<fieldset class="fields-group tb-margin">
<legend translate>notification.filter</legend>
<tb-string-items-list
editable
label="{{ 'alarm.alarm-type-list' | translate }}"
placeholder="{{ !alarmTemplateForm.get('triggerConfig.alarmTypes').value?.length ? ('alarm.any-type' | translate) : '' }}"
floatLabel="always"

1
ui-ngx/src/app/modules/home/pages/notification-center/rule-table/rule-notification-dialog.component.scss

@ -14,6 +14,7 @@
* limitations under the License.
*/
@import "../../../../../../theme";
@import "../../../../../../scss/constants";
:host {
width: 700px;

3
ui-ngx/src/app/modules/home/pages/notification-center/template-table/template-autocomplete.component.html

@ -16,7 +16,8 @@
-->
<mat-form-field [formGroup]="selectTemplateFormGroup" class="mat-block">
<input matInput type="text" placeholder="{{ 'notification.template' | translate }}"
<mat-label translate>notification.template</mat-label>
<input matInput type="text"
#templateInput
formControlName="templateName"
(focusin)="onFocus()"

20
ui-ngx/src/app/modules/home/pages/notification-center/template-table/template-autocomplete.component.ts

@ -21,7 +21,6 @@ import { catchError, debounceTime, distinctUntilChanged, map, share, switchMap,
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { TranslateService } from '@ngx-translate/core';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { EntityId } from '@shared/models/id/entity-id';
import { EntityService } from '@core/http/entity.service';
import { TruncatePipe } from '@shared/pipe/truncate.pipe';
@ -41,6 +40,7 @@ import {
} from '@home/pages/notification-center/template-table/template-notification-dialog.component';
import { MatDialog } from '@angular/material/dialog';
import { MatButton } from '@angular/material/button';
import { coerceBoolean } from '@shared/decorators/coerce-boolean';
@Component({
selector: 'tb-template-autocomplete',
@ -57,23 +57,13 @@ export class TemplateAutocompleteComponent implements ControlValueAccessor, OnIn
notificationDeliveryMethodTranslateMap = NotificationDeliveryMethodTranslateMap;
selectTemplateFormGroup: FormGroup;
private requiredValue: boolean;
get required(): boolean {
return this.requiredValue;
}
@Input()
set required(value: boolean) {
this.requiredValue = coerceBooleanProperty(value);
}
@coerceBoolean()
required: boolean;
private allowCreateValue = false;
get allowCreate(): boolean {
return this.allowCreateValue;
}
@Input()
set allowCreate(value: boolean) {
this.allowCreateValue = coerceBooleanProperty(value);
}
@coerceBoolean()
allowCreate: boolean = false;
@Input()

31
ui-ngx/src/app/modules/home/pages/notification-center/template-table/template-configuration.ts

@ -16,6 +16,8 @@
import { FormBuilder, FormGroup, ValidationErrors, Validators } from '@angular/forms';
import {
ActionButtonLinkType,
ActionButtonLinkTypeTranslateMap,
NotificationDeliveryMethod,
NotificationDeliveryMethodTranslateMap,
NotificationTemplate,
@ -46,6 +48,10 @@ export abstract class TemplateConfiguration<T, R = any> extends DialogComponent<
notificationDeliveryMethodTranslateMap = NotificationDeliveryMethodTranslateMap;
notificationTemplateTypeTranslateMap = NotificationTemplateTypeTranslateMap;
actionButtonLinkType = ActionButtonLinkType;
actionButtonLinkTypes = Object.keys(ActionButtonLinkType) as ActionButtonLinkType[];
actionButtonLinkTypeTranslateMap = ActionButtonLinkTypeTranslateMap;
tinyMceOptions: Record<string, any> = {
base_url: '/assets/tinymce',
suffix: '.min',
@ -97,7 +103,10 @@ export abstract class TemplateConfiguration<T, R = any> extends DialogComponent<
enabled: [false],
text: [{value: '', disabled: true}, Validators.required],
color: ['#305680'],
link: [{value: '', disabled: true}, Validators.required]
linkType: [ActionButtonLinkType.LINK],
link: [{value: '', disabled: true}, Validators.required],
dashboardId: [{value: null, disabled: true}, Validators.required],
dashboardState: [{value: null, disabled: true}]
}),
})
});
@ -116,11 +125,25 @@ export abstract class TemplateConfiguration<T, R = any> extends DialogComponent<
takeUntil(this.destroy$)
).subscribe((value) => {
if (value) {
this.pushTemplateForm.get('additionalConfig.actionButtonConfig.text').enable({emitEvent: false});
this.pushTemplateForm.get('additionalConfig.actionButtonConfig').enable({emitEvent: false});
this.pushTemplateForm.get('additionalConfig.actionButtonConfig.linkType').updateValueAndValidity({onlySelf: true});
} else {
this.pushTemplateForm.get('additionalConfig.actionButtonConfig').disable({emitEvent: false});
this.pushTemplateForm.get('additionalConfig.actionButtonConfig.enabled').enable({emitEvent: false});
}
});
this.pushTemplateForm.get('additionalConfig.actionButtonConfig.linkType').valueChanges.pipe(
takeUntil(this.destroy$)
).subscribe((value) => {
if (value === ActionButtonLinkType.LINK) {
this.pushTemplateForm.get('additionalConfig.actionButtonConfig.link').enable({emitEvent: false});
this.pushTemplateForm.get('additionalConfig.actionButtonConfig.dashboardId').disable({emitEvent: false});
this.pushTemplateForm.get('additionalConfig.actionButtonConfig.dashboardState').disable({emitEvent: false});
} else {
this.pushTemplateForm.get('additionalConfig.actionButtonConfig.text').disable({emitEvent: false});
this.pushTemplateForm.get('additionalConfig.actionButtonConfig.link').disable({emitEvent: false});
this.pushTemplateForm.get('additionalConfig.actionButtonConfig.dashboardId').enable({emitEvent: false});
this.pushTemplateForm.get('additionalConfig.actionButtonConfig.dashboardState').enable({emitEvent: false});
}
});
@ -150,7 +173,7 @@ export abstract class TemplateConfiguration<T, R = any> extends DialogComponent<
this.destroy$.complete();
}
private atLeastOne() {
atLeastOne() {
return (group: FormGroup): ValidationErrors | null => {
let hasAtLeastOne = true;
if (group?.controls) {

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

@ -28,7 +28,7 @@
</mat-progress-bar>
<div style="height: 4px;" *ngIf="!(isLoading$ | async)"></div>
<div mat-dialog-content>
<mat-horizontal-stepper [linear]="true" labelPosition="end" #notificationTemplateStepper [orientation]="(stepperOrientation | async)"
<mat-horizontal-stepper linear labelPosition="end" #notificationTemplateStepper [orientation]="(stepperOrientation | async)"
(selectionChange)="changeStep($event)">
<ng-template matStepperIcon="edit">
<mat-icon>check</mat-icon>
@ -84,7 +84,7 @@
</section>
</form>
</mat-step>
<mat-step optional *ngIf="templateNotificationForm.get('configuration.deliveryMethodsTemplates.PUSH.enabled').value"
<mat-step *ngIf="templateNotificationForm.get('configuration.deliveryMethodsTemplates.PUSH.enabled').value"
[stepControl]="pushTemplateForm">
<ng-template matStepLabel>{{ 'notification.web-settings' | translate }}</ng-template>
<div class="tb-hint tb-hint-available-params">
@ -122,7 +122,7 @@
{{ 'notification.action-button' | translate }}
</mat-slide-toggle>
<div *ngIf="pushTemplateForm.get('additionalConfig.actionButtonConfig.enabled').value">
<div fxLayout="row" fxLayoutGap="12px">
<div fxLayout="row" fxLayoutGap="8px">
<mat-form-field class="mat-block" fxFlex>
<mat-label translate>notification.button-text</mat-label>
<input matInput formControlName="text" required>
@ -133,19 +133,41 @@
<tb-color-input formControlName="color" fxFlex>
</tb-color-input>
</div>
<mat-form-field class="mat-block">
<mat-label translate>notification.link</mat-label>
<input matInput formControlName="link" required>
<mat-error *ngIf="pushTemplateForm.get('additionalConfig.actionButtonConfig.link').hasError('required')">
{{ 'notification.link-required' | translate }}
</mat-error>
</mat-form-field>
<div fxLayout="row" fxLayoutGap="8px">
<mat-form-field fxFlex="30">
<mat-label translate>notification.action-type</mat-label>
<mat-select formControlName="linkType">
<mat-option *ngFor="let actionButtonLinkType of actionButtonLinkTypes" [value]="actionButtonLinkType">
{{ actionButtonLinkTypeTranslateMap.get(actionButtonLinkType) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field fxFlex
*ngIf="pushTemplateForm.get('additionalConfig.actionButtonConfig.linkType').value === actionButtonLinkType.LINK; else dashboardSelector">
<mat-label translate>notification.link</mat-label>
<input matInput formControlName="link" required>
<mat-error *ngIf="pushTemplateForm.get('additionalConfig.actionButtonConfig.link').hasError('required')">
{{ 'notification.link-required' | translate }}
</mat-error>
</mat-form-field>
<ng-template #dashboardSelector>
<tb-dashboard-autocomplete
fxFlex="35"
required
formControlName="dashboardId">
</tb-dashboard-autocomplete>
<tb-dashboard-state-autocomplete fxFlex="35"
[dashboardId]="pushTemplateForm.get('additionalConfig.actionButtonConfig.dashboardId').value"
formControlName="dashboardState">
</tb-dashboard-state-autocomplete>
</ng-template>
</div>
</div>
</section>
</section>
</form>
</mat-step>
<mat-step optional *ngIf="templateNotificationForm.get('configuration.deliveryMethodsTemplates.EMAIL.enabled').value"
<mat-step *ngIf="templateNotificationForm.get('configuration.deliveryMethodsTemplates.EMAIL.enabled').value"
[stepControl]="emailTemplateForm">
<ng-template matStepLabel>{{ 'notification.email-settings' | translate }}</ng-template>
<ng-template matStepContent>
@ -162,7 +184,7 @@
</form>
</ng-template>
</mat-step>
<mat-step optional *ngIf="templateNotificationForm.get('configuration.deliveryMethodsTemplates.SMS.enabled').value"
<mat-step *ngIf="templateNotificationForm.get('configuration.deliveryMethodsTemplates.SMS.enabled').value"
[stepControl]="smsTemplateForm">
<ng-template matStepLabel>{{ 'notification.sms-settings' | translate }}</ng-template>
<div class="tb-hint tb-hint-available-params">
@ -181,7 +203,7 @@
</mat-form-field>
</form>
</mat-step>
<mat-step optional *ngIf="templateNotificationForm.get('configuration.deliveryMethodsTemplates.SLACK.enabled').value"
<mat-step *ngIf="templateNotificationForm.get('configuration.deliveryMethodsTemplates.SLACK.enabled').value"
[stepControl]="slackTemplateForm">
<ng-template matStepLabel>{{ 'notification.slack-settings' | translate }}</ng-template>
<div class="tb-hint tb-hint-available-params">

38
ui-ngx/src/app/shared/components/dashboard-state-autocomplete.component.html

@ -15,11 +15,13 @@
limitations under the License.
-->
<mat-form-field [formGroup]="selectDashboardStateFormGroup" class="mat-block" [floatLabel]="floatLabel">
<input matInput type="text" placeholder="{{ placeholder || ('widget-action.target-dashboard-state' | translate) }}"
<mat-form-field [formGroup]="selectDashboardStateFormGroup" class="mat-block">
<mat-label>{{ label }}</mat-label>
<input matInput type="text" placeholder="{{ placeholder }}"
#dashboardStateInput
formControlName="dashboardStateId"
[required]="required"
(focus)="onFocus()"
[matAutocomplete]="dashboardStateAutocomplete">
<button *ngIf="selectDashboardStateFormGroup.get('dashboardStateId').value"
type="button"
@ -38,35 +40,3 @@
{{ 'widget-action.target-dashboard-state-required' | translate }}
</mat-error>
</mat-form-field>
<!-- <input matInput type="text" placeholder="{{ placeholder || ('dashboard.dashboard' | translate) }}"-->
<!-- #dashboardInput-->
<!-- formControlName="dashboard"-->
<!-- (focusin)="onFocus()"-->
<!-- [required]="required"-->
<!-- [matAutocomplete]="dashboardAutocomplete">-->
<!-- <button *ngIf="selectDashboardStateFormGroup.get('dashboard').value && !disabled"-->
<!-- type="button"-->
<!-- matSuffix mat-button mat-icon-button aria-label="Clear"-->
<!-- (click)="clear()">-->
<!-- <mat-icon class="material-icons">close</mat-icon>-->
<!-- </button>-->
<!-- <mat-autocomplete-->
<!-- class="tb-autocomplete"-->
<!-- #dashboardAutocomplete="matAutocomplete"-->
<!-- [displayWith]="displayDashboardFn">-->
<!-- <mat-option *ngFor="let dashboard of filteredDashboards | async" [value]="dashboard">-->
<!-- <span [innerHTML]="dashboard.title | highlight:searchText"></span>-->
<!-- </mat-option>-->
<!-- <mat-option *ngIf="!(filteredDashboards | async)?.length" [value]="null">-->
<!-- <span>-->
<!-- {{ translate.get('dashboard.no-dashboards-matching', {entity: searchText}) | async }}-->
<!-- </span>-->
<!-- </mat-option>-->
<!-- </mat-autocomplete>-->
<!-- <mat-error>-->
<!-- <ng-content select="[tb-error]"></ng-content>-->
<!-- </mat-error>-->
<!-- <mat-hint>-->
<!-- <ng-content select="[tb-hint]"></ng-content>-->
<!-- </mat-hint>-->
<!--</mat-form-field>-->

24
ui-ngx/src/app/shared/components/dashboard-state-autocomplete.component.ts

@ -47,12 +47,11 @@ export class DashboardStateAutocompleteComponent implements ControlValueAccessor
private propagateChange = (v: any) => { };
@Input()
placeholder: string;
label: string = this.translate.instant('widget-action.target-dashboard-state');
@Input()
floatLabel: FloatLabelType = 'auto';
placeholder: string;
private requiredValue: boolean;
get required(): boolean {
@ -66,17 +65,20 @@ export class DashboardStateAutocompleteComponent implements ControlValueAccessor
@Input()
disabled: boolean;
private dashboardIdValue: string;
private dashboardIdValue: string = null;
get dashboardId(): string {
return this.dashboardIdValue;
}
@Input()
set dashboardId(value: string) {
this.dashboardIdValue = value;
this.clearDashboardStateCache();
this.searchText = '';
this.selectDashboardStateFormGroup.get('dashboardStateId').patchValue('', {emitEvent: false});
this.dirty = true;
if (this.dashboardIdValue !== value) {
this.dashboardIdValue = value;
this.clearDashboardStateCache();
this.searchText = '';
this.selectDashboardStateFormGroup.get('dashboardStateId').patchValue('', {emitEvent: false});
this.dirty = true;
}
}
@ViewChild('dashboardStateInput', {static: true}) dashboardStateInput: ElementRef;
@ -113,7 +115,7 @@ export class DashboardStateAutocompleteComponent implements ControlValueAccessor
debounceTime(150),
tap(value => {
let modelValue;
if (!value || !this.latestDashboardStates.includes(value)) {
if (!value || !this.latestDashboardStates?.includes(value)) {
modelValue = null;
} else {
modelValue = value;
@ -160,7 +162,7 @@ export class DashboardStateAutocompleteComponent implements ControlValueAccessor
onFocus() {
if (this.dirty) {
this.selectDashboardStateFormGroup.get('dashboard').updateValueAndValidity({onlySelf: true});
this.selectDashboardStateFormGroup.get('dashboardStateId').updateValueAndValidity({onlySelf: true});
this.dirty = false;
}
}

25
ui-ngx/src/app/shared/components/notification/notification.component.ts

@ -16,6 +16,7 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import {
ActionButtonLinkType,
AlarmSeverityNotificationColors,
Notification,
NotificationType,
@ -26,6 +27,8 @@ import { Router } from '@angular/router';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { alarmSeverityTranslations } from '@shared/models/alarm.models';
import * as tinycolor_ from 'tinycolor2';
import { StateObject } from '@core/api/widget-api.models';
import { objToBase64URI } from '@core/utils';
@Component({
selector: 'tb-notification',
@ -91,11 +94,27 @@ export class NotificationComponent implements OnInit {
$event.stopPropagation();
}
if (!this.preview) {
if (this.notification.additionalConfig.actionButtonConfig.link.startsWith('/')) {
this.router.navigateByUrl(this.router.parseUrl(this.notification.additionalConfig.actionButtonConfig.link)).then(() => {
let link: string;
if (this.notification.additionalConfig.actionButtonConfig.linkType === ActionButtonLinkType.DASHBOARD) {
let state = null;
if (this.notification.additionalConfig.actionButtonConfig.dashboardState) {
const stateObject: StateObject = {};
stateObject.params = {};
stateObject.id = this.notification.additionalConfig.actionButtonConfig.dashboardState;
state = objToBase64URI([ stateObject ]);
}
link = `/dashboards/${this.notification.additionalConfig.actionButtonConfig.dashboardId}`
if (state) {
link += `?state=${state}`;
}
} else {
link = this.notification.additionalConfig.actionButtonConfig.link;
}
if (link.startsWith('/')) {
this.router.navigateByUrl(this.router.parseUrl(link)).then(() => {
});
} else {
window.open(this.notification.additionalConfig.actionButtonConfig.link, '_blank');
window.open(link, '_blank');
}
if (this.onClose) {
this.onClose();

1
ui-ngx/src/app/shared/components/string-items-list.component.html

@ -22,6 +22,7 @@
<mat-chip *ngFor="let item of stringItemsList"
[selectable]="!disabled"
[removable]="!disabled"
[contentEditable]="editable && !disabled"
(removed)="removeItems(item)">
{{item}}
<mat-icon matChipRemove *ngIf="!disabled">close</mat-icon>

13
ui-ngx/src/app/shared/components/string-items-list.component.ts

@ -16,10 +16,10 @@
import { Component, forwardRef, Input } from '@angular/core';
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { MatChipInputEvent } from '@angular/material/chips';
import { COMMA, ENTER, SEMICOLON } from '@angular/cdk/keycodes';
import { FloatLabelType, MatFormFieldAppearance } from '@angular/material/form-field';
import { coerceBoolean } from '@shared/decorators/coerce-boolean';
@Component({
selector: 'tb-string-items-list',
@ -45,15 +45,16 @@ export class StringItemsListComponent implements ControlValueAccessor{
return this.requiredValue;
}
@Input()
@coerceBoolean()
set required(value: boolean) {
const newVal = coerceBooleanProperty(value);
if (this.requiredValue !== newVal) {
this.requiredValue = newVal;
if (this.requiredValue !== value) {
this.requiredValue = value;
this.updateValidators();
}
}
@Input()
@coerceBoolean()
disabled: boolean;
@Input()
@ -74,6 +75,10 @@ export class StringItemsListComponent implements ControlValueAccessor{
@Input()
appearance: MatFormFieldAppearance = 'standard';
@Input()
@coerceBoolean()
editable: boolean = false
private propagateChange = (v: any) => { };
constructor(private fb: FormBuilder) {

35
ui-ngx/src/app/shared/decorators/coerce-boolean.ts

@ -0,0 +1,35 @@
///
/// Copyright © 2016-2023 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 { coerceBooleanProperty } from '@angular/cdk/coercion';
export function coerceBoolean() {
return function (target: any, key: string): void {
const getter = function () {
return this['__' + key];
};
const setter = function (next: any) {
this['__' + key] = coerceBooleanProperty(next);
};
Object.defineProperty(target, key, {
get: getter,
set: setter,
enumerable: true,
configurable: true,
});
};
}

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

@ -206,7 +206,10 @@ interface PushDeliveryMethodAdditionalConfig {
enabled: boolean;
text: string;
color: string;
link: string;
linkType: ActionButtonLinkType,
link?: string;
dashboardId?: string;
dashboardState?: string;
};
}
@ -301,6 +304,16 @@ export const AlarmSeverityNotificationColors = new Map<AlarmSeverity, string>(
]
);
export enum ActionButtonLinkType {
LINK = 'LINK',
DASHBOARD = 'DASHBOARD'
}
export const ActionButtonLinkTypeTranslateMap = new Map<ActionButtonLinkType, string>([
[ActionButtonLinkType.LINK, 'notification.link-type.link'],
[ActionButtonLinkType.DASHBOARD, 'notification.link-type.dashboard']
]);
interface NotificationTemplateTypeTranslate {
name: string;
hint?: string;

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

@ -2690,6 +2690,7 @@
},
"notification": {
"action-button": "Action button",
"action-type": "Action type",
"add-notification-target": "Add notification recipient",
"add-notification-template": "Add notification template",
"add-rule": "Add rule",
@ -2756,6 +2757,10 @@
"inbox": "Inbox",
"link": "Link",
"link-required": "Link is required",
"link-type": {
"link": "Open URL link",
"dashboard": "Open dashboard"
},
"management": "Notification management",
"mark-all-as-read": "Mark all as read",
"mark-as-read": "Mark as read",

Loading…
Cancel
Save