Skip to content

Commit

Permalink
#2972: Add autocomplete in cross layer filter (#6782)
Browse files Browse the repository at this point in the history
  • Loading branch information
MuhweziDeo authored May 6, 2021
1 parent 9eea54b commit ae25991
Show file tree
Hide file tree
Showing 13 changed files with 132 additions and 26 deletions.
27 changes: 27 additions & 0 deletions web/client/actions/__tests__/queryform-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,33 @@ describe('Test correctness of the queryform actions', () => {
expect(retval.status).toBe(status);
});

it('toggleMenu with layerFilterType undefined', () => {
let status = true;
let rowId = 100;

var retval = toggleMenu(rowId, status);

expect(retval).toExist();
expect(retval.type).toBe(TOGGLE_AUTOCOMPLETE_MENU);
expect(retval.rowId).toBe(rowId);
expect(retval.status).toBe(status);
expect(retval.layerFilterType).toBe("filterField");
});


it('toggleMenu with layerFilterType', () => {
let status = true;
let rowId = 100;

var retval = toggleMenu(rowId, status, "crossLayer");

expect(retval).toExist();
expect(retval.type).toBe(TOGGLE_AUTOCOMPLETE_MENU);
expect(retval.rowId).toBe(rowId);
expect(retval.status).toBe(status);
expect(retval.layerFilterType).toBe("crossLayer");
});

it('set autocomplete', () => {
let status = true;
var retval = setAutocompleteMode(status);
Expand Down
10 changes: 6 additions & 4 deletions web/client/actions/queryform.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,12 @@ export function removeFilterField(rowId) {
};
}

export function toggleMenu(rowId, status) {
export function toggleMenu(rowId, status, layerFilterType = "filterField") {
return {
type: TOGGLE_AUTOCOMPLETE_MENU,
rowId,
status
status,
layerFilterType
};
}

Expand Down Expand Up @@ -401,11 +402,12 @@ export function resetCrossLayerFilter() {
};
}

export function loadingFilterFieldOptions(status, filterField) {
export function loadingFilterFieldOptions(status, filterField, layerFilterType = "filterField") {
return {
type: LOADING_FILTER_FIELD_OPTIONS,
status,
filterField
filterField,
layerFilterType
};
}

Expand Down
2 changes: 2 additions & 0 deletions web/client/components/data/query/AutocompleteField.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import HTML from '../../../components/I18N/HTML';
*/
class AutocompleteField extends React.Component {
static propTypes = {
dropUp: PropTypes.bool,
disabled: PropTypes.bool,
filterField: PropTypes.object,
label: PropTypes.string,
Expand Down Expand Up @@ -109,6 +110,7 @@ class AutocompleteField extends React.Component {
const tooltip = (<Tooltip id={"autocompleteField-tooltip" + (this.props.filterField && this.props.filterField.rowId)}>
<HTML msgId="queryform.attributefilter.tooltipTextField"/></Tooltip>);
const field = (<Combobox
dropUp={this.props.dropUp}
busy={this.props.filterField.loading}
data={this.props.filterField.loading ? [] : options}
disabled={this.props.filterField.operator === "isNull"}
Expand Down
2 changes: 2 additions & 0 deletions web/client/components/data/query/AutocompleteFieldHOC.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import HTML from '../../../components/I18N/HTML';

class AutocompleteFieldHOC extends React.Component {
static propTypes = {
dropUp: PropTypes.bool,
disabled: PropTypes.bool,
filterField: PropTypes.object,
label: PropTypes.string,
Expand Down Expand Up @@ -97,6 +98,7 @@ class AutocompleteFieldHOC extends React.Component {
let options = this.getOptions() ? this.getOptions().slice(0) : [];

return (<PagedCombobox
dropUp={this.props.dropUp}
busy={this.props.filterField.loading}
data={this.props.filterField.loading ? [] : options}
disabled={this.props.filterField.operator === "isNull"}
Expand Down
3 changes: 3 additions & 0 deletions web/client/components/data/query/ComboField.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import Message from '../../../components/I18N/Message';

class ComboField extends React.Component {
static propTypes = {
dropUp: PropTypes.bool,
busy: PropTypes.bool,
style: PropTypes.object,
valueField: PropTypes.string,
Expand Down Expand Up @@ -97,6 +98,7 @@ class ComboField extends React.Component {

const list = this.props.valueField !== null && this.props.textField !== null ?
(<ListComponent
dropUp={this.props.dropUp}
{...this.props.options}
busy={this.props.busy}
disabled={this.props.disabled}
Expand All @@ -118,6 +120,7 @@ class ComboField extends React.Component {
onSearch={this.props.onSearch}/>)
:
(<ListComponent
dropUp={this.props.dropUp}
{...this.props.options}
busy={this.props.busy}
disabled={this.props.disabled}
Expand Down
7 changes: 5 additions & 2 deletions web/client/components/data/query/CrossLayerFilter.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ export default ({
setQueryCollectionParameter = () => {},
addCrossLayerFilterField = () => {},
updateCrossLayerFilterField = () => {},
removeCrossLayerFilterField = () => {}
removeCrossLayerFilterField = () => {},
toggleMenu = () => {}
} = {}) => {
const {typeName, geometryName, filterFields, groupFields = [{
id: 1,
Expand Down Expand Up @@ -115,6 +116,7 @@ export default ({
? (<Row className="filter-field-fixed-row">
<Col xs={12}>
<GroupField
dropUp
autocompleteEnabled
withContainer={false}
attributes={attributes}
Expand All @@ -124,7 +126,8 @@ export default ({
onUpdateLogicCombo: updateLogicCombo,
onAddFilterField: addCrossLayerFilterField,
onUpdateFilterField: updateCrossLayerFilterField,
onRemoveFilterField: removeCrossLayerFilterField
onRemoveFilterField: removeCrossLayerFilterField,
toggleMenu: toggleMenu
}}
groupFields={groupFields} filterField/>
</Col>
Expand Down
3 changes: 3 additions & 0 deletions web/client/components/data/query/FilterField.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { getMessageById } from '../../../utils/LocaleUtils';

class FilterField extends React.Component {
static propTypes = {
dropUp: PropTypes.bool,
attributes: PropTypes.array,
filterField: PropTypes.object,
operatorOptions: PropTypes.array,
Expand Down Expand Up @@ -42,6 +43,7 @@ class FilterField extends React.Component {
renderOperatorField = () => {
return (
<ComboField
dropUp={this.props.dropUp}
fieldOptions= {this.props.operatorOptions}
fieldName="operator"
fieldRowId={this.props.filterField.rowId}
Expand Down Expand Up @@ -77,6 +79,7 @@ class FilterField extends React.Component {
<div className="filter-field-row">
<div className="filter-field-attribute">
<ComboField
dropUp={this.props.dropUp}
valueField={'id'}
textField={'name'}
fieldOptions={this.props.attributes.map((attribute) => { return {id: attribute.attribute, name: attribute.label}; })}
Expand Down
8 changes: 7 additions & 1 deletion web/client/components/data/query/GroupField.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import Button from '../../misc/Button';

class GroupField extends React.Component {
static propTypes = {
dropUp: PropTypes.bool,
groupLevels: PropTypes.number,
withContainer: PropTypes.bool,
autocompleteEnabled: PropTypes.bool,
Expand All @@ -43,7 +44,8 @@ class GroupField extends React.Component {
listOperators: PropTypes.array,
stringOperators: PropTypes.array,
booleanOperators: PropTypes.array,
defaultOperators: PropTypes.array
defaultOperators: PropTypes.array,
comboOptions: PropTypes.object
};

static contextTypes = {
Expand Down Expand Up @@ -143,6 +145,7 @@ class GroupField extends React.Component {
</Button></OverlayTrigger>);
return (
<FilterField
dropUp={this.props.dropUp}
key={filterField.rowId}
deleteButton={deleteButton}
attributes={this.props.attributes}
Expand All @@ -154,6 +157,7 @@ class GroupField extends React.Component {
onUpdateExceptionField={this.props.actions.onUpdateExceptionField}
onChangeCascadingValue={this.props.actions.onChangeCascadingValue}>
<ComboField
dropUp={this.props.dropUp}
attType="list"
valueField={'id'}
textField={'name'}
Expand All @@ -180,6 +184,7 @@ class GroupField extends React.Component {
// flag to swtich from AutocompleteField to TextField
this.props.autocompleteEnabled ?
(<AutocompleteField
dropUp={this.props.dropUp}
filterField={filterField}
attType="string"/>) :
(<TextField
Expand All @@ -188,6 +193,7 @@ class GroupField extends React.Component {
}

<ComboField
dropUp={this.props.dropUp}
fieldOptions={['true', 'false']}
attType="boolean"
comboFilter={"contains"}/>
Expand Down
2 changes: 2 additions & 0 deletions web/client/components/data/query/SimpleFilterField.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { isEqual, head, findIndex } from 'lodash';

class SimpleFilterField extends React.Component {
static propTypes = {
dropUp: PropTypes.bool,
operator: PropTypes.string.isRequired,
maxLabelSize: PropTypes.number,
label: PropTypes.string,
Expand Down Expand Up @@ -226,6 +227,7 @@ class SimpleFilterField extends React.Component {
return (
<div>
<ComboField
dropUp={this.props.dropUp}
valueField="val"
textField="text"
style={this.props.comboStyle}
Expand Down
10 changes: 5 additions & 5 deletions web/client/epics/autocomplete.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,10 @@ export const fetchAutocompleteOptionsEpic = (action$, store) =>
).switchMap((res) => {
let newOptions = isArray(res.values) ? res.values : [res.values];
let valuesCount = res.size;
return Rx.Observable.from(action.type === UPDATE_CROSS_LAYER_FILTER_FIELD ? [updateCrossLayerFilterFieldOptions(filterField, newOptions, valuesCount), toggleMenu(action.rowId, true)] :
[updateFilterFieldOptions(filterField, newOptions, valuesCount), toggleMenu(action.rowId, true)] );
return Rx.Observable.from(action.type === UPDATE_CROSS_LAYER_FILTER_FIELD ? [updateCrossLayerFilterFieldOptions(filterField, newOptions, valuesCount), toggleMenu(action.rowId, true, "crossLayer")] :
[updateFilterFieldOptions(filterField, newOptions, valuesCount), toggleMenu(action.rowId, true, "filterField")] );
})
.startWith(loadingFilterFieldOptions(true, filterField))
.startWith(loadingFilterFieldOptions(true, filterField, action.type === UPDATE_CROSS_LAYER_FILTER_FIELD ? "crossLayer" : "filterField"))
.catch( () => {
// console.log("error: " + e + " data:" + e.data);
return Rx.Observable.from([
Expand All @@ -116,10 +116,10 @@ export const fetchAutocompleteOptionsEpic = (action$, store) =>
},
autoDismiss: 3,
position: "tr"
}), toggleMenu(action.rowId, true)
}), toggleMenu(action.rowId, true, action.type === UPDATE_CROSS_LAYER_FILTER_FIELD ? "crossLayer" : "filterField")
]);
})
.concat([loadingFilterFieldOptions(false, filterField)]);
.concat([loadingFilterFieldOptions(false, filterField, action.type === UPDATE_CROSS_LAYER_FILTER_FIELD ? "crossLayer" : "filterField")]);
});


Expand Down
3 changes: 2 additions & 1 deletion web/client/plugins/QueryPanel.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,8 @@ const SmartQueryForm = connect((state) => {
addCrossLayerFilterField,
updateCrossLayerFilterField,
removeCrossLayerFilterField,
resetCrossLayerFilter
resetCrossLayerFilter,
toggleMenu: (rowId, status) => toggleMenu(rowId, status, "crossLayer")
}, dispatch),
controlActions: bindActionCreators({onToggleQuery: toggleControl.bind(null, 'queryPanel', null)}, dispatch)
};
Expand Down
28 changes: 27 additions & 1 deletion web/client/reducers/__tests__/queryform-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -953,7 +953,8 @@ describe('Test the queryform reducer', () => {
let testAction = {
type: TOGGLE_AUTOCOMPLETE_MENU,
rowId: 100,
status: true
status: true,
"layerFilterType": "filterField"
};

let initialState = {
Expand All @@ -969,6 +970,31 @@ describe('Test the queryform reducer', () => {

expect(state.filterFields[0].openAutocompleteMenu).toBe(true);

});
it('toggle autocomplete mode crossLayerFilter', () => {
let testAction = {
type: TOGGLE_AUTOCOMPLETE_MENU,
rowId: 100,
status: true,
"layerFilterType": "crossLayer"
};

let initialState = {
openAutocompleteMenu: false,
crossLayerFilter: {collectGeometries: {
queryCollection: {
filterFields: [{
rowId: 100,
openAutocompleteMenu: false
}]
}
} }
};

let state = queryform(initialState, testAction);
expect(state).toExist();
expect(state.crossLayerFilter.collectGeometries.queryCollection.filterFields[0].openAutocompleteMenu).toBe(true);

});
it('toggle crosslayer', () => {
let action = expandCrossLayerFilterPanel(true);
Expand Down
53 changes: 41 additions & 12 deletions web/client/reducers/queryform.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,23 +140,52 @@ function queryform(state = initialState, action) {
})});
}
case TOGGLE_AUTOCOMPLETE_MENU: {
return assign({}, state, {filterFields: state.filterFields.map((field) => {
if (field.rowId === action.rowId) {
return assign({}, field, {openAutocompleteMenu: action.status} );
}
return field;
})});
if (action.layerFilterType === "filterField") {
return assign({}, state, {filterFields: state.filterFields.map((field) => {
if (field.rowId === action.rowId) {
return assign({}, field, {openAutocompleteMenu: action.status} );
}
return field;
})});
}
return set(
`crossLayerFilter.collectGeometries.queryCollection.filterFields`,
(get(state, 'crossLayerFilter.collectGeometries.queryCollection.filterFields') || [])
.map((field) => {
if (field.rowId === action.rowId) {
return {
...field,
openAutocompleteMenu: action.status
};
}
return field;
})
, state);
}
case SET_AUTOCOMPLETE_MODE: {
return assign({}, state, {autocompleteEnabled: action.status});
}
case LOADING_FILTER_FIELD_OPTIONS: {
return assign({}, state, {filterFields: state.filterFields.map((field) => {
if (field.rowId === action.filterField.rowId) {
return assign({}, field, {loading: action.status});
}
return field;
})});
if (action.layerFilterType === "filterField") {
return assign({}, state, {filterFields: state.filterFields.map((field) => {
if (field.rowId === action.filterField.rowId) {
return assign({}, field, {loading: action.status});
}
return field;
})});
}
return set(`crossLayerFilter.collectGeometries.queryCollection.filterFields`,
(get(state, 'crossLayerFilter.collectGeometries.queryCollection.filterFields') || [])
.map((field) => {
if (field.rowId === action.filterField.rowId) {
return {
...field,
loading: action.status
};
}
return field;
})
, state);
}
case UPDATE_EXCEPTION_FIELD: {
return assign({}, state, {filterFields: state.filterFields.map((field) => {
Expand Down

0 comments on commit ae25991

Please sign in to comment.