Browse Source

Merge branch 'feature/entity-data-query' of github.com:thingsboard/thingsboard into feature/entity-data-query

pull/3053/head
Andrii Shvaika 6 years ago
parent
commit
39287c8273
  1. 3
      application/src/test/java/org/thingsboard/server/controller/BaseEntityQueryControllerTest.java
  2. 4
      application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java
  3. 2
      common/data/src/main/java/org/thingsboard/server/common/data/query/BooleanFilterPredicate.java
  4. 33
      common/data/src/main/java/org/thingsboard/server/common/data/query/DynamicValue.java
  5. 22
      common/data/src/main/java/org/thingsboard/server/common/data/query/DynamicValueSourceType.java
  6. 71
      common/data/src/main/java/org/thingsboard/server/common/data/query/FilterPredicateValue.java
  7. 2
      common/data/src/main/java/org/thingsboard/server/common/data/query/NumericFilterPredicate.java
  8. 2
      common/data/src/main/java/org/thingsboard/server/common/data/query/StringFilterPredicate.java
  9. 8
      dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java
  10. 9
      dao/src/test/java/org/thingsboard/server/dao/service/BaseEntityServiceTest.java
  11. 4
      ui-ngx/package-lock.json
  12. 4
      ui-ngx/src/app/core/http/entity.service.ts
  13. 9
      ui-ngx/src/app/modules/home/components/filter/boolean-filter-predicate.component.html
  14. 13
      ui-ngx/src/app/modules/home/components/filter/boolean-filter-predicate.component.ts
  15. 2
      ui-ngx/src/app/modules/home/components/filter/complex-filter-predicate-dialog.component.html
  16. 2
      ui-ngx/src/app/modules/home/components/filter/filter-predicate-list.component.html
  17. 82
      ui-ngx/src/app/modules/home/components/filter/filter-predicate-value.component.html
  18. 146
      ui-ngx/src/app/modules/home/components/filter/filter-predicate-value.component.ts
  19. 7
      ui-ngx/src/app/modules/home/components/filter/filter-predicate.scss
  20. 4
      ui-ngx/src/app/modules/home/components/filter/filters-edit-panel.component.html
  21. 2
      ui-ngx/src/app/modules/home/components/filter/key-filter-dialog.component.html
  22. 21
      ui-ngx/src/app/modules/home/components/filter/numeric-filter-predicate.component.html
  23. 13
      ui-ngx/src/app/modules/home/components/filter/numeric-filter-predicate.component.ts
  24. 10
      ui-ngx/src/app/modules/home/components/filter/string-filter-predicate.component.html
  25. 10
      ui-ngx/src/app/modules/home/components/filter/string-filter-predicate.component.ts
  26. 11
      ui-ngx/src/app/modules/home/components/filter/user-filter-dialog.component.ts
  27. 4
      ui-ngx/src/app/modules/home/components/home-components.module.ts
  28. 43
      ui-ngx/src/app/shared/models/query/query.models.ts
  29. 11
      ui-ngx/src/assets/locale/locale.constant-en_US.json

3
application/src/test/java/org/thingsboard/server/controller/BaseEntityQueryControllerTest.java

@ -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.EntityKey;
import org.thingsboard.server.common.data.query.EntityKeyType; import org.thingsboard.server.common.data.query.EntityKeyType;
import org.thingsboard.server.common.data.query.EntityListFilter; 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.KeyFilter;
import org.thingsboard.server.common.data.query.NumericFilterPredicate; import org.thingsboard.server.common.data.query.NumericFilterPredicate;
import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.data.security.Authority;
@ -259,7 +260,7 @@ public abstract class BaseEntityQueryControllerTest extends AbstractControllerTe
KeyFilter highTemperatureFilter = new KeyFilter(); KeyFilter highTemperatureFilter = new KeyFilter();
highTemperatureFilter.setKey(new EntityKey(EntityKeyType.ATTRIBUTE, "temperature")); highTemperatureFilter.setKey(new EntityKey(EntityKeyType.ATTRIBUTE, "temperature"));
NumericFilterPredicate predicate = new NumericFilterPredicate(); NumericFilterPredicate predicate = new NumericFilterPredicate();
predicate.setValue(45); predicate.setValue(FilterPredicateValue.fromDouble(45));
predicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER); predicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER);
highTemperatureFilter.setPredicate(predicate); highTemperatureFilter.setPredicate(predicate);
List<KeyFilter> keyFilters = Collections.singletonList(highTemperatureFilter); List<KeyFilter> keyFilters = Collections.singletonList(highTemperatureFilter);

4
application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java

@ -26,9 +26,9 @@ import java.util.Arrays;
@RunWith(ClasspathSuite.class) @RunWith(ClasspathSuite.class)
@ClasspathSuite.ClassnameFilters({ @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.EntityQueryControllerSqlTest",
// "org.thingsboard.server.controller.sql.*Test", "org.thingsboard.server.controller.sql.*Test",
}) })
public class ControllerSqlTestSuite { public class ControllerSqlTestSuite {

2
common/data/src/main/java/org/thingsboard/server/common/data/query/BooleanFilterPredicate.java

@ -21,7 +21,7 @@ import lombok.Data;
public class BooleanFilterPredicate implements KeyFilterPredicate { public class BooleanFilterPredicate implements KeyFilterPredicate {
private BooleanOperation operation; private BooleanOperation operation;
private boolean value; private FilterPredicateValue<Boolean> value;
@Override @Override
public FilterPredicateType getType() { public FilterPredicateType getType() {

33
common/data/src/main/java/org/thingsboard/server/common/data/query/DynamicValue.java

@ -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;
}

22
common/data/src/main/java/org/thingsboard/server/common/data/query/DynamicValueSourceType.java

@ -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
}

71
common/data/src/main/java/org/thingsboard/server/common/data/query/FilterPredicateValue.java

@ -0,0 +1,71 @@
/**
* 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 T userValue;
@Getter
private final DynamicValue<T> dynamicValue;
public FilterPredicateValue(T defaultValue) {
this(defaultValue, null, null);
}
@JsonCreator
public FilterPredicateValue(@JsonProperty("defaultValue") T defaultValue,
@JsonProperty("userValue") T userValue,
@JsonProperty("dynamicValue") DynamicValue<T> dynamicValue) {
this.defaultValue = defaultValue;
this.userValue = userValue;
this.dynamicValue = dynamicValue;
}
@JsonIgnore
public T getValue() {
if (this.userValue != null) {
return this.userValue;
} else {
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);
}
}

2
common/data/src/main/java/org/thingsboard/server/common/data/query/NumericFilterPredicate.java

@ -21,7 +21,7 @@ import lombok.Data;
public class NumericFilterPredicate implements KeyFilterPredicate { public class NumericFilterPredicate implements KeyFilterPredicate {
private NumericOperation operation; private NumericOperation operation;
private double value; private FilterPredicateValue<Double> value;
@Override @Override
public FilterPredicateType getType() { public FilterPredicateType getType() {

2
common/data/src/main/java/org/thingsboard/server/common/data/query/StringFilterPredicate.java

@ -21,7 +21,7 @@ import lombok.Data;
public class StringFilterPredicate implements KeyFilterPredicate { public class StringFilterPredicate implements KeyFilterPredicate {
private StringOperation operation; private StringOperation operation;
private String value; private FilterPredicateValue<String> value;
private boolean ignoreCase; private boolean ignoreCase;
@Override @Override

8
dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java

@ -406,7 +406,7 @@ public class EntityKeyMapping {
String entityFieldAlias = getEntityFieldAlias(filterType, entityType); String entityFieldAlias = getEntityFieldAlias(filterType, entityType);
String column = null; String column = null;
if (existingEntityFields.contains(entityFieldAlias)) { if (existingEntityFields.contains(entityFieldAlias)) {
column = entityFieldColumnMap.get(key.getKey()); column = entityFieldColumnMap.get(entityFieldAlias);
} }
if (column != null) { if (column != null) {
String field = alias + "." + column; String field = alias + "." + column;
@ -440,7 +440,7 @@ public class EntityKeyMapping {
private String buildStringPredicateQuery(QueryContext ctx, String field, StringFilterPredicate stringFilterPredicate) { private String buildStringPredicateQuery(QueryContext ctx, String field, StringFilterPredicate stringFilterPredicate) {
String operationField = field; String operationField = field;
String paramName = getNextParameterName(field); String paramName = getNextParameterName(field);
String value = stringFilterPredicate.getValue(); String value = stringFilterPredicate.getValue().getValue();
String stringOperationQuery = ""; String stringOperationQuery = "";
if (stringFilterPredicate.isIgnoreCase()) { if (stringFilterPredicate.isIgnoreCase()) {
value = value.toLowerCase(); value = value.toLowerCase();
@ -476,7 +476,7 @@ public class EntityKeyMapping {
private String buildNumericPredicateQuery(QueryContext ctx, String field, NumericFilterPredicate numericFilterPredicate) { private String buildNumericPredicateQuery(QueryContext ctx, String field, NumericFilterPredicate numericFilterPredicate) {
String paramName = getNextParameterName(field); String paramName = getNextParameterName(field);
ctx.addDoubleParameter(paramName, numericFilterPredicate.getValue()); ctx.addDoubleParameter(paramName, numericFilterPredicate.getValue().getValue());
String numericOperationQuery = ""; String numericOperationQuery = "";
switch (numericFilterPredicate.getOperation()) { switch (numericFilterPredicate.getOperation()) {
case EQUAL: case EQUAL:
@ -504,7 +504,7 @@ public class EntityKeyMapping {
private String buildBooleanPredicateQuery(QueryContext ctx, String field, private String buildBooleanPredicateQuery(QueryContext ctx, String field,
BooleanFilterPredicate booleanFilterPredicate) { BooleanFilterPredicate booleanFilterPredicate) {
String paramName = getNextParameterName(field); String paramName = getNextParameterName(field);
ctx.addBooleanParameter(paramName, booleanFilterPredicate.isValue()); ctx.addBooleanParameter(paramName, booleanFilterPredicate.getValue().getValue());
String booleanOperationQuery = ""; String booleanOperationQuery = "";
switch (booleanFilterPredicate.getOperation()) { switch (booleanFilterPredicate.getOperation()) {
case EQUAL: case EQUAL:

9
dao/src/test/java/org/thingsboard/server/dao/service/BaseEntityServiceTest.java

@ -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.EntityKey;
import org.thingsboard.server.common.data.query.EntityKeyType; import org.thingsboard.server.common.data.query.EntityKeyType;
import org.thingsboard.server.common.data.query.EntityListFilter; 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.KeyFilter;
import org.thingsboard.server.common.data.query.NumericFilterPredicate; import org.thingsboard.server.common.data.query.NumericFilterPredicate;
import org.thingsboard.server.common.data.query.RelationsQueryFilter; import org.thingsboard.server.common.data.query.RelationsQueryFilter;
@ -239,7 +240,7 @@ public abstract class BaseEntityServiceTest extends AbstractServiceTest {
KeyFilter highTemperatureFilter = new KeyFilter(); KeyFilter highTemperatureFilter = new KeyFilter();
highTemperatureFilter.setKey(new EntityKey(EntityKeyType.ATTRIBUTE, "temperature")); highTemperatureFilter.setKey(new EntityKey(EntityKeyType.ATTRIBUTE, "temperature"));
NumericFilterPredicate predicate = new NumericFilterPredicate(); NumericFilterPredicate predicate = new NumericFilterPredicate();
predicate.setValue(45); predicate.setValue(FilterPredicateValue.fromDouble(45));
predicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER); predicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER);
highTemperatureFilter.setPredicate(predicate); highTemperatureFilter.setPredicate(predicate);
List<KeyFilter> keyFilters = Collections.singletonList(highTemperatureFilter); List<KeyFilter> keyFilters = Collections.singletonList(highTemperatureFilter);
@ -311,7 +312,7 @@ public abstract class BaseEntityServiceTest extends AbstractServiceTest {
KeyFilter highTemperatureFilter = new KeyFilter(); KeyFilter highTemperatureFilter = new KeyFilter();
highTemperatureFilter.setKey(new EntityKey(EntityKeyType.ATTRIBUTE, "temperature")); highTemperatureFilter.setKey(new EntityKey(EntityKeyType.ATTRIBUTE, "temperature"));
NumericFilterPredicate predicate = new NumericFilterPredicate(); NumericFilterPredicate predicate = new NumericFilterPredicate();
predicate.setValue(45); predicate.setValue(FilterPredicateValue.fromDouble(45));
predicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER); predicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER);
highTemperatureFilter.setPredicate(predicate); highTemperatureFilter.setPredicate(predicate);
List<KeyFilter> keyFilters = Collections.singletonList(highTemperatureFilter); List<KeyFilter> keyFilters = Collections.singletonList(highTemperatureFilter);
@ -382,7 +383,7 @@ public abstract class BaseEntityServiceTest extends AbstractServiceTest {
KeyFilter highTemperatureFilter = new KeyFilter(); KeyFilter highTemperatureFilter = new KeyFilter();
highTemperatureFilter.setKey(new EntityKey(EntityKeyType.ATTRIBUTE, "consumption")); highTemperatureFilter.setKey(new EntityKey(EntityKeyType.ATTRIBUTE, "consumption"));
NumericFilterPredicate predicate = new NumericFilterPredicate(); NumericFilterPredicate predicate = new NumericFilterPredicate();
predicate.setValue(50); predicate.setValue(FilterPredicateValue.fromDouble(50));
predicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER); predicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER);
highTemperatureFilter.setPredicate(predicate); highTemperatureFilter.setPredicate(predicate);
List<KeyFilter> keyFilters = Collections.singletonList(highTemperatureFilter); List<KeyFilter> keyFilters = Collections.singletonList(highTemperatureFilter);
@ -584,7 +585,7 @@ public abstract class BaseEntityServiceTest extends AbstractServiceTest {
KeyFilter highTemperatureFilter = new KeyFilter(); KeyFilter highTemperatureFilter = new KeyFilter();
highTemperatureFilter.setKey(new EntityKey(EntityKeyType.ATTRIBUTE, "temperature")); highTemperatureFilter.setKey(new EntityKey(EntityKeyType.ATTRIBUTE, "temperature"));
NumericFilterPredicate predicate = new NumericFilterPredicate(); NumericFilterPredicate predicate = new NumericFilterPredicate();
predicate.setValue(45); predicate.setValue(FilterPredicateValue.fromDouble(45));
predicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER); predicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER);
highTemperatureFilter.setPredicate(predicate); highTemperatureFilter.setPredicate(predicate);
List<KeyFilter> keyFilters = Collections.singletonList(highTemperatureFilter); List<KeyFilter> keyFilters = Collections.singletonList(highTemperatureFilter);

4
ui-ngx/package-lock.json

@ -8997,10 +8997,10 @@
"integrity": "sha512-4O3GWAYJaauMCILm07weko2rHA8a4kjn7+8Lg4s1d7SxwS/3IpkVD/GljbRrIJ1c1W/XGJ3GbuK7RyYZEJChhw==" "integrity": "sha512-4O3GWAYJaauMCILm07weko2rHA8a4kjn7+8Lg4s1d7SxwS/3IpkVD/GljbRrIJ1c1W/XGJ3GbuK7RyYZEJChhw=="
}, },
"ngx-flowchart": { "ngx-flowchart": {
"version": "git://github.com/thingsboard/ngx-flowchart.git#a4157b0eef2eb3646ef920447c7b06b39d54f87f", "version": "git://github.com/thingsboard/ngx-flowchart.git#7a02f4748b5e7821a883c903107af5f20415d026",
"from": "git://github.com/thingsboard/ngx-flowchart.git#master", "from": "git://github.com/thingsboard/ngx-flowchart.git#master",
"requires": { "requires": {
"tslib": "^1.10.0" "tslib": "^1.13.0"
}, },
"dependencies": { "dependencies": {
"tslib": { "tslib": {

4
ui-ngx/src/app/core/http/entity.service.ts

@ -396,7 +396,9 @@ export class EntityService {
type: FilterPredicateType.STRING, type: FilterPredicateType.STRING,
operation: StringOperation.STARTS_WITH, operation: StringOperation.STARTS_WITH,
ignoreCase: true, ignoreCase: true,
value: searchText value: {
defaultValue: searchText
}
} }
} }
] : null ] : null

9
ui-ngx/src/app/modules/home/components/filter/boolean-filter-predicate.component.html

@ -15,7 +15,7 @@
limitations under the License. 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-form-field floatLabel="always" hideRequiredMarker fxFlex="40" class="mat-block">
<mat-label></mat-label> <mat-label></mat-label>
<mat-select required formControlName="operation" placeholder="{{'filter.operation.operation' | translate}}"> <mat-select required formControlName="operation" placeholder="{{'filter.operation.operation' | translate}}">
@ -24,7 +24,8 @@
</mat-option> </mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<mat-checkbox fxFlex="60" formControlName="value"> <tb-filter-predicate-value fxFlex="60"
{{ (booleanFilterPredicateFormGroup.get('value').value ? 'value.true' : 'value.false') | translate }} [valueType]="valueTypeEnum.BOOLEAN"
</mat-checkbox> formControlName="value">
</tb-filter-predicate-value>
</div> </div>

13
ui-ngx/src/app/modules/home/components/filter/boolean-filter-predicate.component.ts

@ -18,10 +18,10 @@ import { Component, forwardRef, Input, OnInit } 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 { import {
BooleanFilterPredicate, BooleanFilterPredicate,
BooleanOperation, booleanOperationTranslationMap, BooleanOperation,
booleanOperationTranslationMap, EntityKeyValueType,
FilterPredicateType FilterPredicateType
} from '@shared/models/query/query.models'; } from '@shared/models/query/query.models';
import { isDefined } from '@core/utils';
@Component({ @Component({
selector: 'tb-boolean-filter-predicate', selector: 'tb-boolean-filter-predicate',
@ -39,6 +39,8 @@ export class BooleanFilterPredicateComponent implements ControlValueAccessor, On
@Input() disabled: boolean; @Input() disabled: boolean;
valueTypeEnum = EntityKeyValueType;
booleanFilterPredicateFormGroup: FormGroup; booleanFilterPredicateFormGroup: FormGroup;
booleanOperations = Object.keys(BooleanOperation); booleanOperations = Object.keys(BooleanOperation);
@ -53,7 +55,7 @@ export class BooleanFilterPredicateComponent implements ControlValueAccessor, On
ngOnInit(): void { ngOnInit(): void {
this.booleanFilterPredicateFormGroup = this.fb.group({ this.booleanFilterPredicateFormGroup = this.fb.group({
operation: [BooleanOperation.EQUAL, [Validators.required]], operation: [BooleanOperation.EQUAL, [Validators.required]],
value: [false] value: [null, [Validators.required]]
}); });
this.booleanFilterPredicateFormGroup.valueChanges.subscribe(() => { this.booleanFilterPredicateFormGroup.valueChanges.subscribe(() => {
this.updateModel(); this.updateModel();
@ -78,16 +80,13 @@ export class BooleanFilterPredicateComponent implements ControlValueAccessor, On
writeValue(predicate: BooleanFilterPredicate): void { writeValue(predicate: BooleanFilterPredicate): void {
this.booleanFilterPredicateFormGroup.get('operation').patchValue(predicate.operation, {emitEvent: false}); 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() { private updateModel() {
let predicate: BooleanFilterPredicate = null; let predicate: BooleanFilterPredicate = null;
if (this.booleanFilterPredicateFormGroup.valid) { if (this.booleanFilterPredicateFormGroup.valid) {
predicate = this.booleanFilterPredicateFormGroup.getRawValue(); predicate = this.booleanFilterPredicateFormGroup.getRawValue();
if (!isDefined(predicate.value)) {
predicate.value = false;
}
predicate.type = FilterPredicateType.BOOLEAN; predicate.type = FilterPredicateType.BOOLEAN;
} }
this.propagateChange(predicate); this.propagateChange(predicate);

2
ui-ngx/src/app/modules/home/components/filter/complex-filter-predicate-dialog.component.html

@ -15,7 +15,7 @@
limitations under the License. limitations under the License.
--> -->
<form [formGroup]="complexFilterFormGroup" (ngSubmit)="save()" style="width: 700px;"> <form [formGroup]="complexFilterFormGroup" (ngSubmit)="save()" style="width: 900px;">
<mat-toolbar color="primary"> <mat-toolbar color="primary">
<h2 translate>filter.complex-filter</h2> <h2 translate>filter.complex-filter</h2>
<span fxFlex></span> <span fxFlex></span>

2
ui-ngx/src/app/modules/home/components/filter/filter-predicate-list.component.html

@ -39,7 +39,7 @@
</div> </div>
<mat-divider></mat-divider> <mat-divider></mat-divider>
<div class="predicate-list"> <div class="predicate-list">
<div fxLayout="row" fxLayoutAlign="start center" style="height: 40px;" <div fxLayout="row" fxLayoutAlign="start center" style="height: 45px;"
formArrayName="predicates" formArrayName="predicates"
*ngFor="let predicateControl of predicatesFormArray().controls; let $index = index"> *ngFor="let predicateControl of predicatesFormArray().controls; let $index = index">
<div fxFlex="8" fxLayout="row" fxLayoutAlign="center" class="filters-operation"> <div fxFlex="8" fxLayout="row" fxLayoutAlign="center" class="filters-operation">

82
ui-ngx/src/app/modules/home/components/filter/filter-predicate-value.component.html

@ -0,0 +1,82 @@
<!--
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" [fxShow]="!dynamicMode">
<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" translate>filter.default-value</div>
</div>
<div fxFlex fxLayout="column" [fxShow]="dynamicMode">
<div fxFlex formGroupName="dynamicValue" fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<div fxFlex fxLayout="column">
<mat-form-field floatLabel="always" hideRequiredMarker fxFlex class="mat-block">
<mat-label></mat-label>
<mat-select formControlName="sourceType" placeholder="{{'filter.dynamic-source-type' | translate}}">
<mat-option [value]="null">
{{'filter.no-dynamic-value' | translate}}
</mat-option>
<mat-option *ngFor="let sourceType of dynamicValueSourceTypes" [value]="sourceType">
{{dynamicValueSourceTypeTranslations.get(dynamicValueSourceTypeEnum[sourceType]) | translate}}
</mat-option>
</mat-select>
</mat-form-field>
<div class="tb-hint" translate>filter.dynamic-source-type</div>
</div>
<div fxFlex fxLayout="column">
<mat-form-field floatLabel="always" hideRequiredMarker fxFlex class="mat-block">
<mat-label></mat-label>
<input matInput formControlName="sourceAttribute" placeholder="{{'filter.source-attribute' | translate}}">
</mat-form-field>
<div class="tb-hint" translate>filter.source-attribute</div>
</div>
</div>
</div>
<button mat-icon-button
class="mat-elevation-z1 tb-mat-32"
color="primary"
type="button"
matTooltip="{{ (dynamicMode ? 'filter.switch-to-default-value' : 'filter.switch-to-dynamic-value') | translate }}"
matTooltipPosition="above"
(click)="dynamicMode = !dynamicMode">
<mat-icon class="tb-mat-20" [svgIcon]="dynamicMode ? 'mdi:numeric' : 'mdi:variable'"></mat-icon>
</button>
</div>

146
ui-ngx/src/app/modules/home/components/filter/filter-predicate-value.component.ts

@ -0,0 +1,146 @@
///
/// 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 {
DynamicValueSourceType,
dynamicValueSourceTypeTranslationMap,
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;
dynamicValueSourceTypes = Object.keys(DynamicValueSourceType);
dynamicValueSourceTypeEnum = DynamicValueSourceType;
dynamicValueSourceTypeTranslations = dynamicValueSourceTypeTranslationMap;
filterPredicateValueFormGroup: FormGroup;
dynamicMode = false;
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.get('dynamicValue').get('sourceType').valueChanges.subscribe(
(sourceType) => {
if (!sourceType) {
this.filterPredicateValueFormGroup.get('dynamicValue').get('sourceAttribute').patchValue(null, {emitEvent: false});
}
}
);
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').get('sourceType').patchValue(predicateValue.dynamicValue ?
predicateValue.dynamicValue.sourceType : null, {emitEvent: false});
this.filterPredicateValueFormGroup.get('dynamicValue').get('sourceAttribute').patchValue(predicateValue.dynamicValue ?
predicateValue.dynamicValue.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);
}
}

7
ui-ngx/src/app/modules/home/components/filter/filter-predicate.scss

@ -13,6 +13,13 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
:host {
.tb-hint {
padding-bottom: 0;
}
}
:host ::ng-deep { :host ::ng-deep {
mat-form-field { mat-form-field {
.mat-form-field-wrapper { .mat-form-field-wrapper {

4
ui-ngx/src/app/modules/home/components/filter/filters-edit-panel.component.html

@ -16,7 +16,7 @@
--> -->
<div fxLayout="column" class="mat-content mat-padding"> <div fxLayout="column" class="mat-content mat-padding">
<div fxLayout="column" *ngFor="let filter of filtersInfo | keyvalue"> <div fxLayout="column" *ngFor="let filter of filtersInfo | keyvalue; let last = last">
<div fxFlex fxLayout="row" fxLayoutAlign="start center"> <div fxFlex fxLayout="row" fxLayoutAlign="start center">
<mat-label fxFlex>{{filter.value.filter}}</mat-label> <mat-label fxFlex>{{filter.value.filter}}</mat-label>
<button mat-icon-button color="primary" <button mat-icon-button color="primary"
@ -28,6 +28,6 @@
<mat-icon>edit</mat-icon> <mat-icon>edit</mat-icon>
</button> </button>
</div> </div>
<mat-divider></mat-divider> <mat-divider *ngIf="!last"></mat-divider>
</div> </div>
</div> </div>

2
ui-ngx/src/app/modules/home/components/filter/key-filter-dialog.component.html

@ -15,7 +15,7 @@
limitations under the License. limitations under the License.
--> -->
<form [formGroup]="keyFilterFormGroup" (ngSubmit)="save()" style="width: 700px;"> <form [formGroup]="keyFilterFormGroup" (ngSubmit)="save()" style="width: 900px;">
<mat-toolbar color="primary"> <mat-toolbar color="primary">
<h2>{{(data.isAdd ? 'filter.add-key-filter' : 'filter.edit-key-filter') | translate}}</h2> <h2>{{(data.isAdd ? 'filter.add-key-filter' : 'filter.edit-key-filter') | translate}}</h2>
<span fxFlex></span> <span fxFlex></span>

21
ui-ngx/src/app/modules/home/components/filter/numeric-filter-predicate.component.html

@ -15,7 +15,7 @@
limitations under the License. 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-form-field floatLabel="always" hideRequiredMarker fxFlex="40" class="mat-block">
<mat-label></mat-label> <mat-label></mat-label>
<mat-select required formControlName="operation" placeholder="{{'filter.operation.operation' | translate}}"> <mat-select required formControlName="operation" placeholder="{{'filter.operation.operation' | translate}}">
@ -24,19 +24,8 @@
</mat-option> </mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<div fxFlex="60" fxLayout="column" [ngSwitch]="valueType"> <tb-filter-predicate-value fxFlex="60"
<ng-template [ngSwitchCase]="valueTypeEnum.NUMERIC"> [valueType]="valueType"
<mat-form-field floatLabel="always" hideRequiredMarker fxFlex class="mat-block"> formControlName="value">
<mat-label></mat-label> </tb-filter-predicate-value>
<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>
</div> </div>

13
ui-ngx/src/app/modules/home/components/filter/numeric-filter-predicate.component.ts

@ -18,9 +18,11 @@ import { Component, forwardRef, Input, OnInit } 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 { import {
EntityKeyValueType, EntityKeyValueType,
FilterPredicateType, NumericFilterPredicate, NumericOperation, numericOperationTranslationMap, FilterPredicateType,
NumericFilterPredicate,
NumericOperation,
numericOperationTranslationMap,
} from '@shared/models/query/query.models'; } from '@shared/models/query/query.models';
import { isDefined } from '@core/utils';
@Component({ @Component({
selector: 'tb-numeric-filter-predicate', selector: 'tb-numeric-filter-predicate',
@ -56,7 +58,7 @@ export class NumericFilterPredicateComponent implements ControlValueAccessor, On
ngOnInit(): void { ngOnInit(): void {
this.numericFilterPredicateFormGroup = this.fb.group({ this.numericFilterPredicateFormGroup = this.fb.group({
operation: [NumericOperation.EQUAL, [Validators.required]], operation: [NumericOperation.EQUAL, [Validators.required]],
value: [0, [Validators.required]] value: [null, [Validators.required]]
}); });
this.numericFilterPredicateFormGroup.valueChanges.subscribe(() => { this.numericFilterPredicateFormGroup.valueChanges.subscribe(() => {
this.updateModel(); this.updateModel();
@ -81,16 +83,13 @@ export class NumericFilterPredicateComponent implements ControlValueAccessor, On
writeValue(predicate: NumericFilterPredicate): void { writeValue(predicate: NumericFilterPredicate): void {
this.numericFilterPredicateFormGroup.get('operation').patchValue(predicate.operation, {emitEvent: false}); 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() { private updateModel() {
let predicate: NumericFilterPredicate = null; let predicate: NumericFilterPredicate = null;
if (this.numericFilterPredicateFormGroup.valid) { if (this.numericFilterPredicateFormGroup.valid) {
predicate = this.numericFilterPredicateFormGroup.getRawValue(); predicate = this.numericFilterPredicateFormGroup.getRawValue();
if (!predicate.value) {
predicate.value = 0;
}
predicate.type = FilterPredicateType.NUMERIC; predicate.type = FilterPredicateType.NUMERIC;
} }
this.propagateChange(predicate); this.propagateChange(predicate);

10
ui-ngx/src/app/modules/home/components/filter/string-filter-predicate.component.html

@ -15,7 +15,7 @@
limitations under the License. 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"> <div fxFlex="40" fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field floatLabel="always" hideRequiredMarker fxFlex class="mat-block"> <mat-form-field floatLabel="always" hideRequiredMarker fxFlex class="mat-block">
<mat-label></mat-label> <mat-label></mat-label>
@ -28,8 +28,8 @@
<mat-checkbox fxLayout="row" fxLayoutAlign="center" formControlName="ignoreCase" style="min-width: 70px;"> <mat-checkbox fxLayout="row" fxLayoutAlign="center" formControlName="ignoreCase" style="min-width: 70px;">
</mat-checkbox> </mat-checkbox>
</div> </div>
<mat-form-field floatLabel="always" hideRequiredMarker fxFlex="60" class="mat-block"> <tb-filter-predicate-value fxFlex="60"
<mat-label></mat-label> [valueType]="valueTypeEnum.STRING"
<input matInput formControlName="value" placeholder="{{'filter.value' | translate}}"> formControlName="value">
</mat-form-field> </tb-filter-predicate-value>
</div> </div>

10
ui-ngx/src/app/modules/home/components/filter/string-filter-predicate.component.ts

@ -17,6 +17,7 @@
import { Component, forwardRef, Input, OnInit } from '@angular/core'; import { Component, forwardRef, Input, OnInit } 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 { import {
EntityKeyValueType,
FilterPredicateType, FilterPredicateType,
StringFilterPredicate, StringFilterPredicate,
StringOperation, StringOperation,
@ -39,6 +40,8 @@ export class StringFilterPredicateComponent implements ControlValueAccessor, OnI
@Input() disabled: boolean; @Input() disabled: boolean;
valueTypeEnum = EntityKeyValueType;
stringFilterPredicateFormGroup: FormGroup; stringFilterPredicateFormGroup: FormGroup;
stringOperations = Object.keys(StringOperation); stringOperations = Object.keys(StringOperation);
@ -53,7 +56,7 @@ export class StringFilterPredicateComponent implements ControlValueAccessor, OnI
ngOnInit(): void { ngOnInit(): void {
this.stringFilterPredicateFormGroup = this.fb.group({ this.stringFilterPredicateFormGroup = this.fb.group({
operation: [StringOperation.STARTS_WITH, [Validators.required]], operation: [StringOperation.STARTS_WITH, [Validators.required]],
value: [''], value: [null, [Validators.required]],
ignoreCase: [false] ignoreCase: [false]
}); });
this.stringFilterPredicateFormGroup.valueChanges.subscribe(() => { this.stringFilterPredicateFormGroup.valueChanges.subscribe(() => {
@ -79,7 +82,7 @@ export class StringFilterPredicateComponent implements ControlValueAccessor, OnI
writeValue(predicate: StringFilterPredicate): void { writeValue(predicate: StringFilterPredicate): void {
this.stringFilterPredicateFormGroup.get('operation').patchValue(predicate.operation, {emitEvent: false}); 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}); this.stringFilterPredicateFormGroup.get('ignoreCase').patchValue(predicate.ignoreCase, {emitEvent: false});
} }
@ -87,9 +90,6 @@ export class StringFilterPredicateComponent implements ControlValueAccessor, OnI
let predicate: StringFilterPredicate = null; let predicate: StringFilterPredicate = null;
if (this.stringFilterPredicateFormGroup.valid) { if (this.stringFilterPredicateFormGroup.valid) {
predicate = this.stringFilterPredicateFormGroup.getRawValue(); predicate = this.stringFilterPredicateFormGroup.getRawValue();
if (!predicate.value) {
predicate.value = '';
}
predicate.type = FilterPredicateType.STRING; predicate.type = FilterPredicateType.STRING;
} }
this.propagateChange(predicate); this.propagateChange(predicate);

11
ui-ngx/src/app/modules/home/components/filter/user-filter-dialog.component.ts

@ -33,10 +33,11 @@ import { DialogComponent } from '@app/shared/components/dialog.component';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { import {
EntityKeyValueType, EntityKeyValueType,
Filter, Filter, FilterPredicateValue,
filterToUserFilterInfoList, filterToUserFilterInfoList,
UserFilterInputInfo UserFilterInputInfo
} from '@shared/models/query/query.models'; } from '@shared/models/query/query.models';
import { isDefinedAndNotNull } from '@core/utils';
export interface UserFilterDialogData { export interface UserFilterDialogData {
filter: Filter; filter: Filter;
@ -81,15 +82,17 @@ export class UserFilterDialogComponent extends DialogComponent<UserFilterDialogC
} }
private createUserInputFormControl(userInput: UserFilterInputInfo): AbstractControl { private createUserInputFormControl(userInput: UserFilterInputInfo): AbstractControl {
const predicateValue: FilterPredicateValue<string | number | boolean> = (userInput.info.keyFilterPredicate as any).value;
const value = isDefinedAndNotNull(predicateValue.userValue) ? predicateValue.userValue : predicateValue.defaultValue;
const userInputControl = this.fb.group({ const userInputControl = this.fb.group({
label: [userInput.label], label: [userInput.label],
valueType: [userInput.valueType], valueType: [userInput.valueType],
value: [(userInput.info.keyFilterPredicate as any).value, value: [value,
userInput.valueType === EntityKeyValueType.NUMERIC || userInput.valueType === EntityKeyValueType.NUMERIC ||
userInput.valueType === EntityKeyValueType.DATE_TIME ? [Validators.required] : []] userInput.valueType === EntityKeyValueType.DATE_TIME ? [Validators.required] : []]
}); });
userInputControl.get('value').valueChanges.subscribe(value => { userInputControl.get('value').valueChanges.subscribe(userValue => {
(userInput.info.keyFilterPredicate as any).value = value; (userInput.info.keyFilterPredicate as any).value.userValue = userValue;
}); });
return userInputControl; return userInputControl;
} }

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

@ -83,6 +83,7 @@ import { FiltersEditPanelComponent } from '@home/components/filter/filters-edit-
import { UserFilterDialogComponent } from '@home/components/filter/user-filter-dialog.component'; import { UserFilterDialogComponent } from '@home/components/filter/user-filter-dialog.component';
import { FilterUserInfoComponent } from './filter/filter-user-info.component'; import { FilterUserInfoComponent } from './filter/filter-user-info.component';
import { FilterUserInfoDialogComponent } from './filter/filter-user-info-dialog.component'; import { FilterUserInfoDialogComponent } from './filter/filter-user-info-dialog.component';
import { FilterPredicateValueComponent } from './filter/filter-predicate-value.component';
@NgModule({ @NgModule({
declarations: declarations:
@ -148,7 +149,8 @@ import { FilterUserInfoDialogComponent } from './filter/filter-user-info-dialog.
FiltersEditPanelComponent, FiltersEditPanelComponent,
UserFilterDialogComponent, UserFilterDialogComponent,
FilterUserInfoComponent, FilterUserInfoComponent,
FilterUserInfoDialogComponent FilterUserInfoDialogComponent,
FilterPredicateValueComponent
], ],
imports: [ imports: [
CommonModule, CommonModule,

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

@ -138,16 +138,22 @@ export function createDefaultFilterPredicate(valueType: EntityKeyValueType, comp
switch (predicate.type) { switch (predicate.type) {
case FilterPredicateType.STRING: case FilterPredicateType.STRING:
predicate.operation = StringOperation.STARTS_WITH; predicate.operation = StringOperation.STARTS_WITH;
predicate.value = ''; predicate.value = {
defaultValue: ''
};
predicate.ignoreCase = false; predicate.ignoreCase = false;
break; break;
case FilterPredicateType.NUMERIC: case FilterPredicateType.NUMERIC:
predicate.operation = NumericOperation.EQUAL; predicate.operation = NumericOperation.EQUAL;
predicate.value = valueType === EntityKeyValueType.DATE_TIME ? Date.now() : 0; predicate.value = {
defaultValue: valueType === EntityKeyValueType.DATE_TIME ? Date.now() : 0
};
break; break;
case FilterPredicateType.BOOLEAN: case FilterPredicateType.BOOLEAN:
predicate.operation = BooleanOperation.EQUAL; predicate.operation = BooleanOperation.EQUAL;
predicate.value = false; predicate.value = {
defaultValue: false
};
break; break;
case FilterPredicateType.COMPLEX: case FilterPredicateType.COMPLEX:
predicate.operation = ComplexOperation.AND; predicate.operation = ComplexOperation.AND;
@ -228,23 +234,48 @@ 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;
userValue?: T;
dynamicValue?: DynamicValue<T>;
}
export interface StringFilterPredicate { export interface StringFilterPredicate {
type: FilterPredicateType.STRING, type: FilterPredicateType.STRING,
operation: StringOperation; operation: StringOperation;
value: string; value: FilterPredicateValue<string>;
ignoreCase: boolean; ignoreCase: boolean;
} }
export interface NumericFilterPredicate { export interface NumericFilterPredicate {
type: FilterPredicateType.NUMERIC, type: FilterPredicateType.NUMERIC,
operation: NumericOperation; operation: NumericOperation;
value: number; value: FilterPredicateValue<number>;
} }
export interface BooleanFilterPredicate { export interface BooleanFilterPredicate {
type: FilterPredicateType.BOOLEAN, type: FilterPredicateType.BOOLEAN,
operation: BooleanOperation; operation: BooleanOperation;
value: boolean; value: FilterPredicateValue<boolean>;
} }
export interface BaseComplexFilterPredicate<T extends KeyFilterPredicate | KeyFilterPredicateInfo> { export interface BaseComplexFilterPredicate<T extends KeyFilterPredicate | KeyFilterPredicateInfo> {

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

@ -1227,7 +1227,16 @@
"remove-key-filter": "Remove key filter", "remove-key-filter": "Remove key filter",
"edit-key-filter": "Edit key filter", "edit-key-filter": "Edit key filter",
"date": "Date", "date": "Date",
"time": "Time" "time": "Time",
"current-tenant": "Current tenant",
"current-customer": "Current customer",
"current-user": "Current user",
"default-value": "Default value",
"dynamic-source-type": "Dynamic source type",
"no-dynamic-value": "No dynamic value",
"source-attribute": "Source attribute",
"switch-to-dynamic-value": "Switch to dynamic value",
"switch-to-default-value": "Switch to default value"
}, },
"fullscreen": { "fullscreen": {
"expand": "Expand to fullscreen", "expand": "Expand to fullscreen",

Loading…
Cancel
Save