Skip to content

Commit

Permalink
geosolutions-it#9706: resolve review comments
Browse files Browse the repository at this point in the history
Desciption:
- remove expression from filter inputs and make validation for the inputs
- Add cursor style to 'Start' & 'End' tabs
- Add validation for  ranges
- Replace 2 icons with one icon for date-time filter
- Fix style issues
- Fixed 'Start', 'End' tabs in scroll
- improve style of operator
- reset date/time if user change operator from range operator to another
  • Loading branch information
mahmoudadel54 committed Dec 1, 2023
1 parent 2bec670 commit d8d1ae8
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ class AttributeFilter extends React.PureComponent {
booleanOperators: ["="],
defaultOperators: ["=", ">", "<", ">=", "<=", "<>", "isNull"],
timeDateOperators: ["=", ">", "<", ">=", "<=", "<>", "><", "isNull"],
operator: this.props.isWithinAttrTbl ? "=" : ""
operator: this.props.isWithinAttrTbl ? "=" : "",
isInputValid: true
};
}
getOperator = (type) => {
Expand Down Expand Up @@ -86,12 +87,12 @@ class AttributeFilter extends React.PureComponent {
let isValueExist = this.state?.value ?? this.props.value;
if (['date', 'time', 'date-time'].includes(this.props.type)) isValueExist = this.state?.value ?? this.props.value?.startDate ?? this.props.value;
let isNullOperator = this.state.operator === 'isNull';
return (<div className="rw-widget">
return (<div className={`rw-widget ${this.state.isInputValid ? "" : "show-error"}`}>
<input
disabled={this.props.disabled || isNullOperator}
key={inputKey}
type="text"
className="form-control input-sm"
className={"form-control input-sm"}
placeholder={placeholder}
value={isValueExist}
onChange={this.handleChange}/>
Expand All @@ -108,19 +109,33 @@ class AttributeFilter extends React.PureComponent {
renderOperatorField = () => {
return (
<ComboField
style={{ width: '30%'}}
// dropUp={this.props.dropUp}
style={{ width: '90px'}}
fieldOptions= {this.getOperator(this.props.type)}
fieldName="operator"
fieldRowId={1}
onSelect={(selectedOperator)=>{
// if select the same operator -> don't do anything
if (selectedOperator === this.state.operator) return;
let isValueExist = this.state?.value ?? this.props.value;
if (['date', 'time', 'date-time'].includes(this.props.type)) isValueExist = this.state?.value ?? this.props.value?.startDate ?? this.props.value;
this.setState({ operator: selectedOperator, value: selectedOperator === 'isNull' ? undefined : isValueExist });
let isValueExist; // entered value
if (['date', 'time', 'date-time'].includes(this.props.type)) {
isValueExist = this.state?.value ?? this.props.value?.startDate ?? this.props.value;
} else {
isValueExist = this.state?.value ?? this.props.value;
}
let isNullOperatorSelected = selectedOperator === 'isNull';
let isOperatorChangedFromIsNullAndValueNotExist = this.state.operator === 'isNull' && this.state.operator !== selectedOperator && !isValueExist;
if (isValueExist || isNullOperatorSelected || isOperatorChangedFromIsNullAndValueNotExist ) this.props.onChange({value: isNullOperatorSelected ? null : isValueExist, attribute: this.props.column && this.props.column.key, inputOperator: selectedOperator});
let isOperatorChangedFromRange = this.state.operator === '><';
// set the selected operator + value and reset the value in case of isNull
this.setState({ operator: selectedOperator, value: (isNullOperatorSelected || isOperatorChangedFromRange) ? undefined : isValueExist });
// get flag of being (operator was isNull then changes to other operator)
let isOperatorChangedFromIsNull = this.state.operator === 'isNull' && selectedOperator !== 'isNull';
// apply filter if value exists 'OR' operator = isNull 'OR' (prev operator was isNull and changes --> reset filter)
if (isNullOperatorSelected || isOperatorChangedFromIsNull || isOperatorChangedFromRange) {
// reset data --> operator = isNull 'OR' (prev operator was isNull and changes)
this.props.onChange({value: null, attribute: this.props.column && this.props.column.key, inputOperator: selectedOperator});
} else if (isValueExist) {
// apply filter --> if value exists
this.props.onChange({value: isValueExist, attribute: this.props.column && this.props.column.key, inputOperator: selectedOperator});
}
}}
fieldValue={this.state.operator}
onUpdateField={() => {}}/>
Expand All @@ -129,16 +144,23 @@ class AttributeFilter extends React.PureComponent {
render() {
let inputKey = 'header-filter--' + this.props.column.key;
return (
<div key={inputKey} className={`form-group${(this.props.valid ? "" : " has-error")}`}>
<div key={inputKey} className={`form-group${((this.state.isInputValid && this.props.valid) ? "" : " has-error")}`}>
{this.props.isWithinAttrTbl ? this.renderOperatorField() : null}
{this.renderTooltip(this.renderInput())}
</div>
);
}
handleChange = (e) => {
const value = e.target.value;
this.setState({value});
this.props.onChange({value, attribute: this.props.column && this.props.column.key, inputOperator: this.state.operator});
// todo: validate input based on type
let isValid = true;
const match = /\s*(!==|!=|<>|<=|>=|===|==|=|<|>)?(.*)/.exec(value);
if (match[1]) isValid = false;
if (match[2]) {
if (['integer', 'number'].includes(this.props.type) && isNaN(match[2])) isValid = false;
}
this.setState({value, isInputValid: isValid});
if (isValid) this.props.onChange({value, attribute: this.props.column && this.props.column.key, inputOperator: this.state.operator});
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,17 @@ const EXPRESSION_TESTS = [
[" ", "=", undefined],
["ZZZ", "=", undefined]
];
const testExpression = (spyonChange, spyonValueChange, rawValue, expectedOperator, expectedValue) => {
const testExpression = (spyonChange, spyonValueChange, rawValue, expectedOperator, expectedValue, index) => {
const input = document.getElementsByTagName("input")[0];
input.value = rawValue;
ReactTestUtils.Simulate.change(input);
const args = spyonChange.calls[spyonChange.calls.length - 1].arguments[0];
const valueArgs = spyonValueChange.calls[spyonValueChange.calls.length - 1].arguments[0];
expect(args.value).toBe(expectedValue);
expect(args.operator).toBe(expectedOperator);
expect(valueArgs).toBe(rawValue);
const args = spyonChange.calls[index]?.arguments[0];
const valueArgs = spyonValueChange.calls[index]?.arguments[0];
if (valueArgs) { // in case of invalid number expression it will be undefined
expect(args.value).toBe(expectedValue);
expect(args.operator).toBe(expectedOperator);
expect(valueArgs).toBe(rawValue);
}
};

describe('Test for NumberFilter component', () => {
Expand Down Expand Up @@ -75,7 +77,7 @@ describe('Test for NumberFilter component', () => {
ReactDOM.render(<NumberFilter onChange={actions.onChange} />, document.getElementById("container"));

const input = document.getElementsByTagName("input")[0];
input.value = "> 2";
input.value = "2";
ReactTestUtils.Simulate.change(input);
expect(spyonChange).toHaveBeenCalled();
});
Expand Down Expand Up @@ -115,6 +117,6 @@ describe('Test for NumberFilter component', () => {
const spyonChange = expect.spyOn(actions, 'onChange');
const spyonValueChange = expect.spyOn(actions, 'onValueChange');
ReactDOM.render(<NumberFilter onChange={actions.onChange} onValueChange={actions.onValueChange} />, document.getElementById("container"));
EXPRESSION_TESTS.map( params => testExpression(spyonChange, spyonValueChange, ...params));
EXPRESSION_TESTS.map( (params, index) => testExpression(spyonChange, spyonValueChange, ...params, index));
});
});
Loading

0 comments on commit d8d1ae8

Please sign in to comment.