Showing
25 changed files
with
395 additions
and
69 deletions
@@ -44,6 +44,7 @@ import org.thingsboard.server.common.data.query.EntityDataSortOrder; | @@ -44,6 +44,7 @@ import org.thingsboard.server.common.data.query.EntityDataSortOrder; | ||
44 | import org.thingsboard.server.common.data.query.EntityKey; | 44 | import org.thingsboard.server.common.data.query.EntityKey; |
45 | import org.thingsboard.server.common.data.query.EntityKeyType; | 45 | import org.thingsboard.server.common.data.query.EntityKeyType; |
46 | import org.thingsboard.server.common.data.query.EntityListFilter; | 46 | import org.thingsboard.server.common.data.query.EntityListFilter; |
47 | +import org.thingsboard.server.common.data.query.FilterPredicateValue; | ||
47 | import org.thingsboard.server.common.data.query.KeyFilter; | 48 | import org.thingsboard.server.common.data.query.KeyFilter; |
48 | import org.thingsboard.server.common.data.query.NumericFilterPredicate; | 49 | import org.thingsboard.server.common.data.query.NumericFilterPredicate; |
49 | import org.thingsboard.server.common.data.security.Authority; | 50 | import org.thingsboard.server.common.data.security.Authority; |
@@ -259,7 +260,7 @@ public abstract class BaseEntityQueryControllerTest extends AbstractControllerTe | @@ -259,7 +260,7 @@ public abstract class BaseEntityQueryControllerTest extends AbstractControllerTe | ||
259 | KeyFilter highTemperatureFilter = new KeyFilter(); | 260 | KeyFilter highTemperatureFilter = new KeyFilter(); |
260 | highTemperatureFilter.setKey(new EntityKey(EntityKeyType.ATTRIBUTE, "temperature")); | 261 | highTemperatureFilter.setKey(new EntityKey(EntityKeyType.ATTRIBUTE, "temperature")); |
261 | NumericFilterPredicate predicate = new NumericFilterPredicate(); | 262 | NumericFilterPredicate predicate = new NumericFilterPredicate(); |
262 | - predicate.setValue(45); | 263 | + predicate.setValue(FilterPredicateValue.fromDouble(45)); |
263 | predicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER); | 264 | predicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER); |
264 | highTemperatureFilter.setPredicate(predicate); | 265 | highTemperatureFilter.setPredicate(predicate); |
265 | List<KeyFilter> keyFilters = Collections.singletonList(highTemperatureFilter); | 266 | List<KeyFilter> keyFilters = Collections.singletonList(highTemperatureFilter); |
@@ -26,9 +26,9 @@ import java.util.Arrays; | @@ -26,9 +26,9 @@ import java.util.Arrays; | ||
26 | 26 | ||
27 | @RunWith(ClasspathSuite.class) | 27 | @RunWith(ClasspathSuite.class) |
28 | @ClasspathSuite.ClassnameFilters({ | 28 | @ClasspathSuite.ClassnameFilters({ |
29 | - "org.thingsboard.server.controller.sql.WebsocketApiSqlTest", | 29 | +// "org.thingsboard.server.controller.sql.WebsocketApiSqlTest", |
30 | // "org.thingsboard.server.controller.sql.EntityQueryControllerSqlTest", | 30 | // "org.thingsboard.server.controller.sql.EntityQueryControllerSqlTest", |
31 | -// "org.thingsboard.server.controller.sql.*Test", | 31 | + "org.thingsboard.server.controller.sql.*Test", |
32 | }) | 32 | }) |
33 | public class ControllerSqlTestSuite { | 33 | public class ControllerSqlTestSuite { |
34 | 34 |
@@ -21,7 +21,7 @@ import lombok.Data; | @@ -21,7 +21,7 @@ import lombok.Data; | ||
21 | public class BooleanFilterPredicate implements KeyFilterPredicate { | 21 | public class BooleanFilterPredicate implements KeyFilterPredicate { |
22 | 22 | ||
23 | private BooleanOperation operation; | 23 | private BooleanOperation operation; |
24 | - private boolean value; | 24 | + private FilterPredicateValue<Boolean> value; |
25 | 25 | ||
26 | @Override | 26 | @Override |
27 | public FilterPredicateType getType() { | 27 | public FilterPredicateType getType() { |
1 | +/** | ||
2 | + * Copyright © 2016-2020 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.common.data.query; | ||
17 | + | ||
18 | +import com.fasterxml.jackson.annotation.JsonIgnore; | ||
19 | +import lombok.Data; | ||
20 | +import lombok.Getter; | ||
21 | + | ||
22 | +@Data | ||
23 | +public class DynamicValue<T> { | ||
24 | + | ||
25 | + @JsonIgnore | ||
26 | + private T resolvedValue; | ||
27 | + | ||
28 | + @Getter | ||
29 | + private final DynamicValueSourceType sourceType; | ||
30 | + @Getter | ||
31 | + private final String sourceAttribute; | ||
32 | + | ||
33 | +} |
common/data/src/main/java/org/thingsboard/server/common/data/query/DynamicValueSourceType.java
0 → 100644
1 | +/** | ||
2 | + * Copyright © 2016-2020 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.common.data.query; | ||
17 | + | ||
18 | +public enum DynamicValueSourceType { | ||
19 | + CURRENT_TENANT, | ||
20 | + CURRENT_CUSTOMER, | ||
21 | + CURRENT_USER | ||
22 | +} |
common/data/src/main/java/org/thingsboard/server/common/data/query/FilterPredicateValue.java
0 → 100644
1 | +/** | ||
2 | + * Copyright © 2016-2020 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.common.data.query; | ||
17 | + | ||
18 | +import com.fasterxml.jackson.annotation.JsonCreator; | ||
19 | +import com.fasterxml.jackson.annotation.JsonIgnore; | ||
20 | +import com.fasterxml.jackson.annotation.JsonProperty; | ||
21 | +import lombok.Data; | ||
22 | +import lombok.Getter; | ||
23 | + | ||
24 | +@Data | ||
25 | +public class FilterPredicateValue<T> { | ||
26 | + | ||
27 | + @Getter | ||
28 | + private final T defaultValue; | ||
29 | + @Getter | ||
30 | + private final DynamicValue<T> dynamicValue; | ||
31 | + | ||
32 | + public FilterPredicateValue(T defaultValue) { | ||
33 | + this(defaultValue, null); | ||
34 | + } | ||
35 | + | ||
36 | + @JsonCreator | ||
37 | + public FilterPredicateValue(@JsonProperty("defaultValue") T defaultValue, | ||
38 | + @JsonProperty("dynamicValue") DynamicValue<T> dynamicValue) { | ||
39 | + this.defaultValue = defaultValue; | ||
40 | + this.dynamicValue = dynamicValue; | ||
41 | + } | ||
42 | + | ||
43 | + @JsonIgnore | ||
44 | + public T getValue() { | ||
45 | + if (this.dynamicValue != null && this.dynamicValue.getResolvedValue() != null) { | ||
46 | + return this.dynamicValue.getResolvedValue(); | ||
47 | + } else { | ||
48 | + return defaultValue; | ||
49 | + } | ||
50 | + } | ||
51 | + | ||
52 | + public static FilterPredicateValue<Double> fromDouble(double value) { | ||
53 | + return new FilterPredicateValue<>(value); | ||
54 | + } | ||
55 | + | ||
56 | + public static FilterPredicateValue<String> fromString(String value) { | ||
57 | + return new FilterPredicateValue<>(value); | ||
58 | + } | ||
59 | + | ||
60 | + public static FilterPredicateValue<Boolean> fromBoolean(boolean value) { | ||
61 | + return new FilterPredicateValue<>(value); | ||
62 | + } | ||
63 | +} |
@@ -21,7 +21,7 @@ import lombok.Data; | @@ -21,7 +21,7 @@ import lombok.Data; | ||
21 | public class NumericFilterPredicate implements KeyFilterPredicate { | 21 | public class NumericFilterPredicate implements KeyFilterPredicate { |
22 | 22 | ||
23 | private NumericOperation operation; | 23 | private NumericOperation operation; |
24 | - private double value; | 24 | + private FilterPredicateValue<Double> value; |
25 | 25 | ||
26 | @Override | 26 | @Override |
27 | public FilterPredicateType getType() { | 27 | public FilterPredicateType getType() { |
@@ -21,7 +21,7 @@ import lombok.Data; | @@ -21,7 +21,7 @@ import lombok.Data; | ||
21 | public class StringFilterPredicate implements KeyFilterPredicate { | 21 | public class StringFilterPredicate implements KeyFilterPredicate { |
22 | 22 | ||
23 | private StringOperation operation; | 23 | private StringOperation operation; |
24 | - private String value; | 24 | + private FilterPredicateValue<String> value; |
25 | private boolean ignoreCase; | 25 | private boolean ignoreCase; |
26 | 26 | ||
27 | @Override | 27 | @Override |
@@ -440,7 +440,7 @@ public class EntityKeyMapping { | @@ -440,7 +440,7 @@ public class EntityKeyMapping { | ||
440 | private String buildStringPredicateQuery(QueryContext ctx, String field, StringFilterPredicate stringFilterPredicate) { | 440 | private String buildStringPredicateQuery(QueryContext ctx, String field, StringFilterPredicate stringFilterPredicate) { |
441 | String operationField = field; | 441 | String operationField = field; |
442 | String paramName = getNextParameterName(field); | 442 | String paramName = getNextParameterName(field); |
443 | - String value = stringFilterPredicate.getValue(); | 443 | + String value = stringFilterPredicate.getValue().getValue(); |
444 | String stringOperationQuery = ""; | 444 | String stringOperationQuery = ""; |
445 | if (stringFilterPredicate.isIgnoreCase()) { | 445 | if (stringFilterPredicate.isIgnoreCase()) { |
446 | value = value.toLowerCase(); | 446 | value = value.toLowerCase(); |
@@ -476,7 +476,7 @@ public class EntityKeyMapping { | @@ -476,7 +476,7 @@ public class EntityKeyMapping { | ||
476 | 476 | ||
477 | private String buildNumericPredicateQuery(QueryContext ctx, String field, NumericFilterPredicate numericFilterPredicate) { | 477 | private String buildNumericPredicateQuery(QueryContext ctx, String field, NumericFilterPredicate numericFilterPredicate) { |
478 | String paramName = getNextParameterName(field); | 478 | String paramName = getNextParameterName(field); |
479 | - ctx.addDoubleParameter(paramName, numericFilterPredicate.getValue()); | 479 | + ctx.addDoubleParameter(paramName, numericFilterPredicate.getValue().getValue()); |
480 | String numericOperationQuery = ""; | 480 | String numericOperationQuery = ""; |
481 | switch (numericFilterPredicate.getOperation()) { | 481 | switch (numericFilterPredicate.getOperation()) { |
482 | case EQUAL: | 482 | case EQUAL: |
@@ -504,7 +504,7 @@ public class EntityKeyMapping { | @@ -504,7 +504,7 @@ public class EntityKeyMapping { | ||
504 | private String buildBooleanPredicateQuery(QueryContext ctx, String field, | 504 | private String buildBooleanPredicateQuery(QueryContext ctx, String field, |
505 | BooleanFilterPredicate booleanFilterPredicate) { | 505 | BooleanFilterPredicate booleanFilterPredicate) { |
506 | String paramName = getNextParameterName(field); | 506 | String paramName = getNextParameterName(field); |
507 | - ctx.addBooleanParameter(paramName, booleanFilterPredicate.isValue()); | 507 | + ctx.addBooleanParameter(paramName, booleanFilterPredicate.getValue().getValue()); |
508 | String booleanOperationQuery = ""; | 508 | String booleanOperationQuery = ""; |
509 | switch (booleanFilterPredicate.getOperation()) { | 509 | switch (booleanFilterPredicate.getOperation()) { |
510 | case EQUAL: | 510 | case EQUAL: |
@@ -49,6 +49,7 @@ import org.thingsboard.server.common.data.query.EntityDataSortOrder; | @@ -49,6 +49,7 @@ import org.thingsboard.server.common.data.query.EntityDataSortOrder; | ||
49 | import org.thingsboard.server.common.data.query.EntityKey; | 49 | import org.thingsboard.server.common.data.query.EntityKey; |
50 | import org.thingsboard.server.common.data.query.EntityKeyType; | 50 | import org.thingsboard.server.common.data.query.EntityKeyType; |
51 | import org.thingsboard.server.common.data.query.EntityListFilter; | 51 | import org.thingsboard.server.common.data.query.EntityListFilter; |
52 | +import org.thingsboard.server.common.data.query.FilterPredicateValue; | ||
52 | import org.thingsboard.server.common.data.query.KeyFilter; | 53 | import org.thingsboard.server.common.data.query.KeyFilter; |
53 | import org.thingsboard.server.common.data.query.NumericFilterPredicate; | 54 | import org.thingsboard.server.common.data.query.NumericFilterPredicate; |
54 | import org.thingsboard.server.common.data.query.RelationsQueryFilter; | 55 | import org.thingsboard.server.common.data.query.RelationsQueryFilter; |
@@ -239,7 +240,7 @@ public abstract class BaseEntityServiceTest extends AbstractServiceTest { | @@ -239,7 +240,7 @@ public abstract class BaseEntityServiceTest extends AbstractServiceTest { | ||
239 | KeyFilter highTemperatureFilter = new KeyFilter(); | 240 | KeyFilter highTemperatureFilter = new KeyFilter(); |
240 | highTemperatureFilter.setKey(new EntityKey(EntityKeyType.ATTRIBUTE, "temperature")); | 241 | highTemperatureFilter.setKey(new EntityKey(EntityKeyType.ATTRIBUTE, "temperature")); |
241 | NumericFilterPredicate predicate = new NumericFilterPredicate(); | 242 | NumericFilterPredicate predicate = new NumericFilterPredicate(); |
242 | - predicate.setValue(45); | 243 | + predicate.setValue(FilterPredicateValue.fromDouble(45)); |
243 | predicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER); | 244 | predicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER); |
244 | highTemperatureFilter.setPredicate(predicate); | 245 | highTemperatureFilter.setPredicate(predicate); |
245 | List<KeyFilter> keyFilters = Collections.singletonList(highTemperatureFilter); | 246 | List<KeyFilter> keyFilters = Collections.singletonList(highTemperatureFilter); |
@@ -311,7 +312,7 @@ public abstract class BaseEntityServiceTest extends AbstractServiceTest { | @@ -311,7 +312,7 @@ public abstract class BaseEntityServiceTest extends AbstractServiceTest { | ||
311 | KeyFilter highTemperatureFilter = new KeyFilter(); | 312 | KeyFilter highTemperatureFilter = new KeyFilter(); |
312 | highTemperatureFilter.setKey(new EntityKey(EntityKeyType.ATTRIBUTE, "temperature")); | 313 | highTemperatureFilter.setKey(new EntityKey(EntityKeyType.ATTRIBUTE, "temperature")); |
313 | NumericFilterPredicate predicate = new NumericFilterPredicate(); | 314 | NumericFilterPredicate predicate = new NumericFilterPredicate(); |
314 | - predicate.setValue(45); | 315 | + predicate.setValue(FilterPredicateValue.fromDouble(45)); |
315 | predicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER); | 316 | predicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER); |
316 | highTemperatureFilter.setPredicate(predicate); | 317 | highTemperatureFilter.setPredicate(predicate); |
317 | List<KeyFilter> keyFilters = Collections.singletonList(highTemperatureFilter); | 318 | List<KeyFilter> keyFilters = Collections.singletonList(highTemperatureFilter); |
@@ -382,7 +383,7 @@ public abstract class BaseEntityServiceTest extends AbstractServiceTest { | @@ -382,7 +383,7 @@ public abstract class BaseEntityServiceTest extends AbstractServiceTest { | ||
382 | KeyFilter highTemperatureFilter = new KeyFilter(); | 383 | KeyFilter highTemperatureFilter = new KeyFilter(); |
383 | highTemperatureFilter.setKey(new EntityKey(EntityKeyType.ATTRIBUTE, "consumption")); | 384 | highTemperatureFilter.setKey(new EntityKey(EntityKeyType.ATTRIBUTE, "consumption")); |
384 | NumericFilterPredicate predicate = new NumericFilterPredicate(); | 385 | NumericFilterPredicate predicate = new NumericFilterPredicate(); |
385 | - predicate.setValue(50); | 386 | + predicate.setValue(FilterPredicateValue.fromDouble(50)); |
386 | predicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER); | 387 | predicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER); |
387 | highTemperatureFilter.setPredicate(predicate); | 388 | highTemperatureFilter.setPredicate(predicate); |
388 | List<KeyFilter> keyFilters = Collections.singletonList(highTemperatureFilter); | 389 | List<KeyFilter> keyFilters = Collections.singletonList(highTemperatureFilter); |
@@ -584,7 +585,7 @@ public abstract class BaseEntityServiceTest extends AbstractServiceTest { | @@ -584,7 +585,7 @@ public abstract class BaseEntityServiceTest extends AbstractServiceTest { | ||
584 | KeyFilter highTemperatureFilter = new KeyFilter(); | 585 | KeyFilter highTemperatureFilter = new KeyFilter(); |
585 | highTemperatureFilter.setKey(new EntityKey(EntityKeyType.ATTRIBUTE, "temperature")); | 586 | highTemperatureFilter.setKey(new EntityKey(EntityKeyType.ATTRIBUTE, "temperature")); |
586 | NumericFilterPredicate predicate = new NumericFilterPredicate(); | 587 | NumericFilterPredicate predicate = new NumericFilterPredicate(); |
587 | - predicate.setValue(45); | 588 | + predicate.setValue(FilterPredicateValue.fromDouble(45)); |
588 | predicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER); | 589 | predicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER); |
589 | highTemperatureFilter.setPredicate(predicate); | 590 | highTemperatureFilter.setPredicate(predicate); |
590 | List<KeyFilter> keyFilters = Collections.singletonList(highTemperatureFilter); | 591 | List<KeyFilter> keyFilters = Collections.singletonList(highTemperatureFilter); |
@@ -396,7 +396,9 @@ export class EntityService { | @@ -396,7 +396,9 @@ export class EntityService { | ||
396 | type: FilterPredicateType.STRING, | 396 | type: FilterPredicateType.STRING, |
397 | operation: StringOperation.STARTS_WITH, | 397 | operation: StringOperation.STARTS_WITH, |
398 | ignoreCase: true, | 398 | ignoreCase: true, |
399 | - value: searchText | 399 | + value: { |
400 | + defaultValue: searchText | ||
401 | + } | ||
400 | } | 402 | } |
401 | } | 403 | } |
402 | ] : null | 404 | ] : null |
@@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
15 | limitations under the License. | 15 | limitations under the License. |
16 | 16 | ||
17 | --> | 17 | --> |
18 | -<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px" [formGroup]="booleanFilterPredicateFormGroup"> | 18 | +<div fxFlex fxLayout="row" fxLayoutAlign="start start" fxLayoutGap="8px" [formGroup]="booleanFilterPredicateFormGroup"> |
19 | <mat-form-field floatLabel="always" hideRequiredMarker fxFlex="40" class="mat-block"> | 19 | <mat-form-field floatLabel="always" hideRequiredMarker fxFlex="40" class="mat-block"> |
20 | <mat-label></mat-label> | 20 | <mat-label></mat-label> |
21 | <mat-select required formControlName="operation" placeholder="{{'filter.operation.operation' | translate}}"> | 21 | <mat-select required formControlName="operation" placeholder="{{'filter.operation.operation' | translate}}"> |
@@ -24,7 +24,8 @@ | @@ -24,7 +24,8 @@ | ||
24 | </mat-option> | 24 | </mat-option> |
25 | </mat-select> | 25 | </mat-select> |
26 | </mat-form-field> | 26 | </mat-form-field> |
27 | - <mat-checkbox fxFlex="60" formControlName="value"> | ||
28 | - {{ (booleanFilterPredicateFormGroup.get('value').value ? 'value.true' : 'value.false') | translate }} | ||
29 | - </mat-checkbox> | 27 | + <tb-filter-predicate-value fxFlex="60" |
28 | + [valueType]="valueTypeEnum.BOOLEAN" | ||
29 | + formControlName="value"> | ||
30 | + </tb-filter-predicate-value> | ||
30 | </div> | 31 | </div> |
@@ -18,10 +18,10 @@ import { Component, forwardRef, Input, OnInit } from '@angular/core'; | @@ -18,10 +18,10 @@ import { Component, forwardRef, Input, OnInit } from '@angular/core'; | ||
18 | import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; | 18 | import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; |
19 | import { | 19 | import { |
20 | BooleanFilterPredicate, | 20 | BooleanFilterPredicate, |
21 | - BooleanOperation, booleanOperationTranslationMap, | 21 | + BooleanOperation, |
22 | + booleanOperationTranslationMap, EntityKeyValueType, | ||
22 | FilterPredicateType | 23 | FilterPredicateType |
23 | } from '@shared/models/query/query.models'; | 24 | } from '@shared/models/query/query.models'; |
24 | -import { isDefined } from '@core/utils'; | ||
25 | 25 | ||
26 | @Component({ | 26 | @Component({ |
27 | selector: 'tb-boolean-filter-predicate', | 27 | selector: 'tb-boolean-filter-predicate', |
@@ -39,6 +39,8 @@ export class BooleanFilterPredicateComponent implements ControlValueAccessor, On | @@ -39,6 +39,8 @@ export class BooleanFilterPredicateComponent implements ControlValueAccessor, On | ||
39 | 39 | ||
40 | @Input() disabled: boolean; | 40 | @Input() disabled: boolean; |
41 | 41 | ||
42 | + valueTypeEnum = EntityKeyValueType; | ||
43 | + | ||
42 | booleanFilterPredicateFormGroup: FormGroup; | 44 | booleanFilterPredicateFormGroup: FormGroup; |
43 | 45 | ||
44 | booleanOperations = Object.keys(BooleanOperation); | 46 | booleanOperations = Object.keys(BooleanOperation); |
@@ -53,7 +55,7 @@ export class BooleanFilterPredicateComponent implements ControlValueAccessor, On | @@ -53,7 +55,7 @@ export class BooleanFilterPredicateComponent implements ControlValueAccessor, On | ||
53 | ngOnInit(): void { | 55 | ngOnInit(): void { |
54 | this.booleanFilterPredicateFormGroup = this.fb.group({ | 56 | this.booleanFilterPredicateFormGroup = this.fb.group({ |
55 | operation: [BooleanOperation.EQUAL, [Validators.required]], | 57 | operation: [BooleanOperation.EQUAL, [Validators.required]], |
56 | - value: [false] | 58 | + value: [null, [Validators.required]] |
57 | }); | 59 | }); |
58 | this.booleanFilterPredicateFormGroup.valueChanges.subscribe(() => { | 60 | this.booleanFilterPredicateFormGroup.valueChanges.subscribe(() => { |
59 | this.updateModel(); | 61 | this.updateModel(); |
@@ -78,16 +80,13 @@ export class BooleanFilterPredicateComponent implements ControlValueAccessor, On | @@ -78,16 +80,13 @@ export class BooleanFilterPredicateComponent implements ControlValueAccessor, On | ||
78 | 80 | ||
79 | writeValue(predicate: BooleanFilterPredicate): void { | 81 | writeValue(predicate: BooleanFilterPredicate): void { |
80 | this.booleanFilterPredicateFormGroup.get('operation').patchValue(predicate.operation, {emitEvent: false}); | 82 | this.booleanFilterPredicateFormGroup.get('operation').patchValue(predicate.operation, {emitEvent: false}); |
81 | - this.booleanFilterPredicateFormGroup.get('value').patchValue(isDefined(predicate.value) ? predicate.value : false, {emitEvent: false}); | 83 | + this.booleanFilterPredicateFormGroup.get('value').patchValue(predicate.value, {emitEvent: false}); |
82 | } | 84 | } |
83 | 85 | ||
84 | private updateModel() { | 86 | private updateModel() { |
85 | let predicate: BooleanFilterPredicate = null; | 87 | let predicate: BooleanFilterPredicate = null; |
86 | if (this.booleanFilterPredicateFormGroup.valid) { | 88 | if (this.booleanFilterPredicateFormGroup.valid) { |
87 | predicate = this.booleanFilterPredicateFormGroup.getRawValue(); | 89 | predicate = this.booleanFilterPredicateFormGroup.getRawValue(); |
88 | - if (!isDefined(predicate.value)) { | ||
89 | - predicate.value = false; | ||
90 | - } | ||
91 | predicate.type = FilterPredicateType.BOOLEAN; | 90 | predicate.type = FilterPredicateType.BOOLEAN; |
92 | } | 91 | } |
93 | this.propagateChange(predicate); | 92 | this.propagateChange(predicate); |
@@ -39,7 +39,7 @@ | @@ -39,7 +39,7 @@ | ||
39 | </div> | 39 | </div> |
40 | <mat-divider></mat-divider> | 40 | <mat-divider></mat-divider> |
41 | <div class="predicate-list"> | 41 | <div class="predicate-list"> |
42 | - <div fxLayout="row" fxLayoutAlign="start center" style="height: 40px;" | 42 | + <div fxLayout="row" fxLayoutAlign="start center" style="height: 45px;" |
43 | formArrayName="predicates" | 43 | formArrayName="predicates" |
44 | *ngFor="let predicateControl of predicatesFormArray().controls; let $index = index"> | 44 | *ngFor="let predicateControl of predicatesFormArray().controls; let $index = index"> |
45 | <div fxFlex="8" fxLayout="row" fxLayoutAlign="center" class="filters-operation"> | 45 | <div fxFlex="8" fxLayout="row" fxLayoutAlign="center" class="filters-operation"> |
1 | +<!-- | ||
2 | + | ||
3 | + Copyright © 2016-2020 The Thingsboard Authors | ||
4 | + | ||
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | + you may not use this file except in compliance with the License. | ||
7 | + You may obtain a copy of the License at | ||
8 | + | ||
9 | + http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | + | ||
11 | + Unless required by applicable law or agreed to in writing, software | ||
12 | + distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | + See the License for the specific language governing permissions and | ||
15 | + limitations under the License. | ||
16 | + | ||
17 | +--> | ||
18 | +<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px" [formGroup]="filterPredicateValueFormGroup"> | ||
19 | + <div fxFlex fxLayout="column"> | ||
20 | + <div fxFlex fxLayout="column" [ngSwitch]="valueType"> | ||
21 | + <ng-template [ngSwitchCase]="valueTypeEnum.STRING"> | ||
22 | + <mat-form-field floatLabel="always" hideRequiredMarker fxFlex class="mat-block"> | ||
23 | + <mat-label></mat-label> | ||
24 | + <input matInput formControlName="defaultValue" placeholder="{{'filter.value' | translate}}"> | ||
25 | + </mat-form-field> | ||
26 | + </ng-template> | ||
27 | + <ng-template [ngSwitchCase]="valueTypeEnum.NUMERIC"> | ||
28 | + <mat-form-field floatLabel="always" hideRequiredMarker fxFlex class="mat-block"> | ||
29 | + <mat-label></mat-label> | ||
30 | + <input required type="number" matInput formControlName="defaultValue" | ||
31 | + placeholder="{{'filter.value' | translate}}"> | ||
32 | + </mat-form-field> | ||
33 | + </ng-template> | ||
34 | + <ng-template [ngSwitchCase]="valueTypeEnum.DATE_TIME"> | ||
35 | + <tb-datetime fxFlex formControlName="defaultValue" | ||
36 | + dateText="filter.date" | ||
37 | + timeText="filter.time" | ||
38 | + required [showLabel]="false"></tb-datetime> | ||
39 | + </ng-template> | ||
40 | + <ng-template [ngSwitchCase]="valueTypeEnum.BOOLEAN"> | ||
41 | + <mat-checkbox fxFlex formControlName="defaultValue"> | ||
42 | + {{ (filterPredicateValueFormGroup.get('defaultValue').value ? 'value.true' : 'value.false') | translate }} | ||
43 | + </mat-checkbox> | ||
44 | + </ng-template> | ||
45 | + </div> | ||
46 | + <div class="tb-hint">Default value</div> | ||
47 | + </div> | ||
48 | +</div> |
1 | +/// | ||
2 | +/// Copyright © 2016-2020 The Thingsboard Authors | ||
3 | +/// | ||
4 | +/// Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | +/// you may not use this file except in compliance with the License. | ||
6 | +/// You may obtain a copy of the License at | ||
7 | +/// | ||
8 | +/// http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | +/// | ||
10 | +/// Unless required by applicable law or agreed to in writing, software | ||
11 | +/// distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | +/// See the License for the specific language governing permissions and | ||
14 | +/// limitations under the License. | ||
15 | +/// | ||
16 | + | ||
17 | +import { Component, forwardRef, Input, OnInit } from '@angular/core'; | ||
18 | +import { | ||
19 | + ControlValueAccessor, | ||
20 | + FormBuilder, | ||
21 | + FormGroup, | ||
22 | + NG_VALUE_ACCESSOR, | ||
23 | + ValidatorFn, | ||
24 | + Validators | ||
25 | +} from '@angular/forms'; | ||
26 | +import { EntityKeyValueType, FilterPredicateValue } from '@shared/models/query/query.models'; | ||
27 | + | ||
28 | +@Component({ | ||
29 | + selector: 'tb-filter-predicate-value', | ||
30 | + templateUrl: './filter-predicate-value.component.html', | ||
31 | + styleUrls: ['./filter-predicate.scss'], | ||
32 | + providers: [ | ||
33 | + { | ||
34 | + provide: NG_VALUE_ACCESSOR, | ||
35 | + useExisting: forwardRef(() => FilterPredicateValueComponent), | ||
36 | + multi: true | ||
37 | + } | ||
38 | + ] | ||
39 | +}) | ||
40 | +export class FilterPredicateValueComponent implements ControlValueAccessor, OnInit { | ||
41 | + | ||
42 | + @Input() disabled: boolean; | ||
43 | + | ||
44 | + @Input() | ||
45 | + valueType: EntityKeyValueType; | ||
46 | + | ||
47 | + valueTypeEnum = EntityKeyValueType; | ||
48 | + | ||
49 | + filterPredicateValueFormGroup: FormGroup; | ||
50 | + | ||
51 | + private propagateChange = null; | ||
52 | + | ||
53 | + constructor(private fb: FormBuilder) { | ||
54 | + } | ||
55 | + | ||
56 | + ngOnInit(): void { | ||
57 | + let defaultValue: string | number | boolean; | ||
58 | + let defaultValueValidators: ValidatorFn[]; | ||
59 | + switch (this.valueType) { | ||
60 | + case EntityKeyValueType.STRING: | ||
61 | + defaultValue = ''; | ||
62 | + defaultValueValidators = []; | ||
63 | + break; | ||
64 | + case EntityKeyValueType.NUMERIC: | ||
65 | + defaultValue = 0; | ||
66 | + defaultValueValidators = [Validators.required]; | ||
67 | + break; | ||
68 | + case EntityKeyValueType.BOOLEAN: | ||
69 | + defaultValue = false; | ||
70 | + defaultValueValidators = []; | ||
71 | + break; | ||
72 | + case EntityKeyValueType.DATE_TIME: | ||
73 | + defaultValue = Date.now(); | ||
74 | + defaultValueValidators = [Validators.required]; | ||
75 | + break; | ||
76 | + } | ||
77 | + this.filterPredicateValueFormGroup = this.fb.group({ | ||
78 | + defaultValue: [defaultValue, defaultValueValidators], | ||
79 | + dynamicValue: this.fb.group( | ||
80 | + { | ||
81 | + sourceType: [null], | ||
82 | + sourceAttribute: [null] | ||
83 | + } | ||
84 | + ) | ||
85 | + }); | ||
86 | + this.filterPredicateValueFormGroup.valueChanges.subscribe(() => { | ||
87 | + this.updateModel(); | ||
88 | + }); | ||
89 | + } | ||
90 | + | ||
91 | + registerOnChange(fn: any): void { | ||
92 | + this.propagateChange = fn; | ||
93 | + } | ||
94 | + | ||
95 | + registerOnTouched(fn: any): void { | ||
96 | + } | ||
97 | + | ||
98 | + setDisabledState?(isDisabled: boolean): void { | ||
99 | + this.disabled = isDisabled; | ||
100 | + if (this.disabled) { | ||
101 | + this.filterPredicateValueFormGroup.disable({emitEvent: false}); | ||
102 | + } else { | ||
103 | + this.filterPredicateValueFormGroup.enable({emitEvent: false}); | ||
104 | + } | ||
105 | + } | ||
106 | + | ||
107 | + writeValue(predicateValue: FilterPredicateValue<string | number | boolean>): void { | ||
108 | + this.filterPredicateValueFormGroup.get('defaultValue').patchValue(predicateValue.defaultValue, {emitEvent: false}); | ||
109 | + this.filterPredicateValueFormGroup.get('dynamicValue').patchValue(predicateValue.dynamicValue ? | ||
110 | + predicateValue.dynamicValue : { sourceType: null, sourceAttribute: null }, {emitEvent: false}); | ||
111 | + } | ||
112 | + | ||
113 | + private updateModel() { | ||
114 | + let predicateValue: FilterPredicateValue<string | number | boolean> = null; | ||
115 | + if (this.filterPredicateValueFormGroup.valid) { | ||
116 | + predicateValue = this.filterPredicateValueFormGroup.getRawValue(); | ||
117 | + if (predicateValue.dynamicValue) { | ||
118 | + if (!predicateValue.dynamicValue.sourceType || !predicateValue.dynamicValue.sourceAttribute) { | ||
119 | + predicateValue.dynamicValue = null; | ||
120 | + } | ||
121 | + } | ||
122 | + } | ||
123 | + this.propagateChange(predicateValue); | ||
124 | + } | ||
125 | + | ||
126 | +} |
@@ -13,6 +13,13 @@ | @@ -13,6 +13,13 @@ | ||
13 | * See the License for the specific language governing permissions and | 13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | + | ||
17 | +:host { | ||
18 | + .tb-hint { | ||
19 | + padding-bottom: 0; | ||
20 | + } | ||
21 | +} | ||
22 | + | ||
16 | :host ::ng-deep { | 23 | :host ::ng-deep { |
17 | mat-form-field { | 24 | mat-form-field { |
18 | .mat-form-field-wrapper { | 25 | .mat-form-field-wrapper { |
@@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
15 | limitations under the License. | 15 | limitations under the License. |
16 | 16 | ||
17 | --> | 17 | --> |
18 | -<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px" [formGroup]="numericFilterPredicateFormGroup"> | 18 | +<div fxFlex fxLayout="row" fxLayoutAlign="start start" fxLayoutGap="8px" [formGroup]="numericFilterPredicateFormGroup"> |
19 | <mat-form-field floatLabel="always" hideRequiredMarker fxFlex="40" class="mat-block"> | 19 | <mat-form-field floatLabel="always" hideRequiredMarker fxFlex="40" class="mat-block"> |
20 | <mat-label></mat-label> | 20 | <mat-label></mat-label> |
21 | <mat-select required formControlName="operation" placeholder="{{'filter.operation.operation' | translate}}"> | 21 | <mat-select required formControlName="operation" placeholder="{{'filter.operation.operation' | translate}}"> |
@@ -24,19 +24,8 @@ | @@ -24,19 +24,8 @@ | ||
24 | </mat-option> | 24 | </mat-option> |
25 | </mat-select> | 25 | </mat-select> |
26 | </mat-form-field> | 26 | </mat-form-field> |
27 | - <div fxFlex="60" fxLayout="column" [ngSwitch]="valueType"> | ||
28 | - <ng-template [ngSwitchCase]="valueTypeEnum.NUMERIC"> | ||
29 | - <mat-form-field floatLabel="always" hideRequiredMarker fxFlex class="mat-block"> | ||
30 | - <mat-label></mat-label> | ||
31 | - <input required type="number" matInput formControlName="value" | ||
32 | - placeholder="{{'filter.value' | translate}}"> | ||
33 | - </mat-form-field> | ||
34 | - </ng-template> | ||
35 | - <ng-template [ngSwitchCase]="valueTypeEnum.DATE_TIME"> | ||
36 | - <tb-datetime fxFlex formControlName="value" | ||
37 | - dateText="filter.date" | ||
38 | - timeText="filter.time" | ||
39 | - required [showLabel]="false"></tb-datetime> | ||
40 | - </ng-template> | ||
41 | - </div> | 27 | + <tb-filter-predicate-value fxFlex="60" |
28 | + [valueType]="valueType" | ||
29 | + formControlName="value"> | ||
30 | + </tb-filter-predicate-value> | ||
42 | </div> | 31 | </div> |
@@ -18,9 +18,11 @@ import { Component, forwardRef, Input, OnInit } from '@angular/core'; | @@ -18,9 +18,11 @@ import { Component, forwardRef, Input, OnInit } from '@angular/core'; | ||
18 | import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; | 18 | import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; |
19 | import { | 19 | import { |
20 | EntityKeyValueType, | 20 | EntityKeyValueType, |
21 | - FilterPredicateType, NumericFilterPredicate, NumericOperation, numericOperationTranslationMap, | 21 | + FilterPredicateType, |
22 | + NumericFilterPredicate, | ||
23 | + NumericOperation, | ||
24 | + numericOperationTranslationMap, | ||
22 | } from '@shared/models/query/query.models'; | 25 | } from '@shared/models/query/query.models'; |
23 | -import { isDefined } from '@core/utils'; | ||
24 | 26 | ||
25 | @Component({ | 27 | @Component({ |
26 | selector: 'tb-numeric-filter-predicate', | 28 | selector: 'tb-numeric-filter-predicate', |
@@ -56,7 +58,7 @@ export class NumericFilterPredicateComponent implements ControlValueAccessor, On | @@ -56,7 +58,7 @@ export class NumericFilterPredicateComponent implements ControlValueAccessor, On | ||
56 | ngOnInit(): void { | 58 | ngOnInit(): void { |
57 | this.numericFilterPredicateFormGroup = this.fb.group({ | 59 | this.numericFilterPredicateFormGroup = this.fb.group({ |
58 | operation: [NumericOperation.EQUAL, [Validators.required]], | 60 | operation: [NumericOperation.EQUAL, [Validators.required]], |
59 | - value: [0, [Validators.required]] | 61 | + value: [null, [Validators.required]] |
60 | }); | 62 | }); |
61 | this.numericFilterPredicateFormGroup.valueChanges.subscribe(() => { | 63 | this.numericFilterPredicateFormGroup.valueChanges.subscribe(() => { |
62 | this.updateModel(); | 64 | this.updateModel(); |
@@ -81,16 +83,13 @@ export class NumericFilterPredicateComponent implements ControlValueAccessor, On | @@ -81,16 +83,13 @@ export class NumericFilterPredicateComponent implements ControlValueAccessor, On | ||
81 | 83 | ||
82 | writeValue(predicate: NumericFilterPredicate): void { | 84 | writeValue(predicate: NumericFilterPredicate): void { |
83 | this.numericFilterPredicateFormGroup.get('operation').patchValue(predicate.operation, {emitEvent: false}); | 85 | this.numericFilterPredicateFormGroup.get('operation').patchValue(predicate.operation, {emitEvent: false}); |
84 | - this.numericFilterPredicateFormGroup.get('value').patchValue(isDefined(predicate.value) ? predicate.value : 0, {emitEvent: false}); | 86 | + this.numericFilterPredicateFormGroup.get('value').patchValue(predicate.value, {emitEvent: false}); |
85 | } | 87 | } |
86 | 88 | ||
87 | private updateModel() { | 89 | private updateModel() { |
88 | let predicate: NumericFilterPredicate = null; | 90 | let predicate: NumericFilterPredicate = null; |
89 | if (this.numericFilterPredicateFormGroup.valid) { | 91 | if (this.numericFilterPredicateFormGroup.valid) { |
90 | predicate = this.numericFilterPredicateFormGroup.getRawValue(); | 92 | predicate = this.numericFilterPredicateFormGroup.getRawValue(); |
91 | - if (!predicate.value) { | ||
92 | - predicate.value = 0; | ||
93 | - } | ||
94 | predicate.type = FilterPredicateType.NUMERIC; | 93 | predicate.type = FilterPredicateType.NUMERIC; |
95 | } | 94 | } |
96 | this.propagateChange(predicate); | 95 | this.propagateChange(predicate); |
@@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
15 | limitations under the License. | 15 | limitations under the License. |
16 | 16 | ||
17 | --> | 17 | --> |
18 | -<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px" [formGroup]="stringFilterPredicateFormGroup"> | 18 | +<div fxFlex fxLayout="row" fxLayoutAlign="start start" fxLayoutGap="8px" [formGroup]="stringFilterPredicateFormGroup"> |
19 | <div fxFlex="40" fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px"> | 19 | <div fxFlex="40" fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px"> |
20 | <mat-form-field floatLabel="always" hideRequiredMarker fxFlex class="mat-block"> | 20 | <mat-form-field floatLabel="always" hideRequiredMarker fxFlex class="mat-block"> |
21 | <mat-label></mat-label> | 21 | <mat-label></mat-label> |
@@ -28,8 +28,8 @@ | @@ -28,8 +28,8 @@ | ||
28 | <mat-checkbox fxLayout="row" fxLayoutAlign="center" formControlName="ignoreCase" style="min-width: 70px;"> | 28 | <mat-checkbox fxLayout="row" fxLayoutAlign="center" formControlName="ignoreCase" style="min-width: 70px;"> |
29 | </mat-checkbox> | 29 | </mat-checkbox> |
30 | </div> | 30 | </div> |
31 | - <mat-form-field floatLabel="always" hideRequiredMarker fxFlex="60" class="mat-block"> | ||
32 | - <mat-label></mat-label> | ||
33 | - <input matInput formControlName="value" placeholder="{{'filter.value' | translate}}"> | ||
34 | - </mat-form-field> | 31 | + <tb-filter-predicate-value fxFlex="60" |
32 | + [valueType]="valueTypeEnum.STRING" | ||
33 | + formControlName="value"> | ||
34 | + </tb-filter-predicate-value> | ||
35 | </div> | 35 | </div> |
@@ -17,6 +17,7 @@ | @@ -17,6 +17,7 @@ | ||
17 | import { Component, forwardRef, Input, OnInit } from '@angular/core'; | 17 | import { Component, forwardRef, Input, OnInit } from '@angular/core'; |
18 | import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; | 18 | import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; |
19 | import { | 19 | import { |
20 | + EntityKeyValueType, | ||
20 | FilterPredicateType, | 21 | FilterPredicateType, |
21 | StringFilterPredicate, | 22 | StringFilterPredicate, |
22 | StringOperation, | 23 | StringOperation, |
@@ -39,6 +40,8 @@ export class StringFilterPredicateComponent implements ControlValueAccessor, OnI | @@ -39,6 +40,8 @@ export class StringFilterPredicateComponent implements ControlValueAccessor, OnI | ||
39 | 40 | ||
40 | @Input() disabled: boolean; | 41 | @Input() disabled: boolean; |
41 | 42 | ||
43 | + valueTypeEnum = EntityKeyValueType; | ||
44 | + | ||
42 | stringFilterPredicateFormGroup: FormGroup; | 45 | stringFilterPredicateFormGroup: FormGroup; |
43 | 46 | ||
44 | stringOperations = Object.keys(StringOperation); | 47 | stringOperations = Object.keys(StringOperation); |
@@ -53,7 +56,7 @@ export class StringFilterPredicateComponent implements ControlValueAccessor, OnI | @@ -53,7 +56,7 @@ export class StringFilterPredicateComponent implements ControlValueAccessor, OnI | ||
53 | ngOnInit(): void { | 56 | ngOnInit(): void { |
54 | this.stringFilterPredicateFormGroup = this.fb.group({ | 57 | this.stringFilterPredicateFormGroup = this.fb.group({ |
55 | operation: [StringOperation.STARTS_WITH, [Validators.required]], | 58 | operation: [StringOperation.STARTS_WITH, [Validators.required]], |
56 | - value: [''], | 59 | + value: [null, [Validators.required]], |
57 | ignoreCase: [false] | 60 | ignoreCase: [false] |
58 | }); | 61 | }); |
59 | this.stringFilterPredicateFormGroup.valueChanges.subscribe(() => { | 62 | this.stringFilterPredicateFormGroup.valueChanges.subscribe(() => { |
@@ -79,7 +82,7 @@ export class StringFilterPredicateComponent implements ControlValueAccessor, OnI | @@ -79,7 +82,7 @@ export class StringFilterPredicateComponent implements ControlValueAccessor, OnI | ||
79 | 82 | ||
80 | writeValue(predicate: StringFilterPredicate): void { | 83 | writeValue(predicate: StringFilterPredicate): void { |
81 | this.stringFilterPredicateFormGroup.get('operation').patchValue(predicate.operation, {emitEvent: false}); | 84 | this.stringFilterPredicateFormGroup.get('operation').patchValue(predicate.operation, {emitEvent: false}); |
82 | - this.stringFilterPredicateFormGroup.get('value').patchValue(predicate.value ? predicate.value : '', {emitEvent: false}); | 85 | + this.stringFilterPredicateFormGroup.get('value').patchValue(predicate.value, {emitEvent: false}); |
83 | this.stringFilterPredicateFormGroup.get('ignoreCase').patchValue(predicate.ignoreCase, {emitEvent: false}); | 86 | this.stringFilterPredicateFormGroup.get('ignoreCase').patchValue(predicate.ignoreCase, {emitEvent: false}); |
84 | } | 87 | } |
85 | 88 | ||
@@ -87,9 +90,6 @@ export class StringFilterPredicateComponent implements ControlValueAccessor, OnI | @@ -87,9 +90,6 @@ export class StringFilterPredicateComponent implements ControlValueAccessor, OnI | ||
87 | let predicate: StringFilterPredicate = null; | 90 | let predicate: StringFilterPredicate = null; |
88 | if (this.stringFilterPredicateFormGroup.valid) { | 91 | if (this.stringFilterPredicateFormGroup.valid) { |
89 | predicate = this.stringFilterPredicateFormGroup.getRawValue(); | 92 | predicate = this.stringFilterPredicateFormGroup.getRawValue(); |
90 | - if (!predicate.value) { | ||
91 | - predicate.value = ''; | ||
92 | - } | ||
93 | predicate.type = FilterPredicateType.STRING; | 93 | predicate.type = FilterPredicateType.STRING; |
94 | } | 94 | } |
95 | this.propagateChange(predicate); | 95 | this.propagateChange(predicate); |
@@ -84,12 +84,12 @@ export class UserFilterDialogComponent extends DialogComponent<UserFilterDialogC | @@ -84,12 +84,12 @@ export class UserFilterDialogComponent extends DialogComponent<UserFilterDialogC | ||
84 | const userInputControl = this.fb.group({ | 84 | const userInputControl = this.fb.group({ |
85 | label: [userInput.label], | 85 | label: [userInput.label], |
86 | valueType: [userInput.valueType], | 86 | valueType: [userInput.valueType], |
87 | - value: [(userInput.info.keyFilterPredicate as any).value, | 87 | + value: [(userInput.info.keyFilterPredicate as any).value.defaultValue, |
88 | userInput.valueType === EntityKeyValueType.NUMERIC || | 88 | userInput.valueType === EntityKeyValueType.NUMERIC || |
89 | userInput.valueType === EntityKeyValueType.DATE_TIME ? [Validators.required] : []] | 89 | userInput.valueType === EntityKeyValueType.DATE_TIME ? [Validators.required] : []] |
90 | }); | 90 | }); |
91 | userInputControl.get('value').valueChanges.subscribe(value => { | 91 | userInputControl.get('value').valueChanges.subscribe(value => { |
92 | - (userInput.info.keyFilterPredicate as any).value = value; | 92 | + (userInput.info.keyFilterPredicate as any).value.defaultValue = value; |
93 | }); | 93 | }); |
94 | return userInputControl; | 94 | return userInputControl; |
95 | } | 95 | } |
@@ -83,6 +83,7 @@ import { FiltersEditPanelComponent } from '@home/components/filter/filters-edit- | @@ -83,6 +83,7 @@ import { FiltersEditPanelComponent } from '@home/components/filter/filters-edit- | ||
83 | import { UserFilterDialogComponent } from '@home/components/filter/user-filter-dialog.component'; | 83 | import { UserFilterDialogComponent } from '@home/components/filter/user-filter-dialog.component'; |
84 | import { FilterUserInfoComponent } from './filter/filter-user-info.component'; | 84 | import { FilterUserInfoComponent } from './filter/filter-user-info.component'; |
85 | import { FilterUserInfoDialogComponent } from './filter/filter-user-info-dialog.component'; | 85 | import { FilterUserInfoDialogComponent } from './filter/filter-user-info-dialog.component'; |
86 | +import { FilterPredicateValueComponent } from './filter/filter-predicate-value.component'; | ||
86 | 87 | ||
87 | @NgModule({ | 88 | @NgModule({ |
88 | declarations: | 89 | declarations: |
@@ -148,7 +149,8 @@ import { FilterUserInfoDialogComponent } from './filter/filter-user-info-dialog. | @@ -148,7 +149,8 @@ import { FilterUserInfoDialogComponent } from './filter/filter-user-info-dialog. | ||
148 | FiltersEditPanelComponent, | 149 | FiltersEditPanelComponent, |
149 | UserFilterDialogComponent, | 150 | UserFilterDialogComponent, |
150 | FilterUserInfoComponent, | 151 | FilterUserInfoComponent, |
151 | - FilterUserInfoDialogComponent | 152 | + FilterUserInfoDialogComponent, |
153 | + FilterPredicateValueComponent | ||
152 | ], | 154 | ], |
153 | imports: [ | 155 | imports: [ |
154 | CommonModule, | 156 | CommonModule, |
@@ -138,16 +138,22 @@ export function createDefaultFilterPredicate(valueType: EntityKeyValueType, comp | @@ -138,16 +138,22 @@ export function createDefaultFilterPredicate(valueType: EntityKeyValueType, comp | ||
138 | switch (predicate.type) { | 138 | switch (predicate.type) { |
139 | case FilterPredicateType.STRING: | 139 | case FilterPredicateType.STRING: |
140 | predicate.operation = StringOperation.STARTS_WITH; | 140 | predicate.operation = StringOperation.STARTS_WITH; |
141 | - predicate.value = ''; | 141 | + predicate.value = { |
142 | + defaultValue: '' | ||
143 | + }; | ||
142 | predicate.ignoreCase = false; | 144 | predicate.ignoreCase = false; |
143 | break; | 145 | break; |
144 | case FilterPredicateType.NUMERIC: | 146 | case FilterPredicateType.NUMERIC: |
145 | predicate.operation = NumericOperation.EQUAL; | 147 | predicate.operation = NumericOperation.EQUAL; |
146 | - predicate.value = valueType === EntityKeyValueType.DATE_TIME ? Date.now() : 0; | 148 | + predicate.value = { |
149 | + defaultValue: valueType === EntityKeyValueType.DATE_TIME ? Date.now() : 0 | ||
150 | + }; | ||
147 | break; | 151 | break; |
148 | case FilterPredicateType.BOOLEAN: | 152 | case FilterPredicateType.BOOLEAN: |
149 | predicate.operation = BooleanOperation.EQUAL; | 153 | predicate.operation = BooleanOperation.EQUAL; |
150 | - predicate.value = false; | 154 | + predicate.value = { |
155 | + defaultValue: false | ||
156 | + }; | ||
151 | break; | 157 | break; |
152 | case FilterPredicateType.COMPLEX: | 158 | case FilterPredicateType.COMPLEX: |
153 | predicate.operation = ComplexOperation.AND; | 159 | predicate.operation = ComplexOperation.AND; |
@@ -228,23 +234,47 @@ export const complexOperationTranslationMap = new Map<ComplexOperation, string>( | @@ -228,23 +234,47 @@ export const complexOperationTranslationMap = new Map<ComplexOperation, string>( | ||
228 | ] | 234 | ] |
229 | ); | 235 | ); |
230 | 236 | ||
237 | +export enum DynamicValueSourceType { | ||
238 | + CURRENT_TENANT = 'CURRENT_TENANT', | ||
239 | + CURRENT_CUSTOMER = 'CURRENT_CUSTOMER', | ||
240 | + CURRENT_USER = 'CURRENT_USER' | ||
241 | +} | ||
242 | + | ||
243 | +export const dynamicValueSourceTypeTranslationMap = new Map<DynamicValueSourceType, string>( | ||
244 | + [ | ||
245 | + [DynamicValueSourceType.CURRENT_TENANT, 'filter.current-tenant'], | ||
246 | + [DynamicValueSourceType.CURRENT_CUSTOMER, 'filter.current-customer'], | ||
247 | + [DynamicValueSourceType.CURRENT_USER, 'filter.current-user'] | ||
248 | + ] | ||
249 | +); | ||
250 | + | ||
251 | +export interface DynamicValue<T> { | ||
252 | + sourceType: DynamicValueSourceType; | ||
253 | + sourceAttribute: string; | ||
254 | +} | ||
255 | + | ||
256 | +export interface FilterPredicateValue<T> { | ||
257 | + defaultValue: T; | ||
258 | + dynamicValue?: DynamicValue<T>; | ||
259 | +} | ||
260 | + | ||
231 | export interface StringFilterPredicate { | 261 | export interface StringFilterPredicate { |
232 | type: FilterPredicateType.STRING, | 262 | type: FilterPredicateType.STRING, |
233 | operation: StringOperation; | 263 | operation: StringOperation; |
234 | - value: string; | 264 | + value: FilterPredicateValue<string>; |
235 | ignoreCase: boolean; | 265 | ignoreCase: boolean; |
236 | } | 266 | } |
237 | 267 | ||
238 | export interface NumericFilterPredicate { | 268 | export interface NumericFilterPredicate { |
239 | type: FilterPredicateType.NUMERIC, | 269 | type: FilterPredicateType.NUMERIC, |
240 | operation: NumericOperation; | 270 | operation: NumericOperation; |
241 | - value: number; | 271 | + value: FilterPredicateValue<number>; |
242 | } | 272 | } |
243 | 273 | ||
244 | export interface BooleanFilterPredicate { | 274 | export interface BooleanFilterPredicate { |
245 | type: FilterPredicateType.BOOLEAN, | 275 | type: FilterPredicateType.BOOLEAN, |
246 | operation: BooleanOperation; | 276 | operation: BooleanOperation; |
247 | - value: boolean; | 277 | + value: FilterPredicateValue<boolean>; |
248 | } | 278 | } |
249 | 279 | ||
250 | export interface BaseComplexFilterPredicate<T extends KeyFilterPredicate | KeyFilterPredicateInfo> { | 280 | export interface BaseComplexFilterPredicate<T extends KeyFilterPredicate | KeyFilterPredicateInfo> { |
@@ -1227,7 +1227,10 @@ | @@ -1227,7 +1227,10 @@ | ||
1227 | "remove-key-filter": "Remove key filter", | 1227 | "remove-key-filter": "Remove key filter", |
1228 | "edit-key-filter": "Edit key filter", | 1228 | "edit-key-filter": "Edit key filter", |
1229 | "date": "Date", | 1229 | "date": "Date", |
1230 | - "time": "Time" | 1230 | + "time": "Time", |
1231 | + "current-tenant": "Current tenant", | ||
1232 | + "current-customer": "Current customer", | ||
1233 | + "current-user": "Current user" | ||
1231 | }, | 1234 | }, |
1232 | "fullscreen": { | 1235 | "fullscreen": { |
1233 | "expand": "Expand to fullscreen", | 1236 | "expand": "Expand to fullscreen", |