UI: Change notification request support send without template
This commit is contained in:
parent
7e4d92e8eb
commit
6945b96e3c
@ -1,3 +1,19 @@
|
|||||||
|
///
|
||||||
|
/// 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 { CmdWrapper, WsService, WsSubscriber } from '@shared/models/websocket/websocket.models';
|
import { CmdWrapper, WsService, WsSubscriber } from '@shared/models/websocket/websocket.models';
|
||||||
import { select, Store } from '@ngrx/store';
|
import { select, Store } from '@ngrx/store';
|
||||||
import { AppState } from '@core/core.state';
|
import { AppState } from '@core/core.state';
|
||||||
|
|||||||
@ -16,8 +16,8 @@
|
|||||||
|
|
||||||
import { Component, ElementRef, forwardRef, Input, OnChanges, OnInit, SimpleChanges, ViewChild } from '@angular/core';
|
import { Component, ElementRef, forwardRef, Input, OnChanges, OnInit, SimpleChanges, ViewChild } from '@angular/core';
|
||||||
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
|
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
|
||||||
import { Observable, of } from 'rxjs';
|
import { Observable, of, ReplaySubject } from 'rxjs';
|
||||||
import { debounceTime, map, publishReplay, refCount, share, switchMap, tap } from 'rxjs/operators';
|
import { debounceTime, map, share, switchMap, tap } from 'rxjs/operators';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { AppState } from '@core/core.state';
|
import { AppState } from '@core/core.state';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
@ -201,8 +201,12 @@ export class SlackConversationAutocompleteComponent implements ControlValueAcces
|
|||||||
fetchObservable = of([]);
|
fetchObservable = of([]);
|
||||||
}
|
}
|
||||||
this.slackConversetionFetchObservable$ = fetchObservable.pipe(
|
this.slackConversetionFetchObservable$ = fetchObservable.pipe(
|
||||||
publishReplay(1),
|
share({
|
||||||
refCount()
|
connector: () => new ReplaySubject(1),
|
||||||
|
resetOnError: false,
|
||||||
|
resetOnComplete: false,
|
||||||
|
resetOnRefCountZero: false
|
||||||
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return this.slackConversetionFetchObservable$;
|
return this.slackConversetionFetchObservable$;
|
||||||
|
|||||||
@ -36,7 +36,7 @@
|
|||||||
</ng-template>
|
</ng-template>
|
||||||
<mat-step [stepControl]="notificationRequestForm">
|
<mat-step [stepControl]="notificationRequestForm">
|
||||||
<ng-template matStepLabel>{{ 'notification.compose' | translate }}</ng-template>
|
<ng-template matStepLabel>{{ 'notification.compose' | translate }}</ng-template>
|
||||||
<form [formGroup]="notificationRequestForm" style="padding-bottom: 16px;">
|
<form [formGroup]="notificationRequestForm">
|
||||||
<div fxLayout="row" fxLayoutAlign="center">
|
<div fxLayout="row" fxLayoutAlign="center">
|
||||||
<mat-button-toggle-group class="tb-notification-use-template-toggle-group"
|
<mat-button-toggle-group class="tb-notification-use-template-toggle-group"
|
||||||
style="width: 320px;"
|
style="width: 320px;"
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
@import "../../../../../../theme";
|
@import "../../../../../../theme";
|
||||||
|
|
||||||
:host-context(.tb-fullscreen-dialog .mat-dialog-container) {
|
:host-context(.tb-fullscreen-dialog .mat-dialog-container) {
|
||||||
width: 640px;
|
width: 800px;
|
||||||
max-height: 100vh;
|
max-height: 100vh;
|
||||||
|
|
||||||
.tb-form-fields {
|
.tb-form-fields {
|
||||||
@ -169,7 +169,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.mat-horizontal-content-container {
|
.mat-horizontal-content-container {
|
||||||
height: 540px;
|
height: 600px;
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
width: 100%;;
|
width: 100%;;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
@ -241,7 +241,7 @@
|
|||||||
|
|
||||||
.mat-form-field {
|
.mat-form-field {
|
||||||
.mat-form-field-wrapper {
|
.mat-form-field-wrapper {
|
||||||
padding-bottom: 0px;
|
padding-bottom: 0;
|
||||||
|
|
||||||
.mat-form-field-underline {
|
.mat-form-field-underline {
|
||||||
position: initial !important;
|
position: initial !important;
|
||||||
|
|||||||
@ -29,7 +29,7 @@ import { Router } from '@angular/router';
|
|||||||
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog';
|
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog';
|
||||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||||
import { NotificationService } from '@core/http/notification.service';
|
import { NotificationService } from '@core/http/notification.service';
|
||||||
import { deepTrim } from '@core/utils';
|
import { deepTrim, guid } from '@core/utils';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { EntityType } from '@shared/models/entity-type.models';
|
import { EntityType } from '@shared/models/entity-type.models';
|
||||||
import { BreakpointObserver } from '@angular/cdk/layout';
|
import { BreakpointObserver } from '@angular/cdk/layout';
|
||||||
@ -88,8 +88,8 @@ export class RequestNotificationDialogComponent extends
|
|||||||
.pipe(map(({matches}) => matches ? 'horizontal' : 'vertical'));
|
.pipe(map(({matches}) => matches ? 'horizontal' : 'vertical'));
|
||||||
|
|
||||||
this.notificationRequestForm = this.fb.group({
|
this.notificationRequestForm = this.fb.group({
|
||||||
useTemplate: [true],
|
useTemplate: [false],
|
||||||
templateId: [null, Validators.required],
|
templateId: [{value: null, disabled: true}, Validators.required],
|
||||||
targets: [null, Validators.required],
|
targets: [null, Validators.required],
|
||||||
template: this.templateNotificationForm,
|
template: this.templateNotificationForm,
|
||||||
additionalConfig: this.fb.group({
|
additionalConfig: this.fb.group({
|
||||||
@ -99,9 +99,7 @@ export class RequestNotificationDialogComponent extends
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
this.notificationRequestForm.get('template').disable({emitEvent: false});
|
this.notificationRequestForm.get('template.name').setValue(guid())
|
||||||
this.notificationRequestForm.get('template.name').removeValidators(Validators.required);
|
|
||||||
this.notificationRequestForm.get('template.name').updateValueAndValidity({emitEvent: false});
|
|
||||||
|
|
||||||
this.notificationRequestForm.get('useTemplate').valueChanges.pipe(
|
this.notificationRequestForm.get('useTemplate').valueChanges.pipe(
|
||||||
takeUntil(this.destroy$)
|
takeUntil(this.destroy$)
|
||||||
@ -203,8 +201,10 @@ export class RequestNotificationDialogComponent extends
|
|||||||
|
|
||||||
private get notificationFormValue(): NotificationRequest {
|
private get notificationFormValue(): NotificationRequest {
|
||||||
const formValue = deepTrim(this.notificationRequestForm.value);
|
const formValue = deepTrim(this.notificationRequestForm.value);
|
||||||
|
if (!formValue.useTemplate) {
|
||||||
|
formValue.template = super.getNotificationTemplateValue();
|
||||||
|
}
|
||||||
delete formValue.useTemplate;
|
delete formValue.useTemplate;
|
||||||
delete formValue.template;
|
|
||||||
let delay = 0;
|
let delay = 0;
|
||||||
if (formValue.additionalConfig.enabled) {
|
if (formValue.additionalConfig.enabled) {
|
||||||
delay = (this.notificationRequestForm.value.additionalConfig.time.valueOf() - this.minDate().valueOf()) / 1000;
|
delay = (this.notificationRequestForm.value.additionalConfig.time.valueOf() - this.minDate().valueOf()) / 1000;
|
||||||
|
|||||||
@ -30,6 +30,7 @@ import { Store } from '@ngrx/store';
|
|||||||
import { AppState } from '@core/core.state';
|
import { AppState } from '@core/core.state';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { MatDialogRef } from '@angular/material/dialog';
|
import { MatDialogRef } from '@angular/material/dialog';
|
||||||
|
import { deepClone, deepTrim } from '@core/utils';
|
||||||
|
|
||||||
@Directive()
|
@Directive()
|
||||||
// tslint:disable-next-line:directive-class-suffix
|
// tslint:disable-next-line:directive-class-suffix
|
||||||
@ -161,7 +162,7 @@ export abstract class TemplateConfiguration<T, R = any> extends DialogComponent<
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected getNotificationTemplateValue(): NotificationTemplate {
|
protected getNotificationTemplateValue(): NotificationTemplate {
|
||||||
const template: NotificationTemplate = this.templateNotificationForm.value;
|
const template: NotificationTemplate = deepClone(this.templateNotificationForm.value);
|
||||||
this.notificationDeliveryMethods.forEach(method => {
|
this.notificationDeliveryMethods.forEach(method => {
|
||||||
if (template.configuration.deliveryMethodsTemplates[method].enabled) {
|
if (template.configuration.deliveryMethodsTemplates[method].enabled) {
|
||||||
Object.assign(template.configuration.deliveryMethodsTemplates[method], this.deliveryMethodFormsMap.get(method).value, {method});
|
Object.assign(template.configuration.deliveryMethodsTemplates[method], this.deliveryMethodFormsMap.get(method).value, {method});
|
||||||
@ -169,6 +170,6 @@ export abstract class TemplateConfiguration<T, R = any> extends DialogComponent<
|
|||||||
delete template.configuration.deliveryMethodsTemplates[method];
|
delete template.configuration.deliveryMethodsTemplates[method];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return template;
|
return deepTrim(template);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,7 +27,7 @@ import { Router } from '@angular/router';
|
|||||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||||
import { NotificationService } from '@core/http/notification.service';
|
import { NotificationService } from '@core/http/notification.service';
|
||||||
import { deepClone, deepTrim, isDefinedAndNotNull } from '@core/utils';
|
import { deepClone, isDefinedAndNotNull } from '@core/utils';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { map } from 'rxjs/operators';
|
import { map } from 'rxjs/operators';
|
||||||
import { StepperOrientation, StepperSelectionEvent } from '@angular/cdk/stepper';
|
import { StepperOrientation, StepperSelectionEvent } from '@angular/cdk/stepper';
|
||||||
@ -155,7 +155,7 @@ export class TemplateNotificationDialogComponent
|
|||||||
if (this.templateNotification && !this.data.isCopy) {
|
if (this.templateNotification && !this.data.isCopy) {
|
||||||
template = {...this.templateNotification, ...template};
|
template = {...this.templateNotification, ...template};
|
||||||
}
|
}
|
||||||
this.notificationService.saveNotificationTemplate(deepTrim(template)).subscribe(
|
this.notificationService.saveNotificationTemplate(template).subscribe(
|
||||||
(target) => this.dialogRef.close(target)
|
(target) => this.dialogRef.close(target)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,72 @@
|
|||||||
|
<!--
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
-->
|
||||||
|
<mat-form-field [formGroup]="selectDashboardStateFormGroup" class="mat-block" [floatLabel]="floatLabel">
|
||||||
|
<input matInput type="text" placeholder="{{ placeholder || ('widget-action.target-dashboard-state' | translate) }}"
|
||||||
|
#dashboardStateInput
|
||||||
|
formControlName="dashboardStateId"
|
||||||
|
[required]="required"
|
||||||
|
[matAutocomplete]="dashboardStateAutocomplete">
|
||||||
|
<button *ngIf="selectDashboardStateFormGroup.get('dashboardStateId').value"
|
||||||
|
type="button"
|
||||||
|
matSuffix mat-icon-button aria-label="Clear"
|
||||||
|
(click)="clear()">
|
||||||
|
<mat-icon class="material-icons">close</mat-icon>
|
||||||
|
</button>
|
||||||
|
<mat-autocomplete
|
||||||
|
class="tb-autocomplete"
|
||||||
|
#dashboardStateAutocomplete="matAutocomplete">
|
||||||
|
<mat-option *ngFor="let state of filteredStatesDashboard$ | async" [value]="state">
|
||||||
|
<span [innerHTML]="state | highlight:searchText"></span>
|
||||||
|
</mat-option>
|
||||||
|
</mat-autocomplete>
|
||||||
|
<mat-error *ngIf="selectDashboardStateFormGroup.get('dashboardStateId').hasError('required')">
|
||||||
|
{{ '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>-->
|
||||||
@ -0,0 +1,229 @@
|
|||||||
|
///
|
||||||
|
/// 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 { Component, ElementRef, forwardRef, Input, OnInit, ViewChild } from '@angular/core';
|
||||||
|
import { ControlValueAccessor, FormBuilder, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
|
||||||
|
import { Observable, of, ReplaySubject } from 'rxjs';
|
||||||
|
import { debounceTime, distinctUntilChanged, map, share, switchMap, tap } from 'rxjs/operators';
|
||||||
|
import { Dashboard, DashboardInfo } from '@app/shared/models/dashboard.models';
|
||||||
|
import { DashboardService } from '@core/http/dashboard.service';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
import { AppState } from '@app/core/core.state';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
import { coerceBooleanProperty } from '@angular/cdk/coercion';
|
||||||
|
import { FloatLabelType } from '@angular/material/form-field';
|
||||||
|
import { DashboardUtilsService } from '@core/services/dashboard-utils.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'tb-dashboard-state-autocomplete',
|
||||||
|
templateUrl: './dashboard-state-autocomplete.component.html',
|
||||||
|
styleUrls: [],
|
||||||
|
providers: [{
|
||||||
|
provide: NG_VALUE_ACCESSOR,
|
||||||
|
useExisting: forwardRef(() => DashboardStateAutocompleteComponent),
|
||||||
|
multi: true
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
export class DashboardStateAutocompleteComponent implements ControlValueAccessor, OnInit {
|
||||||
|
|
||||||
|
private dirty = false;
|
||||||
|
private modelValue: string;
|
||||||
|
|
||||||
|
private latestDashboardStates: Array<string> = null;
|
||||||
|
private dashboardStatesFetchObservable$: Observable<Array<string>> = null;
|
||||||
|
|
||||||
|
private propagateChange = (v: any) => { };
|
||||||
|
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
placeholder: string;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
floatLabel: FloatLabelType = 'auto';
|
||||||
|
|
||||||
|
private requiredValue: boolean;
|
||||||
|
get required(): boolean {
|
||||||
|
return this.requiredValue;
|
||||||
|
}
|
||||||
|
@Input()
|
||||||
|
set required(value: boolean) {
|
||||||
|
this.requiredValue = coerceBooleanProperty(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
disabled: boolean;
|
||||||
|
|
||||||
|
private dashboardIdValue: string;
|
||||||
|
get dashboardId(): string {
|
||||||
|
return this.dashboardIdValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
set dashboardId(value: string) {
|
||||||
|
this.dashboardIdValue = value;
|
||||||
|
this.clearDashboardStateCache();
|
||||||
|
this.searchText = '';
|
||||||
|
this.selectDashboardStateFormGroup.get('dashboardStateId').patchValue('', {emitEvent: false});
|
||||||
|
this.dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewChild('dashboardStateInput', {static: true}) dashboardStateInput: ElementRef;
|
||||||
|
|
||||||
|
filteredStatesDashboard$: Observable<Array<string>>;
|
||||||
|
|
||||||
|
searchText = '';
|
||||||
|
|
||||||
|
selectDashboardStateFormGroup = this.fb.group({
|
||||||
|
dashboardStateId: [null]
|
||||||
|
});
|
||||||
|
|
||||||
|
constructor(private store: Store<AppState>,
|
||||||
|
public translate: TranslateService,
|
||||||
|
private dashboardService: DashboardService,
|
||||||
|
private dashboardUtils: DashboardUtilsService,
|
||||||
|
private fb: FormBuilder) {
|
||||||
|
}
|
||||||
|
|
||||||
|
registerOnChange(fn: any): void {
|
||||||
|
this.propagateChange = fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
registerOnTouched(fn: any): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
if (this.required) {
|
||||||
|
this.selectDashboardStateFormGroup.get('dashboardStateId').addValidators(Validators.required);
|
||||||
|
this.selectDashboardStateFormGroup.get('dashboardStateId').updateValueAndValidity({emitEvent: false});
|
||||||
|
}
|
||||||
|
this.filteredStatesDashboard$ = this.selectDashboardStateFormGroup.get('dashboardStateId').valueChanges
|
||||||
|
.pipe(
|
||||||
|
debounceTime(150),
|
||||||
|
tap(value => {
|
||||||
|
let modelValue;
|
||||||
|
if (!value || !this.latestDashboardStates.includes(value)) {
|
||||||
|
modelValue = null;
|
||||||
|
} else {
|
||||||
|
modelValue = value;
|
||||||
|
}
|
||||||
|
this.updateView(modelValue);
|
||||||
|
}),
|
||||||
|
distinctUntilChanged(),
|
||||||
|
switchMap(name => this.fetchDashboardStates(name) ),
|
||||||
|
share()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
setDisabledState(isDisabled: boolean): void {
|
||||||
|
this.disabled = isDisabled;
|
||||||
|
if (this.disabled) {
|
||||||
|
this.selectDashboardStateFormGroup.disable({emitEvent: false});
|
||||||
|
} else {
|
||||||
|
this.selectDashboardStateFormGroup.enable({emitEvent: false});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writeValue(value: string | null): void {
|
||||||
|
this.searchText = '';
|
||||||
|
if (value != null) {
|
||||||
|
this.modelValue = value;
|
||||||
|
this.selectDashboardStateFormGroup.get('dashboardStateId').patchValue(value, {emitEvent: false});
|
||||||
|
} else {
|
||||||
|
this.modelValue = null;
|
||||||
|
this.selectDashboardStateFormGroup.get('dashboardStateId').patchValue('', {emitEvent: false});
|
||||||
|
}
|
||||||
|
this.dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateView(value: string | null) {
|
||||||
|
if (this.modelValue !== value) {
|
||||||
|
this.modelValue = value;
|
||||||
|
this.propagateChange(this.modelValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
displayDashboardFn(dashboard?: DashboardInfo): string | undefined {
|
||||||
|
return dashboard ? dashboard.title : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
onFocus() {
|
||||||
|
if (this.dirty) {
|
||||||
|
this.selectDashboardStateFormGroup.get('dashboard').updateValueAndValidity({onlySelf: true});
|
||||||
|
this.dirty = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clear(value = '') {
|
||||||
|
this.dashboardStateInput.nativeElement.value = value;
|
||||||
|
this.selectDashboardStateFormGroup.get('dashboardStateId').patchValue(value, {emitEvent: true});
|
||||||
|
setTimeout(() => {
|
||||||
|
this.dashboardStateInput.nativeElement.blur();
|
||||||
|
this.dashboardStateInput.nativeElement.focus();
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private fetchDashboardStates(searchText?: string): Observable<Array<string>> {
|
||||||
|
if (this.searchText !== searchText || this.latestDashboardStates === null) {
|
||||||
|
this.searchText = searchText;
|
||||||
|
const slackConversationFilter = this.createFilterForDashboardState(this.searchText);
|
||||||
|
return this.getDashboardStatesById().pipe(
|
||||||
|
map(name => name.filter(slackConversationFilter)),
|
||||||
|
tap(res => this.latestDashboardStates = res)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return of(this.latestDashboardStates);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getDashboardStatesById() {
|
||||||
|
if (this.dashboardStatesFetchObservable$ === null) {
|
||||||
|
let fetchObservable: Observable<Array<string>>;
|
||||||
|
if (this.dashboardId) {
|
||||||
|
fetchObservable = this.dashboardService.getDashboard(this.dashboardId, {ignoreLoading: true}).pipe(
|
||||||
|
map((dashboard: Dashboard) => {
|
||||||
|
if (dashboard) {
|
||||||
|
dashboard = this.dashboardUtils.validateAndUpdateDashboard(dashboard);
|
||||||
|
const states = dashboard.configuration.states;
|
||||||
|
return Object.keys(states);
|
||||||
|
} else {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
fetchObservable = of([]);
|
||||||
|
}
|
||||||
|
this.dashboardStatesFetchObservable$ = fetchObservable.pipe(
|
||||||
|
share({
|
||||||
|
connector: () => new ReplaySubject(1),
|
||||||
|
resetOnError: false,
|
||||||
|
resetOnComplete: false,
|
||||||
|
resetOnRefCountZero: false
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return this.dashboardStatesFetchObservable$;
|
||||||
|
}
|
||||||
|
|
||||||
|
private createFilterForDashboardState(query: string): (stateId: string) => boolean {
|
||||||
|
const lowercaseQuery = query.toLowerCase();
|
||||||
|
return stateId => stateId.toLowerCase().indexOf(lowercaseQuery) === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private clearDashboardStateCache(): void {
|
||||||
|
this.latestDashboardStates = null;
|
||||||
|
this.dashboardStatesFetchObservable$ = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -50,7 +50,8 @@ export interface NotificationInfo {
|
|||||||
export interface NotificationRequest extends Omit<BaseData<NotificationRequestId>, 'label'> {
|
export interface NotificationRequest extends Omit<BaseData<NotificationRequestId>, 'label'> {
|
||||||
tenantId?: TenantId;
|
tenantId?: TenantId;
|
||||||
targets: Array<string>;
|
targets: Array<string>;
|
||||||
templateId: NotificationTemplateId;
|
templateId?: NotificationTemplateId;
|
||||||
|
template?: NotificationTemplate;
|
||||||
info?: NotificationInfo;
|
info?: NotificationInfo;
|
||||||
deliveryMethods: Array<NotificationDeliveryMethod>;
|
deliveryMethods: Array<NotificationDeliveryMethod>;
|
||||||
originatorEntityId: EntityId;
|
originatorEntityId: EntityId;
|
||||||
|
|||||||
@ -1,3 +1,19 @@
|
|||||||
|
///
|
||||||
|
/// 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 { NgZone } from '@angular/core';
|
import { NgZone } from '@angular/core';
|
||||||
import { WebsocketCmd } from '@shared/models/telemetry/telemetry.models';
|
import { WebsocketCmd } from '@shared/models/telemetry/telemetry.models';
|
||||||
import { Subject } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
|
|||||||
@ -86,6 +86,7 @@ import { MarkdownEditorComponent } from '@shared/components/markdown-editor.comp
|
|||||||
import { FullscreenDirective } from '@shared/components/fullscreen.directive';
|
import { FullscreenDirective } from '@shared/components/fullscreen.directive';
|
||||||
import { HighlightPipe } from '@shared/pipe/highlight.pipe';
|
import { HighlightPipe } from '@shared/pipe/highlight.pipe';
|
||||||
import { DashboardAutocompleteComponent } from '@shared/components/dashboard-autocomplete.component';
|
import { DashboardAutocompleteComponent } from '@shared/components/dashboard-autocomplete.component';
|
||||||
|
import { DashboardStateAutocompleteComponent } from '@shared/components/dashboard-state-autocomplete.component';
|
||||||
import { EntitySubTypeAutocompleteComponent } from '@shared/components/entity/entity-subtype-autocomplete.component';
|
import { EntitySubTypeAutocompleteComponent } from '@shared/components/entity/entity-subtype-autocomplete.component';
|
||||||
import { EntitySubTypeSelectComponent } from '@shared/components/entity/entity-subtype-select.component';
|
import { EntitySubTypeSelectComponent } from '@shared/components/entity/entity-subtype-select.component';
|
||||||
import { EntityAutocompleteComponent } from '@shared/components/entity/entity-autocomplete.component';
|
import { EntityAutocompleteComponent } from '@shared/components/entity/entity-autocomplete.component';
|
||||||
@ -243,6 +244,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService)
|
|||||||
TimezoneSelectComponent,
|
TimezoneSelectComponent,
|
||||||
ValueInputComponent,
|
ValueInputComponent,
|
||||||
DashboardAutocompleteComponent,
|
DashboardAutocompleteComponent,
|
||||||
|
DashboardStateAutocompleteComponent,
|
||||||
EntitySubTypeAutocompleteComponent,
|
EntitySubTypeAutocompleteComponent,
|
||||||
EntitySubTypeSelectComponent,
|
EntitySubTypeSelectComponent,
|
||||||
EntitySubTypeListComponent,
|
EntitySubTypeListComponent,
|
||||||
@ -403,6 +405,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService)
|
|||||||
DatetimeComponent,
|
DatetimeComponent,
|
||||||
TimezoneSelectComponent,
|
TimezoneSelectComponent,
|
||||||
DashboardAutocompleteComponent,
|
DashboardAutocompleteComponent,
|
||||||
|
DashboardStateAutocompleteComponent,
|
||||||
EntitySubTypeAutocompleteComponent,
|
EntitySubTypeAutocompleteComponent,
|
||||||
EntitySubTypeSelectComponent,
|
EntitySubTypeSelectComponent,
|
||||||
EntitySubTypeListComponent,
|
EntitySubTypeListComponent,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user