Filter predicate dynamic value
This commit is contained in:
		
							parent
							
								
									faee8e6bf0
								
							
						
					
					
						commit
						cf6824cf22
					
				@ -44,6 +44,7 @@ import org.thingsboard.server.common.data.query.EntityDataSortOrder;
 | 
			
		||||
import org.thingsboard.server.common.data.query.EntityKey;
 | 
			
		||||
import org.thingsboard.server.common.data.query.EntityKeyType;
 | 
			
		||||
import org.thingsboard.server.common.data.query.EntityListFilter;
 | 
			
		||||
import org.thingsboard.server.common.data.query.FilterPredicateValue;
 | 
			
		||||
import org.thingsboard.server.common.data.query.KeyFilter;
 | 
			
		||||
import org.thingsboard.server.common.data.query.NumericFilterPredicate;
 | 
			
		||||
import org.thingsboard.server.common.data.security.Authority;
 | 
			
		||||
@ -259,7 +260,7 @@ public abstract class BaseEntityQueryControllerTest extends AbstractControllerTe
 | 
			
		||||
        KeyFilter highTemperatureFilter = new KeyFilter();
 | 
			
		||||
        highTemperatureFilter.setKey(new EntityKey(EntityKeyType.ATTRIBUTE, "temperature"));
 | 
			
		||||
        NumericFilterPredicate predicate = new NumericFilterPredicate();
 | 
			
		||||
        predicate.setValue(45);
 | 
			
		||||
        predicate.setValue(FilterPredicateValue.fromDouble(45));
 | 
			
		||||
        predicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER);
 | 
			
		||||
        highTemperatureFilter.setPredicate(predicate);
 | 
			
		||||
        List<KeyFilter> keyFilters = Collections.singletonList(highTemperatureFilter);
 | 
			
		||||
 | 
			
		||||
@ -26,9 +26,9 @@ import java.util.Arrays;
 | 
			
		||||
 | 
			
		||||
@RunWith(ClasspathSuite.class)
 | 
			
		||||
@ClasspathSuite.ClassnameFilters({
 | 
			
		||||
        "org.thingsboard.server.controller.sql.WebsocketApiSqlTest",
 | 
			
		||||
//        "org.thingsboard.server.controller.sql.WebsocketApiSqlTest",
 | 
			
		||||
//        "org.thingsboard.server.controller.sql.EntityQueryControllerSqlTest",
 | 
			
		||||
//        "org.thingsboard.server.controller.sql.*Test",
 | 
			
		||||
        "org.thingsboard.server.controller.sql.*Test",
 | 
			
		||||
        })
 | 
			
		||||
public class ControllerSqlTestSuite {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -21,7 +21,7 @@ import lombok.Data;
 | 
			
		||||
public class BooleanFilterPredicate implements KeyFilterPredicate {
 | 
			
		||||
 | 
			
		||||
    private BooleanOperation operation;
 | 
			
		||||
    private boolean value;
 | 
			
		||||
    private FilterPredicateValue<Boolean> value;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public FilterPredicateType getType() {
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,33 @@
 | 
			
		||||
/**
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
package org.thingsboard.server.common.data.query;
 | 
			
		||||
 | 
			
		||||
import com.fasterxml.jackson.annotation.JsonIgnore;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.Getter;
 | 
			
		||||
 | 
			
		||||
@Data
 | 
			
		||||
public class DynamicValue<T> {
 | 
			
		||||
 | 
			
		||||
    @JsonIgnore
 | 
			
		||||
    private T resolvedValue;
 | 
			
		||||
 | 
			
		||||
    @Getter
 | 
			
		||||
    private final DynamicValueSourceType sourceType;
 | 
			
		||||
    @Getter
 | 
			
		||||
    private final String sourceAttribute;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,22 @@
 | 
			
		||||
/**
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
package org.thingsboard.server.common.data.query;
 | 
			
		||||
 | 
			
		||||
public enum DynamicValueSourceType {
 | 
			
		||||
    CURRENT_TENANT,
 | 
			
		||||
    CURRENT_CUSTOMER,
 | 
			
		||||
    CURRENT_USER
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,63 @@
 | 
			
		||||
/**
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
package org.thingsboard.server.common.data.query;
 | 
			
		||||
 | 
			
		||||
import com.fasterxml.jackson.annotation.JsonCreator;
 | 
			
		||||
import com.fasterxml.jackson.annotation.JsonIgnore;
 | 
			
		||||
import com.fasterxml.jackson.annotation.JsonProperty;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.Getter;
 | 
			
		||||
 | 
			
		||||
@Data
 | 
			
		||||
public class FilterPredicateValue<T> {
 | 
			
		||||
 | 
			
		||||
    @Getter
 | 
			
		||||
    private final T defaultValue;
 | 
			
		||||
    @Getter
 | 
			
		||||
    private final DynamicValue<T> dynamicValue;
 | 
			
		||||
 | 
			
		||||
    public FilterPredicateValue(T defaultValue) {
 | 
			
		||||
        this(defaultValue, null);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @JsonCreator
 | 
			
		||||
    public FilterPredicateValue(@JsonProperty("defaultValue") T defaultValue,
 | 
			
		||||
                                @JsonProperty("dynamicValue") DynamicValue<T> dynamicValue) {
 | 
			
		||||
        this.defaultValue = defaultValue;
 | 
			
		||||
        this.dynamicValue = dynamicValue;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @JsonIgnore
 | 
			
		||||
    public T getValue() {
 | 
			
		||||
        if (this.dynamicValue != null && this.dynamicValue.getResolvedValue() != null) {
 | 
			
		||||
            return this.dynamicValue.getResolvedValue();
 | 
			
		||||
        } else {
 | 
			
		||||
            return defaultValue;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static FilterPredicateValue<Double> fromDouble(double value) {
 | 
			
		||||
        return new FilterPredicateValue<>(value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static FilterPredicateValue<String> fromString(String value) {
 | 
			
		||||
        return new FilterPredicateValue<>(value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static FilterPredicateValue<Boolean> fromBoolean(boolean value) {
 | 
			
		||||
        return new FilterPredicateValue<>(value);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -21,7 +21,7 @@ import lombok.Data;
 | 
			
		||||
public class NumericFilterPredicate implements KeyFilterPredicate {
 | 
			
		||||
 | 
			
		||||
    private NumericOperation operation;
 | 
			
		||||
    private double value;
 | 
			
		||||
    private FilterPredicateValue<Double> value;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public FilterPredicateType getType() {
 | 
			
		||||
 | 
			
		||||
@ -21,7 +21,7 @@ import lombok.Data;
 | 
			
		||||
public class StringFilterPredicate implements KeyFilterPredicate {
 | 
			
		||||
 | 
			
		||||
    private StringOperation operation;
 | 
			
		||||
    private String value;
 | 
			
		||||
    private FilterPredicateValue<String> value;
 | 
			
		||||
    private boolean ignoreCase;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
 | 
			
		||||
@ -440,7 +440,7 @@ public class EntityKeyMapping {
 | 
			
		||||
    private String buildStringPredicateQuery(QueryContext ctx, String field, StringFilterPredicate stringFilterPredicate) {
 | 
			
		||||
        String operationField = field;
 | 
			
		||||
        String paramName = getNextParameterName(field);
 | 
			
		||||
        String value = stringFilterPredicate.getValue();
 | 
			
		||||
        String value = stringFilterPredicate.getValue().getValue();
 | 
			
		||||
        String stringOperationQuery = "";
 | 
			
		||||
        if (stringFilterPredicate.isIgnoreCase()) {
 | 
			
		||||
            value = value.toLowerCase();
 | 
			
		||||
@ -476,7 +476,7 @@ public class EntityKeyMapping {
 | 
			
		||||
 | 
			
		||||
    private String buildNumericPredicateQuery(QueryContext ctx, String field, NumericFilterPredicate numericFilterPredicate) {
 | 
			
		||||
        String paramName = getNextParameterName(field);
 | 
			
		||||
        ctx.addDoubleParameter(paramName, numericFilterPredicate.getValue());
 | 
			
		||||
        ctx.addDoubleParameter(paramName, numericFilterPredicate.getValue().getValue());
 | 
			
		||||
        String numericOperationQuery = "";
 | 
			
		||||
        switch (numericFilterPredicate.getOperation()) {
 | 
			
		||||
            case EQUAL:
 | 
			
		||||
@ -504,7 +504,7 @@ public class EntityKeyMapping {
 | 
			
		||||
    private String buildBooleanPredicateQuery(QueryContext ctx, String field,
 | 
			
		||||
                                              BooleanFilterPredicate booleanFilterPredicate) {
 | 
			
		||||
        String paramName = getNextParameterName(field);
 | 
			
		||||
        ctx.addBooleanParameter(paramName, booleanFilterPredicate.isValue());
 | 
			
		||||
        ctx.addBooleanParameter(paramName, booleanFilterPredicate.getValue().getValue());
 | 
			
		||||
        String booleanOperationQuery = "";
 | 
			
		||||
        switch (booleanFilterPredicate.getOperation()) {
 | 
			
		||||
            case EQUAL:
 | 
			
		||||
 | 
			
		||||
@ -49,6 +49,7 @@ import org.thingsboard.server.common.data.query.EntityDataSortOrder;
 | 
			
		||||
import org.thingsboard.server.common.data.query.EntityKey;
 | 
			
		||||
import org.thingsboard.server.common.data.query.EntityKeyType;
 | 
			
		||||
import org.thingsboard.server.common.data.query.EntityListFilter;
 | 
			
		||||
import org.thingsboard.server.common.data.query.FilterPredicateValue;
 | 
			
		||||
import org.thingsboard.server.common.data.query.KeyFilter;
 | 
			
		||||
import org.thingsboard.server.common.data.query.NumericFilterPredicate;
 | 
			
		||||
import org.thingsboard.server.common.data.query.RelationsQueryFilter;
 | 
			
		||||
@ -239,7 +240,7 @@ public abstract class BaseEntityServiceTest extends AbstractServiceTest {
 | 
			
		||||
        KeyFilter highTemperatureFilter = new KeyFilter();
 | 
			
		||||
        highTemperatureFilter.setKey(new EntityKey(EntityKeyType.ATTRIBUTE, "temperature"));
 | 
			
		||||
        NumericFilterPredicate predicate = new NumericFilterPredicate();
 | 
			
		||||
        predicate.setValue(45);
 | 
			
		||||
        predicate.setValue(FilterPredicateValue.fromDouble(45));
 | 
			
		||||
        predicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER);
 | 
			
		||||
        highTemperatureFilter.setPredicate(predicate);
 | 
			
		||||
        List<KeyFilter> keyFilters = Collections.singletonList(highTemperatureFilter);
 | 
			
		||||
@ -311,7 +312,7 @@ public abstract class BaseEntityServiceTest extends AbstractServiceTest {
 | 
			
		||||
        KeyFilter highTemperatureFilter = new KeyFilter();
 | 
			
		||||
        highTemperatureFilter.setKey(new EntityKey(EntityKeyType.ATTRIBUTE, "temperature"));
 | 
			
		||||
        NumericFilterPredicate predicate = new NumericFilterPredicate();
 | 
			
		||||
        predicate.setValue(45);
 | 
			
		||||
        predicate.setValue(FilterPredicateValue.fromDouble(45));
 | 
			
		||||
        predicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER);
 | 
			
		||||
        highTemperatureFilter.setPredicate(predicate);
 | 
			
		||||
        List<KeyFilter> keyFilters = Collections.singletonList(highTemperatureFilter);
 | 
			
		||||
@ -382,7 +383,7 @@ public abstract class BaseEntityServiceTest extends AbstractServiceTest {
 | 
			
		||||
        KeyFilter highTemperatureFilter = new KeyFilter();
 | 
			
		||||
        highTemperatureFilter.setKey(new EntityKey(EntityKeyType.ATTRIBUTE, "consumption"));
 | 
			
		||||
        NumericFilterPredicate predicate = new NumericFilterPredicate();
 | 
			
		||||
        predicate.setValue(50);
 | 
			
		||||
        predicate.setValue(FilterPredicateValue.fromDouble(50));
 | 
			
		||||
        predicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER);
 | 
			
		||||
        highTemperatureFilter.setPredicate(predicate);
 | 
			
		||||
        List<KeyFilter> keyFilters = Collections.singletonList(highTemperatureFilter);
 | 
			
		||||
@ -584,7 +585,7 @@ public abstract class BaseEntityServiceTest extends AbstractServiceTest {
 | 
			
		||||
        KeyFilter highTemperatureFilter = new KeyFilter();
 | 
			
		||||
        highTemperatureFilter.setKey(new EntityKey(EntityKeyType.ATTRIBUTE, "temperature"));
 | 
			
		||||
        NumericFilterPredicate predicate = new NumericFilterPredicate();
 | 
			
		||||
        predicate.setValue(45);
 | 
			
		||||
        predicate.setValue(FilterPredicateValue.fromDouble(45));
 | 
			
		||||
        predicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER);
 | 
			
		||||
        highTemperatureFilter.setPredicate(predicate);
 | 
			
		||||
        List<KeyFilter> keyFilters = Collections.singletonList(highTemperatureFilter);
 | 
			
		||||
 | 
			
		||||
@ -396,7 +396,9 @@ export class EntityService {
 | 
			
		||||
            type: FilterPredicateType.STRING,
 | 
			
		||||
            operation: StringOperation.STARTS_WITH,
 | 
			
		||||
            ignoreCase: true,
 | 
			
		||||
            value: searchText
 | 
			
		||||
            value: {
 | 
			
		||||
              defaultValue: searchText
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      ] : null
 | 
			
		||||
 | 
			
		||||
@ -15,7 +15,7 @@
 | 
			
		||||
    limitations under the License.
 | 
			
		||||
 | 
			
		||||
-->
 | 
			
		||||
<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px" [formGroup]="booleanFilterPredicateFormGroup">
 | 
			
		||||
<div fxFlex fxLayout="row" fxLayoutAlign="start start" fxLayoutGap="8px" [formGroup]="booleanFilterPredicateFormGroup">
 | 
			
		||||
  <mat-form-field floatLabel="always" hideRequiredMarker fxFlex="40" class="mat-block">
 | 
			
		||||
    <mat-label></mat-label>
 | 
			
		||||
    <mat-select required formControlName="operation" placeholder="{{'filter.operation.operation' | translate}}">
 | 
			
		||||
@ -24,7 +24,8 @@
 | 
			
		||||
      </mat-option>
 | 
			
		||||
    </mat-select>
 | 
			
		||||
  </mat-form-field>
 | 
			
		||||
  <mat-checkbox fxFlex="60" formControlName="value">
 | 
			
		||||
    {{ (booleanFilterPredicateFormGroup.get('value').value ? 'value.true' : 'value.false') | translate }}
 | 
			
		||||
  </mat-checkbox>
 | 
			
		||||
  <tb-filter-predicate-value fxFlex="60"
 | 
			
		||||
                             [valueType]="valueTypeEnum.BOOLEAN"
 | 
			
		||||
                             formControlName="value">
 | 
			
		||||
  </tb-filter-predicate-value>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
@ -18,10 +18,10 @@ import { Component, forwardRef, Input, OnInit } from '@angular/core';
 | 
			
		||||
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
 | 
			
		||||
import {
 | 
			
		||||
  BooleanFilterPredicate,
 | 
			
		||||
  BooleanOperation, booleanOperationTranslationMap,
 | 
			
		||||
  BooleanOperation,
 | 
			
		||||
  booleanOperationTranslationMap, EntityKeyValueType,
 | 
			
		||||
  FilterPredicateType
 | 
			
		||||
} from '@shared/models/query/query.models';
 | 
			
		||||
import { isDefined } from '@core/utils';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'tb-boolean-filter-predicate',
 | 
			
		||||
@ -39,6 +39,8 @@ export class BooleanFilterPredicateComponent implements ControlValueAccessor, On
 | 
			
		||||
 | 
			
		||||
  @Input() disabled: boolean;
 | 
			
		||||
 | 
			
		||||
  valueTypeEnum = EntityKeyValueType;
 | 
			
		||||
 | 
			
		||||
  booleanFilterPredicateFormGroup: FormGroup;
 | 
			
		||||
 | 
			
		||||
  booleanOperations = Object.keys(BooleanOperation);
 | 
			
		||||
@ -53,7 +55,7 @@ export class BooleanFilterPredicateComponent implements ControlValueAccessor, On
 | 
			
		||||
  ngOnInit(): void {
 | 
			
		||||
    this.booleanFilterPredicateFormGroup = this.fb.group({
 | 
			
		||||
      operation: [BooleanOperation.EQUAL, [Validators.required]],
 | 
			
		||||
      value: [false]
 | 
			
		||||
      value: [null, [Validators.required]]
 | 
			
		||||
    });
 | 
			
		||||
    this.booleanFilterPredicateFormGroup.valueChanges.subscribe(() => {
 | 
			
		||||
      this.updateModel();
 | 
			
		||||
@ -78,16 +80,13 @@ export class BooleanFilterPredicateComponent implements ControlValueAccessor, On
 | 
			
		||||
 | 
			
		||||
  writeValue(predicate: BooleanFilterPredicate): void {
 | 
			
		||||
    this.booleanFilterPredicateFormGroup.get('operation').patchValue(predicate.operation, {emitEvent: false});
 | 
			
		||||
    this.booleanFilterPredicateFormGroup.get('value').patchValue(isDefined(predicate.value) ? predicate.value : false, {emitEvent: false});
 | 
			
		||||
    this.booleanFilterPredicateFormGroup.get('value').patchValue(predicate.value, {emitEvent: false});
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private updateModel() {
 | 
			
		||||
    let predicate: BooleanFilterPredicate = null;
 | 
			
		||||
    if (this.booleanFilterPredicateFormGroup.valid) {
 | 
			
		||||
      predicate = this.booleanFilterPredicateFormGroup.getRawValue();
 | 
			
		||||
      if (!isDefined(predicate.value)) {
 | 
			
		||||
        predicate.value = false;
 | 
			
		||||
      }
 | 
			
		||||
      predicate.type = FilterPredicateType.BOOLEAN;
 | 
			
		||||
    }
 | 
			
		||||
    this.propagateChange(predicate);
 | 
			
		||||
 | 
			
		||||
@ -39,7 +39,7 @@
 | 
			
		||||
    </div>
 | 
			
		||||
    <mat-divider></mat-divider>
 | 
			
		||||
    <div class="predicate-list">
 | 
			
		||||
      <div fxLayout="row" fxLayoutAlign="start center" style="height: 40px;"
 | 
			
		||||
      <div fxLayout="row" fxLayoutAlign="start center" style="height: 45px;"
 | 
			
		||||
           formArrayName="predicates"
 | 
			
		||||
           *ngFor="let predicateControl of predicatesFormArray().controls; let $index = index">
 | 
			
		||||
        <div fxFlex="8" fxLayout="row" fxLayoutAlign="center" class="filters-operation">
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,48 @@
 | 
			
		||||
<!--
 | 
			
		||||
 | 
			
		||||
    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 fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px" [formGroup]="filterPredicateValueFormGroup">
 | 
			
		||||
  <div fxFlex fxLayout="column">
 | 
			
		||||
    <div fxFlex fxLayout="column" [ngSwitch]="valueType">
 | 
			
		||||
      <ng-template [ngSwitchCase]="valueTypeEnum.STRING">
 | 
			
		||||
        <mat-form-field floatLabel="always" hideRequiredMarker fxFlex class="mat-block">
 | 
			
		||||
          <mat-label></mat-label>
 | 
			
		||||
          <input matInput formControlName="defaultValue" placeholder="{{'filter.value' | translate}}">
 | 
			
		||||
        </mat-form-field>
 | 
			
		||||
      </ng-template>
 | 
			
		||||
      <ng-template [ngSwitchCase]="valueTypeEnum.NUMERIC">
 | 
			
		||||
        <mat-form-field floatLabel="always" hideRequiredMarker fxFlex class="mat-block">
 | 
			
		||||
          <mat-label></mat-label>
 | 
			
		||||
          <input required type="number" matInput formControlName="defaultValue"
 | 
			
		||||
                 placeholder="{{'filter.value' | translate}}">
 | 
			
		||||
        </mat-form-field>
 | 
			
		||||
      </ng-template>
 | 
			
		||||
      <ng-template [ngSwitchCase]="valueTypeEnum.DATE_TIME">
 | 
			
		||||
        <tb-datetime fxFlex formControlName="defaultValue"
 | 
			
		||||
                     dateText="filter.date"
 | 
			
		||||
                     timeText="filter.time"
 | 
			
		||||
                     required [showLabel]="false"></tb-datetime>
 | 
			
		||||
      </ng-template>
 | 
			
		||||
      <ng-template [ngSwitchCase]="valueTypeEnum.BOOLEAN">
 | 
			
		||||
        <mat-checkbox fxFlex formControlName="defaultValue">
 | 
			
		||||
          {{ (filterPredicateValueFormGroup.get('defaultValue').value ? 'value.true' : 'value.false') | translate }}
 | 
			
		||||
        </mat-checkbox>
 | 
			
		||||
      </ng-template>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="tb-hint">Default value</div>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
@ -0,0 +1,126 @@
 | 
			
		||||
///
 | 
			
		||||
/// 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,
 | 
			
		||||
  FormGroup,
 | 
			
		||||
  NG_VALUE_ACCESSOR,
 | 
			
		||||
  ValidatorFn,
 | 
			
		||||
  Validators
 | 
			
		||||
} from '@angular/forms';
 | 
			
		||||
import { EntityKeyValueType, FilterPredicateValue } from '@shared/models/query/query.models';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'tb-filter-predicate-value',
 | 
			
		||||
  templateUrl: './filter-predicate-value.component.html',
 | 
			
		||||
  styleUrls: ['./filter-predicate.scss'],
 | 
			
		||||
  providers: [
 | 
			
		||||
    {
 | 
			
		||||
      provide: NG_VALUE_ACCESSOR,
 | 
			
		||||
      useExisting: forwardRef(() => FilterPredicateValueComponent),
 | 
			
		||||
      multi: true
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
export class FilterPredicateValueComponent implements ControlValueAccessor, OnInit {
 | 
			
		||||
 | 
			
		||||
  @Input() disabled: boolean;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  valueType: EntityKeyValueType;
 | 
			
		||||
 | 
			
		||||
  valueTypeEnum = EntityKeyValueType;
 | 
			
		||||
 | 
			
		||||
  filterPredicateValueFormGroup: FormGroup;
 | 
			
		||||
 | 
			
		||||
  private propagateChange = null;
 | 
			
		||||
 | 
			
		||||
  constructor(private fb: FormBuilder) {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ngOnInit(): void {
 | 
			
		||||
    let defaultValue: string | number | boolean;
 | 
			
		||||
    let defaultValueValidators: ValidatorFn[];
 | 
			
		||||
    switch (this.valueType) {
 | 
			
		||||
      case EntityKeyValueType.STRING:
 | 
			
		||||
        defaultValue = '';
 | 
			
		||||
        defaultValueValidators = [];
 | 
			
		||||
        break;
 | 
			
		||||
      case EntityKeyValueType.NUMERIC:
 | 
			
		||||
        defaultValue = 0;
 | 
			
		||||
        defaultValueValidators = [Validators.required];
 | 
			
		||||
        break;
 | 
			
		||||
      case EntityKeyValueType.BOOLEAN:
 | 
			
		||||
        defaultValue = false;
 | 
			
		||||
        defaultValueValidators = [];
 | 
			
		||||
        break;
 | 
			
		||||
      case EntityKeyValueType.DATE_TIME:
 | 
			
		||||
        defaultValue = Date.now();
 | 
			
		||||
        defaultValueValidators = [Validators.required];
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    this.filterPredicateValueFormGroup = this.fb.group({
 | 
			
		||||
      defaultValue: [defaultValue, defaultValueValidators],
 | 
			
		||||
      dynamicValue: this.fb.group(
 | 
			
		||||
        {
 | 
			
		||||
          sourceType: [null],
 | 
			
		||||
          sourceAttribute: [null]
 | 
			
		||||
        }
 | 
			
		||||
      )
 | 
			
		||||
    });
 | 
			
		||||
    this.filterPredicateValueFormGroup.valueChanges.subscribe(() => {
 | 
			
		||||
      this.updateModel();
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  registerOnChange(fn: any): void {
 | 
			
		||||
    this.propagateChange = fn;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  registerOnTouched(fn: any): void {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setDisabledState?(isDisabled: boolean): void {
 | 
			
		||||
    this.disabled = isDisabled;
 | 
			
		||||
    if (this.disabled) {
 | 
			
		||||
      this.filterPredicateValueFormGroup.disable({emitEvent: false});
 | 
			
		||||
    } else {
 | 
			
		||||
      this.filterPredicateValueFormGroup.enable({emitEvent: false});
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  writeValue(predicateValue: FilterPredicateValue<string | number | boolean>): void {
 | 
			
		||||
    this.filterPredicateValueFormGroup.get('defaultValue').patchValue(predicateValue.defaultValue, {emitEvent: false});
 | 
			
		||||
    this.filterPredicateValueFormGroup.get('dynamicValue').patchValue(predicateValue.dynamicValue ?
 | 
			
		||||
      predicateValue.dynamicValue : { sourceType: null, sourceAttribute: null }, {emitEvent: false});
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private updateModel() {
 | 
			
		||||
    let predicateValue: FilterPredicateValue<string | number | boolean> = null;
 | 
			
		||||
    if (this.filterPredicateValueFormGroup.valid) {
 | 
			
		||||
      predicateValue = this.filterPredicateValueFormGroup.getRawValue();
 | 
			
		||||
      if (predicateValue.dynamicValue) {
 | 
			
		||||
        if (!predicateValue.dynamicValue.sourceType || !predicateValue.dynamicValue.sourceAttribute) {
 | 
			
		||||
          predicateValue.dynamicValue = null;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    this.propagateChange(predicateValue);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -13,6 +13,13 @@
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
:host {
 | 
			
		||||
  .tb-hint {
 | 
			
		||||
    padding-bottom: 0;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
:host ::ng-deep {
 | 
			
		||||
  mat-form-field {
 | 
			
		||||
    .mat-form-field-wrapper {
 | 
			
		||||
 | 
			
		||||
@ -15,7 +15,7 @@
 | 
			
		||||
    limitations under the License.
 | 
			
		||||
 | 
			
		||||
-->
 | 
			
		||||
<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px" [formGroup]="numericFilterPredicateFormGroup">
 | 
			
		||||
<div fxFlex fxLayout="row" fxLayoutAlign="start start" fxLayoutGap="8px" [formGroup]="numericFilterPredicateFormGroup">
 | 
			
		||||
  <mat-form-field floatLabel="always" hideRequiredMarker fxFlex="40" class="mat-block">
 | 
			
		||||
    <mat-label></mat-label>
 | 
			
		||||
    <mat-select required formControlName="operation" placeholder="{{'filter.operation.operation' | translate}}">
 | 
			
		||||
@ -24,19 +24,8 @@
 | 
			
		||||
      </mat-option>
 | 
			
		||||
    </mat-select>
 | 
			
		||||
  </mat-form-field>
 | 
			
		||||
  <div fxFlex="60" fxLayout="column" [ngSwitch]="valueType">
 | 
			
		||||
    <ng-template [ngSwitchCase]="valueTypeEnum.NUMERIC">
 | 
			
		||||
      <mat-form-field floatLabel="always" hideRequiredMarker fxFlex class="mat-block">
 | 
			
		||||
        <mat-label></mat-label>
 | 
			
		||||
        <input required type="number" matInput formControlName="value"
 | 
			
		||||
               placeholder="{{'filter.value' | translate}}">
 | 
			
		||||
      </mat-form-field>
 | 
			
		||||
    </ng-template>
 | 
			
		||||
    <ng-template [ngSwitchCase]="valueTypeEnum.DATE_TIME">
 | 
			
		||||
      <tb-datetime fxFlex formControlName="value"
 | 
			
		||||
                   dateText="filter.date"
 | 
			
		||||
                   timeText="filter.time"
 | 
			
		||||
                   required [showLabel]="false"></tb-datetime>
 | 
			
		||||
    </ng-template>
 | 
			
		||||
  </div>
 | 
			
		||||
  <tb-filter-predicate-value fxFlex="60"
 | 
			
		||||
                             [valueType]="valueType"
 | 
			
		||||
                             formControlName="value">
 | 
			
		||||
  </tb-filter-predicate-value>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
@ -18,9 +18,11 @@ import { Component, forwardRef, Input, OnInit } from '@angular/core';
 | 
			
		||||
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
 | 
			
		||||
import {
 | 
			
		||||
  EntityKeyValueType,
 | 
			
		||||
  FilterPredicateType, NumericFilterPredicate, NumericOperation, numericOperationTranslationMap,
 | 
			
		||||
  FilterPredicateType,
 | 
			
		||||
  NumericFilterPredicate,
 | 
			
		||||
  NumericOperation,
 | 
			
		||||
  numericOperationTranslationMap,
 | 
			
		||||
} from '@shared/models/query/query.models';
 | 
			
		||||
import { isDefined } from '@core/utils';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'tb-numeric-filter-predicate',
 | 
			
		||||
@ -56,7 +58,7 @@ export class NumericFilterPredicateComponent implements ControlValueAccessor, On
 | 
			
		||||
  ngOnInit(): void {
 | 
			
		||||
    this.numericFilterPredicateFormGroup = this.fb.group({
 | 
			
		||||
      operation: [NumericOperation.EQUAL, [Validators.required]],
 | 
			
		||||
      value: [0, [Validators.required]]
 | 
			
		||||
      value: [null, [Validators.required]]
 | 
			
		||||
    });
 | 
			
		||||
    this.numericFilterPredicateFormGroup.valueChanges.subscribe(() => {
 | 
			
		||||
      this.updateModel();
 | 
			
		||||
@ -81,16 +83,13 @@ export class NumericFilterPredicateComponent implements ControlValueAccessor, On
 | 
			
		||||
 | 
			
		||||
  writeValue(predicate: NumericFilterPredicate): void {
 | 
			
		||||
    this.numericFilterPredicateFormGroup.get('operation').patchValue(predicate.operation, {emitEvent: false});
 | 
			
		||||
    this.numericFilterPredicateFormGroup.get('value').patchValue(isDefined(predicate.value) ? predicate.value : 0, {emitEvent: false});
 | 
			
		||||
    this.numericFilterPredicateFormGroup.get('value').patchValue(predicate.value, {emitEvent: false});
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private updateModel() {
 | 
			
		||||
    let predicate: NumericFilterPredicate = null;
 | 
			
		||||
    if (this.numericFilterPredicateFormGroup.valid) {
 | 
			
		||||
      predicate = this.numericFilterPredicateFormGroup.getRawValue();
 | 
			
		||||
      if (!predicate.value) {
 | 
			
		||||
        predicate.value = 0;
 | 
			
		||||
      }
 | 
			
		||||
      predicate.type = FilterPredicateType.NUMERIC;
 | 
			
		||||
    }
 | 
			
		||||
    this.propagateChange(predicate);
 | 
			
		||||
 | 
			
		||||
@ -15,7 +15,7 @@
 | 
			
		||||
    limitations under the License.
 | 
			
		||||
 | 
			
		||||
-->
 | 
			
		||||
<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px" [formGroup]="stringFilterPredicateFormGroup">
 | 
			
		||||
<div fxFlex fxLayout="row" fxLayoutAlign="start start" fxLayoutGap="8px" [formGroup]="stringFilterPredicateFormGroup">
 | 
			
		||||
  <div fxFlex="40" fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
 | 
			
		||||
    <mat-form-field floatLabel="always" hideRequiredMarker fxFlex class="mat-block">
 | 
			
		||||
      <mat-label></mat-label>
 | 
			
		||||
@ -28,8 +28,8 @@
 | 
			
		||||
    <mat-checkbox fxLayout="row" fxLayoutAlign="center" formControlName="ignoreCase" style="min-width: 70px;">
 | 
			
		||||
    </mat-checkbox>
 | 
			
		||||
  </div>
 | 
			
		||||
  <mat-form-field floatLabel="always" hideRequiredMarker fxFlex="60" class="mat-block">
 | 
			
		||||
    <mat-label></mat-label>
 | 
			
		||||
    <input matInput formControlName="value" placeholder="{{'filter.value' | translate}}">
 | 
			
		||||
  </mat-form-field>
 | 
			
		||||
  <tb-filter-predicate-value fxFlex="60"
 | 
			
		||||
                             [valueType]="valueTypeEnum.STRING"
 | 
			
		||||
                             formControlName="value">
 | 
			
		||||
  </tb-filter-predicate-value>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
@ -17,6 +17,7 @@
 | 
			
		||||
import { Component, forwardRef, Input, OnInit } from '@angular/core';
 | 
			
		||||
import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
 | 
			
		||||
import {
 | 
			
		||||
  EntityKeyValueType,
 | 
			
		||||
  FilterPredicateType,
 | 
			
		||||
  StringFilterPredicate,
 | 
			
		||||
  StringOperation,
 | 
			
		||||
@ -39,6 +40,8 @@ export class StringFilterPredicateComponent implements ControlValueAccessor, OnI
 | 
			
		||||
 | 
			
		||||
  @Input() disabled: boolean;
 | 
			
		||||
 | 
			
		||||
  valueTypeEnum = EntityKeyValueType;
 | 
			
		||||
 | 
			
		||||
  stringFilterPredicateFormGroup: FormGroup;
 | 
			
		||||
 | 
			
		||||
  stringOperations = Object.keys(StringOperation);
 | 
			
		||||
@ -53,7 +56,7 @@ export class StringFilterPredicateComponent implements ControlValueAccessor, OnI
 | 
			
		||||
  ngOnInit(): void {
 | 
			
		||||
    this.stringFilterPredicateFormGroup = this.fb.group({
 | 
			
		||||
      operation: [StringOperation.STARTS_WITH, [Validators.required]],
 | 
			
		||||
      value: [''],
 | 
			
		||||
      value: [null, [Validators.required]],
 | 
			
		||||
      ignoreCase: [false]
 | 
			
		||||
    });
 | 
			
		||||
    this.stringFilterPredicateFormGroup.valueChanges.subscribe(() => {
 | 
			
		||||
@ -79,7 +82,7 @@ export class StringFilterPredicateComponent implements ControlValueAccessor, OnI
 | 
			
		||||
 | 
			
		||||
  writeValue(predicate: StringFilterPredicate): void {
 | 
			
		||||
    this.stringFilterPredicateFormGroup.get('operation').patchValue(predicate.operation, {emitEvent: false});
 | 
			
		||||
    this.stringFilterPredicateFormGroup.get('value').patchValue(predicate.value ? predicate.value : '', {emitEvent: false});
 | 
			
		||||
    this.stringFilterPredicateFormGroup.get('value').patchValue(predicate.value, {emitEvent: false});
 | 
			
		||||
    this.stringFilterPredicateFormGroup.get('ignoreCase').patchValue(predicate.ignoreCase, {emitEvent: false});
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -87,9 +90,6 @@ export class StringFilterPredicateComponent implements ControlValueAccessor, OnI
 | 
			
		||||
    let predicate: StringFilterPredicate = null;
 | 
			
		||||
    if (this.stringFilterPredicateFormGroup.valid) {
 | 
			
		||||
      predicate = this.stringFilterPredicateFormGroup.getRawValue();
 | 
			
		||||
      if (!predicate.value) {
 | 
			
		||||
        predicate.value = '';
 | 
			
		||||
      }
 | 
			
		||||
      predicate.type = FilterPredicateType.STRING;
 | 
			
		||||
    }
 | 
			
		||||
    this.propagateChange(predicate);
 | 
			
		||||
 | 
			
		||||
@ -84,12 +84,12 @@ export class UserFilterDialogComponent extends DialogComponent<UserFilterDialogC
 | 
			
		||||
    const userInputControl = this.fb.group({
 | 
			
		||||
      label: [userInput.label],
 | 
			
		||||
      valueType: [userInput.valueType],
 | 
			
		||||
      value: [(userInput.info.keyFilterPredicate as any).value,
 | 
			
		||||
      value: [(userInput.info.keyFilterPredicate as any).value.defaultValue,
 | 
			
		||||
        userInput.valueType === EntityKeyValueType.NUMERIC ||
 | 
			
		||||
        userInput.valueType === EntityKeyValueType.DATE_TIME  ? [Validators.required] : []]
 | 
			
		||||
    });
 | 
			
		||||
    userInputControl.get('value').valueChanges.subscribe(value => {
 | 
			
		||||
      (userInput.info.keyFilterPredicate as any).value = value;
 | 
			
		||||
      (userInput.info.keyFilterPredicate as any).value.defaultValue = value;
 | 
			
		||||
    });
 | 
			
		||||
    return userInputControl;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -83,6 +83,7 @@ import { FiltersEditPanelComponent } from '@home/components/filter/filters-edit-
 | 
			
		||||
import { UserFilterDialogComponent } from '@home/components/filter/user-filter-dialog.component';
 | 
			
		||||
import { FilterUserInfoComponent } from './filter/filter-user-info.component';
 | 
			
		||||
import { FilterUserInfoDialogComponent } from './filter/filter-user-info-dialog.component';
 | 
			
		||||
import { FilterPredicateValueComponent } from './filter/filter-predicate-value.component';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  declarations:
 | 
			
		||||
@ -148,7 +149,8 @@ import { FilterUserInfoDialogComponent } from './filter/filter-user-info-dialog.
 | 
			
		||||
      FiltersEditPanelComponent,
 | 
			
		||||
      UserFilterDialogComponent,
 | 
			
		||||
      FilterUserInfoComponent,
 | 
			
		||||
      FilterUserInfoDialogComponent
 | 
			
		||||
      FilterUserInfoDialogComponent,
 | 
			
		||||
      FilterPredicateValueComponent
 | 
			
		||||
    ],
 | 
			
		||||
  imports: [
 | 
			
		||||
    CommonModule,
 | 
			
		||||
 | 
			
		||||
@ -138,16 +138,22 @@ export function createDefaultFilterPredicate(valueType: EntityKeyValueType, comp
 | 
			
		||||
  switch (predicate.type) {
 | 
			
		||||
    case FilterPredicateType.STRING:
 | 
			
		||||
      predicate.operation = StringOperation.STARTS_WITH;
 | 
			
		||||
      predicate.value = '';
 | 
			
		||||
      predicate.value = {
 | 
			
		||||
        defaultValue: ''
 | 
			
		||||
      };
 | 
			
		||||
      predicate.ignoreCase = false;
 | 
			
		||||
      break;
 | 
			
		||||
    case FilterPredicateType.NUMERIC:
 | 
			
		||||
      predicate.operation = NumericOperation.EQUAL;
 | 
			
		||||
      predicate.value = valueType === EntityKeyValueType.DATE_TIME ? Date.now() : 0;
 | 
			
		||||
      predicate.value = {
 | 
			
		||||
        defaultValue: valueType === EntityKeyValueType.DATE_TIME ? Date.now() : 0
 | 
			
		||||
      };
 | 
			
		||||
      break;
 | 
			
		||||
    case FilterPredicateType.BOOLEAN:
 | 
			
		||||
      predicate.operation = BooleanOperation.EQUAL;
 | 
			
		||||
      predicate.value = false;
 | 
			
		||||
      predicate.value = {
 | 
			
		||||
        defaultValue: false
 | 
			
		||||
      };
 | 
			
		||||
      break;
 | 
			
		||||
    case FilterPredicateType.COMPLEX:
 | 
			
		||||
      predicate.operation = ComplexOperation.AND;
 | 
			
		||||
@ -228,23 +234,47 @@ export const complexOperationTranslationMap = new Map<ComplexOperation, string>(
 | 
			
		||||
  ]
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
export enum DynamicValueSourceType {
 | 
			
		||||
  CURRENT_TENANT = 'CURRENT_TENANT',
 | 
			
		||||
  CURRENT_CUSTOMER = 'CURRENT_CUSTOMER',
 | 
			
		||||
  CURRENT_USER = 'CURRENT_USER'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const dynamicValueSourceTypeTranslationMap = new Map<DynamicValueSourceType, string>(
 | 
			
		||||
  [
 | 
			
		||||
    [DynamicValueSourceType.CURRENT_TENANT, 'filter.current-tenant'],
 | 
			
		||||
    [DynamicValueSourceType.CURRENT_CUSTOMER, 'filter.current-customer'],
 | 
			
		||||
    [DynamicValueSourceType.CURRENT_USER, 'filter.current-user']
 | 
			
		||||
  ]
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
export interface DynamicValue<T> {
 | 
			
		||||
  sourceType: DynamicValueSourceType;
 | 
			
		||||
  sourceAttribute: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface FilterPredicateValue<T> {
 | 
			
		||||
  defaultValue: T;
 | 
			
		||||
  dynamicValue?: DynamicValue<T>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface StringFilterPredicate {
 | 
			
		||||
  type: FilterPredicateType.STRING,
 | 
			
		||||
  operation: StringOperation;
 | 
			
		||||
  value: string;
 | 
			
		||||
  value: FilterPredicateValue<string>;
 | 
			
		||||
  ignoreCase: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface NumericFilterPredicate {
 | 
			
		||||
  type: FilterPredicateType.NUMERIC,
 | 
			
		||||
  operation: NumericOperation;
 | 
			
		||||
  value: number;
 | 
			
		||||
  value: FilterPredicateValue<number>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface BooleanFilterPredicate {
 | 
			
		||||
  type: FilterPredicateType.BOOLEAN,
 | 
			
		||||
  operation: BooleanOperation;
 | 
			
		||||
  value: boolean;
 | 
			
		||||
  value: FilterPredicateValue<boolean>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface BaseComplexFilterPredicate<T extends KeyFilterPredicate | KeyFilterPredicateInfo> {
 | 
			
		||||
 | 
			
		||||
@ -1227,7 +1227,10 @@
 | 
			
		||||
         "remove-key-filter": "Remove key filter",
 | 
			
		||||
         "edit-key-filter": "Edit key filter",
 | 
			
		||||
         "date": "Date",
 | 
			
		||||
         "time": "Time"
 | 
			
		||||
         "time": "Time",
 | 
			
		||||
         "current-tenant": "Current tenant",
 | 
			
		||||
         "current-customer": "Current customer",
 | 
			
		||||
         "current-user": "Current user"
 | 
			
		||||
    },
 | 
			
		||||
    "fullscreen": {
 | 
			
		||||
        "expand": "Expand to fullscreen",
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user