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