Browse Source

UI: Device profile alarm rules

pull/3477/head
Igor Kulikov 6 years ago
parent
commit
3a830eeb9a
  1. 19
      ui-ngx/src/app/modules/home/components/filter/filter-text.component.html
  2. 79
      ui-ngx/src/app/modules/home/components/filter/filter-text.component.scss
  3. 101
      ui-ngx/src/app/modules/home/components/filter/filter-text.component.ts
  4. 3
      ui-ngx/src/app/modules/home/components/home-components.module.ts
  5. 32
      ui-ngx/src/app/modules/home/components/profile/alarm/alarm-rule-condition.component.html
  6. 17
      ui-ngx/src/app/modules/home/components/profile/alarm/alarm-rule-condition.component.scss
  7. 23
      ui-ngx/src/app/modules/home/components/profile/alarm/alarm-rule-condition.component.ts
  8. 88
      ui-ngx/src/app/modules/home/components/profile/alarm/alarm-rule.component.html
  9. 5
      ui-ngx/src/app/modules/home/components/profile/alarm/alarm-rule.component.scss
  10. 6
      ui-ngx/src/app/modules/home/components/profile/alarm/create-alarm-rules.component.html
  11. 2
      ui-ngx/src/app/modules/home/components/profile/alarm/create-alarm-rules.component.ts
  12. 4
      ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.html
  13. 3
      ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarms.component.html
  14. 2
      ui-ngx/src/app/modules/home/components/profile/device-profile-data.component.html
  15. 94
      ui-ngx/src/app/shared/models/query/query.models.ts
  16. 12
      ui-ngx/src/assets/locale/locale.constant-en_US.json

19
ui-ngx/src/app/modules/home/components/filter/filter-text.component.html

@ -0,0 +1,19 @@
<!--
Copyright © 2016-2020 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 class="tb-filter-text" [ngClass]="{disabled: disabled, required: requiredClass}"
[innerHTML]="filterText"></div>

79
ui-ngx/src/app/modules/home/components/filter/filter-text.component.scss

@ -0,0 +1,79 @@
/**
* Copyright © 2016-2020 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 {
.tb-filter-text {
overflow-y: auto;
&.disabled {
opacity: 0.7;
}
&.required {
color: #f44336;
}
}
}
:host ::ng-deep {
.tb-filter-text {
line-height: 1.8em;
span {
display: inline-block;
vertical-align: middle;
line-height: 1.4em;
}
.tb-filter-predicate {
padding-right: 4px;
padding-left: 4px;
}
.tb-filter-entity-key, .tb-filter-value, .tb-filter-dynamic-source {
font-weight: bold;
border: 1px groove rgba(0, 0, 0, .25);
border-radius: 4px;
padding-left: 4px;
padding-right: 4px;
}
.tb-filter-entity-key, .tb-filter-value {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 150px;
}
.tb-filter-dynamic-source {
}
.tb-filter-entity-key {
color: #305680;
}
.tb-filter-value {
color: #ff5722;
}
.tb-filter-simple-operation {
font-size: 0.9em;
}
.tb-filter-complex-operation {
text-transform: uppercase;
font-weight: bold;
}
.tb-filter-dynamic-value {
.tb-filter-dynamic-source, .tb-filter-value {
color: #0c959c;
}
}
.tb-filter-bracket {
.tb-left-bracket, .tb-right-bracket {
font-size: 1.2em;
}
}
}
}

101
ui-ngx/src/app/modules/home/components/filter/filter-text.component.ts

@ -0,0 +1,101 @@
///
/// Copyright © 2016-2020 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, forwardRef, Input, OnInit } from '@angular/core';
import { ControlValueAccessor, FormBuilder, NG_VALUE_ACCESSOR } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { KeyFilter, keyFiltersToText } from '@shared/models/query/query.models';
import { TranslateService } from '@ngx-translate/core';
import { DatePipe } from '@angular/common';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
@Component({
selector: 'tb-filter-text',
templateUrl: './filter-text.component.html',
styleUrls: ['./filter-text.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => FilterTextComponent),
multi: true
}
]
})
export class FilterTextComponent implements ControlValueAccessor, OnInit {
private requiredValue: boolean;
get required(): boolean {
return this.requiredValue;
}
@Input()
set required(value: boolean) {
this.requiredValue = coerceBooleanProperty(value);
}
@Input()
disabled: boolean;
@Input()
noFilterText = this.translate.instant('filter.no-filter-text');
@Input()
addFilterPrompt = this.translate.instant('filter.add-filter-prompt');
requiredClass = false;
private filterText: string;
private propagateChange = (v: any) => { };
constructor(private dialog: MatDialog,
private fb: FormBuilder,
private translate: TranslateService,
private datePipe: DatePipe) {
}
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
registerOnTouched(fn: any): void {
}
ngOnInit() {
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
}
writeValue(value: Array<KeyFilter>): void {
this.updateFilterText(value);
}
private updateFilterText(value: Array<KeyFilter>) {
this.requiredClass = false;
if (value && value.length) {
this.filterText = keyFiltersToText(this.translate, this.datePipe, value);
} else {
if (this.required && !this.disabled) {
this.filterText = this.addFilterPrompt;
this.requiredClass = true;
} else {
this.filterText = this.noFilterText;
}
}
}
}

3
ui-ngx/src/app/modules/home/components/home-components.module.ts

@ -104,6 +104,7 @@ import { CreateAlarmRulesComponent } from './profile/alarm/create-alarm-rules.co
import { AlarmRuleComponent } from './profile/alarm/alarm-rule.component'; import { AlarmRuleComponent } from './profile/alarm/alarm-rule.component';
import { AlarmRuleConditionComponent } from './profile/alarm/alarm-rule-condition.component'; import { AlarmRuleConditionComponent } from './profile/alarm/alarm-rule-condition.component';
import { AlarmRuleKeyFiltersDialogComponent } from './profile/alarm/alarm-rule-key-filters-dialog.component'; import { AlarmRuleKeyFiltersDialogComponent } from './profile/alarm/alarm-rule-key-filters-dialog.component';
import { FilterTextComponent } from './filter/filter-text.component';
@NgModule({ @NgModule({
declarations: declarations:
@ -165,6 +166,7 @@ import { AlarmRuleKeyFiltersDialogComponent } from './profile/alarm/alarm-rule-k
FilterDialogComponent, FilterDialogComponent,
FiltersDialogComponent, FiltersDialogComponent,
FilterSelectComponent, FilterSelectComponent,
FilterTextComponent,
FiltersEditComponent, FiltersEditComponent,
FiltersEditPanelComponent, FiltersEditPanelComponent,
UserFilterDialogComponent, UserFilterDialogComponent,
@ -245,6 +247,7 @@ import { AlarmRuleKeyFiltersDialogComponent } from './profile/alarm/alarm-rule-k
FilterDialogComponent, FilterDialogComponent,
FiltersDialogComponent, FiltersDialogComponent,
FilterSelectComponent, FilterSelectComponent,
FilterTextComponent,
FiltersEditComponent, FiltersEditComponent,
UserFilterDialogComponent, UserFilterDialogComponent,
TenantProfileAutocompleteComponent, TenantProfileAutocompleteComponent,

32
ui-ngx/src/app/modules/home/components/profile/alarm/alarm-rule-condition.component.html

@ -15,16 +15,22 @@
limitations under the License. limitations under the License.
--> -->
<mat-form-field class="mat-block" (click)="openFilterDialog($event)" floatLabel="always" hideRequiredMarker> <div fxLayout="column" fxFlex>
<mat-label></mat-label> <div fxLayout="row" fxLayoutAlign="start center" style="min-height: 40px;">
<input readonly <div class="tb-small" translate>device-profile.alarm-rule-condition</div>
required matInput [formControl]="alarmRuleConditionControl" <span fxFlex></span>
placeholder="{{'device-profile.enter-alarm-rule-condition-prompt' | translate}}"> <a mat-button color="primary"
<a matSuffix mat-icon-button color="primary" type="button"
type="button" (click)="openFilterDialog($event)"
(click)="openFilterDialog($event)" matTooltip="{{ (disabled ? 'action.view' : 'action.edit') | translate }}"
matTooltip="{{ (disabled ? 'action.view' : 'action.edit') | translate }}" matTooltipPosition="above">
matTooltipPosition="above"> {{ (disabled ? 'action.view' : (conditionSet() ? 'action.edit' : 'action.add')) | translate }}
<mat-icon>{{ disabled ? 'more_vert' : 'edit' }}</mat-icon> </a>
</a> </div>
</mat-form-field> <div class="tb-alarm-rule-condition" fxFlex fxLayout="column" fxLayoutAlign="center" (click)="openFilterDialog($event)">
<tb-filter-text [formControl]="alarmRuleConditionControl"
required
addFilterPrompt="{{'device-profile.enter-alarm-rule-condition-prompt' | translate}}">
</tb-filter-text>
</div>
</div>

17
ui-ngx/src/app/modules/home/components/profile/alarm/alarm-rule-condition.component.scss

@ -14,9 +14,24 @@
* limitations under the License. * limitations under the License.
*/ */
:host { :host {
a.mat-icon-button { display: flex;
a.mat-button {
&:hover, &:focus { &:hover, &:focus {
border-bottom: none; border-bottom: none;
} }
} }
.tb-alarm-rule-condition {
padding: 8px;
border: 1px groove rgba(0, 0, 0, .25);
border-radius: 4px;
cursor: pointer;
}
}
:host ::ng-deep {
.tb-alarm-rule-condition {
.tb-filter-text {
max-height: 200px;
}
}
} }

23
ui-ngx/src/app/modules/home/components/profile/alarm/alarm-rule-condition.component.ts

@ -30,6 +30,8 @@ import {
AlarmRuleKeyFiltersDialogComponent, AlarmRuleKeyFiltersDialogComponent,
AlarmRuleKeyFiltersDialogData AlarmRuleKeyFiltersDialogData
} from './alarm-rule-key-filters-dialog.component'; } from './alarm-rule-key-filters-dialog.component';
import { TranslateService } from '@ngx-translate/core';
import { DatePipe } from '@angular/common';
@Component({ @Component({
selector: 'tb-alarm-rule-condition', selector: 'tb-alarm-rule-condition',
@ -60,7 +62,9 @@ export class AlarmRuleConditionComponent implements ControlValueAccessor, OnInit
private propagateChange = (v: any) => { }; private propagateChange = (v: any) => { };
constructor(private dialog: MatDialog, constructor(private dialog: MatDialog,
private fb: FormBuilder) { private fb: FormBuilder,
private translate: TranslateService,
private datePipe: DatePipe) {
} }
registerOnChange(fn: any): void { registerOnChange(fn: any): void {
@ -76,6 +80,11 @@ export class AlarmRuleConditionComponent implements ControlValueAccessor, OnInit
setDisabledState(isDisabled: boolean): void { setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled; this.disabled = isDisabled;
if (this.disabled) {
this.alarmRuleConditionControl.disable({emitEvent: false});
} else {
this.alarmRuleConditionControl.enable({emitEvent: false});
}
} }
writeValue(value: Array<KeyFilter>): void { writeValue(value: Array<KeyFilter>): void {
@ -83,8 +92,12 @@ export class AlarmRuleConditionComponent implements ControlValueAccessor, OnInit
this.updateConditionInfo(); this.updateConditionInfo();
} }
public conditionSet() {
return this.modelValue && this.modelValue.length;
}
public validate(c: FormControl) { public validate(c: FormControl) {
return (this.modelValue && this.modelValue.length) ? null : { return this.conditionSet() ? null : {
alarmRuleCondition: { alarmRuleCondition: {
valid: false, valid: false,
}, },
@ -112,11 +125,7 @@ export class AlarmRuleConditionComponent implements ControlValueAccessor, OnInit
} }
private updateConditionInfo() { private updateConditionInfo() {
if (this.modelValue && this.modelValue.length) { this.alarmRuleConditionControl.patchValue(this.modelValue);
this.alarmRuleConditionControl.patchValue('Condition set');
} else {
this.alarmRuleConditionControl.patchValue(null);
}
} }
private updateModel() { private updateModel() {

88
ui-ngx/src/app/modules/home/components/profile/alarm/alarm-rule.component.html

@ -16,56 +16,56 @@
--> -->
<div fxLayout="column" [formGroup]="alarmRuleFormGroup"> <div fxLayout="column" [formGroup]="alarmRuleFormGroup">
<div formGroupName="condition" fxLayout="row" fxLayoutAlign="start" fxLayoutGap="8px" fxFlex> <div formGroupName="condition" fxLayout="row" fxLayoutGap="8px" fxFlex>
<div fxLayout="column" fxFlex> <tb-alarm-rule-condition fxFlex
formControlName="condition">
</tb-alarm-rule-condition>
<div fxLayout="column">
<div fxLayout="row" fxLayoutAlign="start center" style="min-height: 40px;"> <div fxLayout="row" fxLayoutAlign="start center" style="min-height: 40px;">
<label class="tb-small" translate>device-profile.alarm-rule-condition</label> <div class="tb-small" translate>device-profile.condition-duration</div>
</div> <span fxFlex></span>
<tb-alarm-rule-condition fxFlex
formControlName="condition">
</tb-alarm-rule-condition>
</div>
<div fxLayout="column" style="min-width: 250px;">
<div fxLayout="row" fxLayoutAlign="start center" style="min-height: 40px;">
<label fxFlex class="tb-small" translate>device-profile.condition-duration</label>
<mat-slide-toggle [disabled]="disabled" <mat-slide-toggle [disabled]="disabled"
color="primary"
[ngModelOptions]="{standalone: true}" [ngModelOptions]="{standalone: true}"
(ngModelChange)="enableDurationChanged($event)" (ngModelChange)="enableDurationChanged($event)"
[ngModel]="enableDuration"> [ngModel]="enableDuration">
</mat-slide-toggle> </mat-slide-toggle>
</div> </div>
<div fxLayout="row" fxLayoutGap="8px" [fxShow]="enableDuration"> <div class="tb-condition-duration" fxFlex fxLayout="row" fxLayoutGap="8px">
<mat-form-field class="mat-block duration-value-field" hideRequiredMarker floatLabel="always"> <span style="min-width: 250px;" [fxShow]="!enableDuration"></span>
<mat-label></mat-label> <div style="min-width: 250px;" fxLayout="row" fxLayoutGap="8px" [fxShow]="enableDuration">
<input type="number" <mat-form-field class="mat-block duration-value-field" hideRequiredMarker floatLabel="always">
[required]="enableDuration" <mat-label></mat-label>
step="1" <input type="number"
min="1" max="2147483647" matInput [required]="enableDuration"
placeholder="{{ 'device-profile.condition-duration-value' | translate }}" step="1"
formControlName="durationValue"> min="1" max="2147483647" matInput
<mat-error *ngIf="alarmRuleFormGroup.get('condition').get('durationValue').hasError('required')"> placeholder="{{ 'device-profile.condition-duration-value' | translate }}"
{{ 'device-profile.condition-duration-value-required' | translate }} formControlName="durationValue">
</mat-error> <mat-error *ngIf="alarmRuleFormGroup.get('condition').get('durationValue').hasError('required')">
<mat-error *ngIf="alarmRuleFormGroup.get('condition').get('durationValue').hasError('min')"> {{ 'device-profile.condition-duration-value-required' | translate }}
{{ 'device-profile.condition-duration-value-range' | translate }} </mat-error>
</mat-error> <mat-error *ngIf="alarmRuleFormGroup.get('condition').get('durationValue').hasError('min')">
<mat-error *ngIf="alarmRuleFormGroup.get('condition').get('durationValue').hasError('max')"> {{ 'device-profile.condition-duration-value-range' | translate }}
{{ 'device-profile.condition-duration-value-range' | translate }} </mat-error>
</mat-error> <mat-error *ngIf="alarmRuleFormGroup.get('condition').get('durationValue').hasError('max')">
</mat-form-field> {{ 'device-profile.condition-duration-value-range' | translate }}
<mat-form-field class="mat-block duration-unit-field" hideRequiredMarker floatLabel="always"> </mat-error>
<mat-label></mat-label> </mat-form-field>
<mat-select formControlName="durationUnit" <mat-form-field class="mat-block duration-unit-field" hideRequiredMarker floatLabel="always">
[required]="enableDuration" <mat-label></mat-label>
placeholder="{{ 'device-profile.condition-duration-time-unit' | translate }}"> <mat-select formControlName="durationUnit"
<mat-option *ngFor="let timeUnit of timeUnits" [value]="timeUnit"> [required]="enableDuration"
{{ timeUnitTranslations.get(timeUnit) | translate }} placeholder="{{ 'device-profile.condition-duration-time-unit' | translate }}">
</mat-option> <mat-option *ngFor="let timeUnit of timeUnits" [value]="timeUnit">
</mat-select> {{ timeUnitTranslations.get(timeUnit) | translate }}
<mat-error *ngIf="alarmRuleFormGroup.get('condition').get('durationUnit').hasError('required')"> </mat-option>
{{ 'device-profile.condition-duration-time-unit-required' | translate }} </mat-select>
</mat-error> <mat-error *ngIf="alarmRuleFormGroup.get('condition').get('durationUnit').hasError('required')">
</mat-form-field> {{ 'device-profile.condition-duration-time-unit-required' | translate }}
</mat-error>
</mat-form-field>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -73,7 +73,7 @@
<mat-expansion-panel-header> <mat-expansion-panel-header>
<mat-panel-title> <mat-panel-title>
<div fxFlex fxLayout="row" fxLayoutAlign="end center"> <div fxFlex fxLayout="row" fxLayoutAlign="end center">
<div class="tb-small" translate>device-profile.advanced-settings</div> <div class="tb-small" translate>device-profile.alarm-rule-details</div>
</div> </div>
</mat-panel-title> </mat-panel-title>
</mat-expansion-panel-header> </mat-expansion-panel-header>

5
ui-ngx/src/app/modules/home/components/profile/alarm/alarm-rule.component.scss

@ -14,6 +14,11 @@
* limitations under the License. * limitations under the License.
*/ */
:host { :host {
.tb-condition-duration {
padding: 8px;
border: 1px groove rgba(0, 0, 0, .25);
border-radius: 4px;
}
.mat-expansion-panel.advanced-settings { .mat-expansion-panel.advanced-settings {
box-shadow: none; box-shadow: none;
border: none; border: none;

6
ui-ngx/src/app/modules/home/components/profile/alarm/create-alarm-rules.component.html

@ -36,7 +36,7 @@
<tb-alarm-rule formControlName="alarmRule" required fxFlex> <tb-alarm-rule formControlName="alarmRule" required fxFlex>
</tb-alarm-rule> </tb-alarm-rule>
</div> </div>
<button *ngIf="!disabled && createAlarmRulesFormArray().controls.length > 1" <button *ngIf="!disabled"
mat-icon-button color="primary" style="min-width: 40px;" mat-icon-button color="primary" style="min-width: 40px;"
type="button" type="button"
(click)="removeCreateAlarmRule($index)" (click)="removeCreateAlarmRule($index)"
@ -45,6 +45,10 @@
<mat-icon>remove_circle_outline</mat-icon> <mat-icon>remove_circle_outline</mat-icon>
</button> </button>
</div> </div>
<div *ngIf="disabled && !createAlarmRulesFormArray().controls.length">
<span translate fxLayoutAlign="center center"
class="tb-prompt">device-profile.no-create-alarm-rules</span>
</div>
<div fxLayout="row" *ngIf="!disabled"> <div fxLayout="row" *ngIf="!disabled">
<button mat-stroked-button color="primary" <button mat-stroked-button color="primary"
type="button" type="button"

2
ui-ngx/src/app/modules/home/components/profile/alarm/create-alarm-rules.component.ts

@ -142,7 +142,7 @@ export class CreateAlarmRulesComponent implements ControlValueAccessor, OnInit,
} }
public validate(c: FormControl) { public validate(c: FormControl) {
return (this.createAlarmRulesFormGroup.valid && this.createAlarmRulesFormGroup.get('createAlarmRules').value.length) ? null : { return (this.createAlarmRulesFormGroup.valid) ? null : {
createAlarmRules: { createAlarmRules: {
valid: false, valid: false,
}, },

4
ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarm.component.html

@ -66,6 +66,10 @@
<mat-icon>remove_circle_outline</mat-icon> <mat-icon>remove_circle_outline</mat-icon>
</button> </button>
</div> </div>
<div *ngIf="disabled && !alarmFormGroup.get('clearRule').value">
<span translate fxLayoutAlign="center center"
class="tb-prompt">device-profile.no-clear-alarm-rule</span>
</div>
<div fxLayout="row" *ngIf="!disabled" <div fxLayout="row" *ngIf="!disabled"
[fxShow]="!alarmFormGroup.get('clearRule').value"> [fxShow]="!alarmFormGroup.get('clearRule').value">
<button mat-stroked-button color="primary" <button mat-stroked-button color="primary"

3
ui-ngx/src/app/modules/home/components/profile/alarm/device-profile-alarms.component.html

@ -32,8 +32,7 @@
(click)="addAlarm()" (click)="addAlarm()"
matTooltip="{{ 'device-profile.add-alarm-rule' | translate }}" matTooltip="{{ 'device-profile.add-alarm-rule' | translate }}"
matTooltipPosition="above"> matTooltipPosition="above">
<mat-icon>add</mat-icon> <span translate>device-profile.add-alarm-rule</span>
<span translate>action.add</span>
</button> </button>
</div> </div>
</div> </div>

2
ui-ngx/src/app/modules/home/components/profile/device-profile-data.component.html

@ -39,7 +39,7 @@
required> required>
</tb-device-profile-transport-configuration> </tb-device-profile-transport-configuration>
</mat-expansion-panel> </mat-expansion-panel>
<mat-expansion-panel [expanded]="false"> <mat-expansion-panel [expanded]="true">
<mat-expansion-panel-header> <mat-expansion-panel-header>
<mat-panel-title> <mat-panel-title>
<div>{{'device-profile.alarm-rules' | translate: <div>{{'device-profile.alarm-rules' | translate:

94
ui-ngx/src/app/shared/models/query/query.models.ts

@ -25,6 +25,8 @@ import { PageData } from '@shared/models/page/page-data';
import { isDefined, isEqual } from '@core/utils'; import { isDefined, isEqual } from '@core/utils';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { AlarmInfo, AlarmSearchStatus, AlarmSeverity } from '../alarm.models'; import { AlarmInfo, AlarmSearchStatus, AlarmSeverity } from '../alarm.models';
import { Filter } from '@material-ui/icons';
import { DatePipe } from '@angular/common';
export enum EntityKeyType { export enum EntityKeyType {
ATTRIBUTE = 'ATTRIBUTE', ATTRIBUTE = 'ATTRIBUTE',
@ -358,6 +360,98 @@ export interface FiltersInfo {
datasourceFilters: {[datasourceIndex: number]: FilterInfo}; datasourceFilters: {[datasourceIndex: number]: FilterInfo};
} }
export function keyFiltersToText(translate: TranslateService, datePipe: DatePipe, keyFilters: Array<KeyFilter>): string {
const filtersText = keyFilters.map(keyFilter =>
keyFilterToText(translate, datePipe, keyFilter,
keyFilters.length > 1 ? ComplexOperation.AND : undefined));
let result: string;
if (filtersText.length > 1) {
const andText = translate.instant('filter.operation.and');
result = filtersText.join(' <span class="tb-filter-complex-operation">' + andText + '</span> ');
} else {
result = filtersText[0];
}
return result;
}
export function keyFilterToText(translate: TranslateService, datePipe: DatePipe, keyFilter: KeyFilter,
parentComplexOperation?: ComplexOperation): string {
const keyFilterPredicate = keyFilter.predicate;
return keyFilterPredicateToText(translate, datePipe, keyFilter, keyFilterPredicate, parentComplexOperation);
}
export function keyFilterPredicateToText(translate: TranslateService,
datePipe: DatePipe,
keyFilter: KeyFilter,
keyFilterPredicate: KeyFilterPredicate,
parentComplexOperation?: ComplexOperation): string {
if (keyFilterPredicate.type === FilterPredicateType.COMPLEX) {
const complexPredicate = keyFilterPredicate as ComplexFilterPredicate;
const complexOperation = complexPredicate.operation;
const complexPredicatesText =
complexPredicate.predicates.map(predicate => keyFilterPredicateToText(translate, datePipe, keyFilter, predicate, complexOperation));
if (complexPredicatesText.length > 1) {
const operationText = translate.instant(complexOperationTranslationMap.get(complexOperation));
let result = complexPredicatesText.join(' <span class="tb-filter-complex-operation">' + operationText + '</span> ');
if (complexOperation === ComplexOperation.OR && parentComplexOperation && ComplexOperation.OR !== parentComplexOperation) {
result = `<span class="tb-filter-bracket"><span class="tb-left-bracket">(</span>${result}<span class="tb-right-bracket">)</span></span>`;
}
return result;
} else {
return complexPredicatesText[0];
}
} else {
return simpleKeyFilterPredicateToText(translate, datePipe, keyFilter, keyFilterPredicate);
}
}
function simpleKeyFilterPredicateToText(translate: TranslateService,
datePipe: DatePipe,
keyFilter: KeyFilter,
keyFilterPredicate: StringFilterPredicate |
NumericFilterPredicate |
BooleanFilterPredicate): string {
const key = keyFilter.key.key;
let operation: string;
let value: string;
const val = keyFilterPredicate.value;
const dynamicValue = !!val.dynamicValue && !!val.dynamicValue.sourceType;
if (dynamicValue) {
value = '<span class="tb-filter-dynamic-value"><span class="tb-filter-dynamic-source">' +
translate.instant(dynamicValueSourceTypeTranslationMap.get(val.dynamicValue.sourceType)) + '</span>';
value += '.<span class="tb-filter-value">' + val.dynamicValue.sourceAttribute + '</span></span>';
}
switch (keyFilterPredicate.type) {
case FilterPredicateType.STRING:
operation = translate.instant(stringOperationTranslationMap.get(keyFilterPredicate.operation));
if (keyFilterPredicate.ignoreCase) {
operation += ' ' + translate.instant('filter.ignore-case');
}
if (!dynamicValue) {
value = `'${keyFilterPredicate.value.defaultValue}'`;
}
break;
case FilterPredicateType.NUMERIC:
operation = translate.instant(numericOperationTranslationMap.get(keyFilterPredicate.operation));
if (!dynamicValue) {
if (keyFilter.valueType === EntityKeyValueType.DATE_TIME) {
value = datePipe.transform(keyFilterPredicate.value.defaultValue, 'yyyy-MM-dd HH:mm');
} else {
value = keyFilterPredicate.value.defaultValue + '';
}
}
break;
case FilterPredicateType.BOOLEAN:
operation = translate.instant(booleanOperationTranslationMap.get(keyFilterPredicate.operation));
value = translate.instant(keyFilterPredicate.value.defaultValue ? 'value.true' : 'value.false');
break;
}
if (!dynamicValue) {
value = `<span class="tb-filter-value">${value}</span>`;
}
return `<span class="tb-filter-predicate"><span class="tb-filter-entity-key">${key}</span> <span class="tb-filter-simple-operation">${operation}</span> ${value}</span>`;
}
export function keyFilterInfosToKeyFilters(keyFilterInfos: Array<KeyFilterInfo>): Array<KeyFilter> { export function keyFilterInfosToKeyFilters(keyFilterInfos: Array<KeyFilterInfo>): Array<KeyFilter> {
const keyFilters: Array<KeyFilter> = []; const keyFilters: Array<KeyFilter> = [];
for (const keyFilterInfo of keyFilterInfos) { for (const keyFilterInfo of keyFilterInfos) {

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

@ -813,15 +813,16 @@
"alarm-rules": "Alarm rules ({{count}})", "alarm-rules": "Alarm rules ({{count}})",
"add-alarm-rule": "Add alarm rule", "add-alarm-rule": "Add alarm rule",
"edit-alarm-rule": "Edit alarm rule", "edit-alarm-rule": "Edit alarm rule",
"alarm-rule-details": "Alarm rule details",
"alarm-type": "Alarm type", "alarm-type": "Alarm type",
"alarm-type-required": "Alarm type is required.", "alarm-type-required": "Alarm type is required.",
"alarm-type-pattern-hint": "Alarm type pattern, use <code>${metaKeyName}</code> to substitute variables from metadata", "alarm-type-pattern-hint": "Alarm type pattern, use <code>${metaKeyName}</code> to substitute variables from metadata",
"create-alarm-pattern": "Create <b>{{alarmType}}</b> alarm", "create-alarm-pattern": "Create <b>{{alarmType}}</b> alarm",
"create-alarm-rules": "Create alarm rules", "create-alarm-rules": "Create alarm rules",
"no-create-alarm-rules": "No create conditions configured",
"clear-alarm-rule": "Clear alarm rule", "clear-alarm-rule": "Clear alarm rule",
"add-create-alarm-rule": "Add create alarm rule", "no-clear-alarm-rule": "No clear condition configured",
"add-clear-alarm-rule": "Add clear alarm rule", "add-create-alarm-rule": "Add create condition",
"add-clear-alarm-rule": "Add clear condition",
"select-alarm-severity": "Select alarm severity", "select-alarm-severity": "Select alarm severity",
"alarm-severity-required": "Alarm severity is required.", "alarm-severity-required": "Alarm severity is required.",
"condition-duration": "Condition duration", "condition-duration": "Condition duration",
@ -831,6 +832,7 @@
"condition-duration-value-required": "Duration value is required.", "condition-duration-value-required": "Duration value is required.",
"condition-duration-time-unit-required": "Time unit is required.", "condition-duration-time-unit-required": "Time unit is required.",
"advanced-settings": "Advanced settings", "advanced-settings": "Advanced settings",
"alarm-rule-details": "Details",
"propagate-alarm": "Propagate alarm", "propagate-alarm": "Propagate alarm",
"alarm-details": "Alarm details", "alarm-details": "Alarm details",
"alarm-rule-condition": "Alarm rule condition", "alarm-rule-condition": "Alarm rule condition",
@ -1277,6 +1279,8 @@
"filter": "Filter", "filter": "Filter",
"editable": "Editable", "editable": "Editable",
"no-filters-found": "No filters found.", "no-filters-found": "No filters found.",
"no-filter-text": "No filter specified",
"add-filter-prompt": "Please add filter",
"no-filter-matching": "'{{filter}}' not found.", "no-filter-matching": "'{{filter}}' not found.",
"create-new-filter": "Create a new one!", "create-new-filter": "Create a new one!",
"filter-required": "Filter is required.", "filter-required": "Filter is required.",
@ -1295,7 +1299,7 @@
"and": "and", "and": "and",
"or": "or" "or": "or"
}, },
"ignore-case": "Ignore case", "ignore-case": "ignore case",
"value": "Value", "value": "Value",
"remove-filter": "Remove filter", "remove-filter": "Remove filter",
"no-filters": "No filters configured", "no-filters": "No filters configured",

Loading…
Cancel
Save