Skip to content

Commit

Permalink
Fixes #1441: allow query with no filter set (#1673)
Browse files Browse the repository at this point in the history
  • Loading branch information
mbarto authored Apr 3, 2017
1 parent cbe588f commit 528e8f4
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 9 deletions.
8 changes: 7 additions & 1 deletion web/client/components/data/query/QueryBuilder.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ const QueryBuilder = React.createClass({
pagination: React.PropTypes.object,
sortOptions: React.PropTypes.object,
hits: React.PropTypes.bool,
maxHeight: React.PropTypes.number
maxHeight: React.PropTypes.number,
allowEmptyFilter: React.PropTypes.bool,
emptyFilterWarning: React.PropTypes.bool
},
getDefaultProps() {
return {
Expand All @@ -74,6 +76,8 @@ const QueryBuilder = React.createClass({
sortOptions: null,
hits: false,
maxHeight: 830,
allowEmptyFilter: false,
emptyFilterWarning: false,
attributeFilterActions: {
onAddGroupField: () => {},
onAddFilterField: () => {},
Expand Down Expand Up @@ -138,6 +142,8 @@ const QueryBuilder = React.createClass({
pagination={this.props.pagination}
sortOptions={this.props.sortOptions}
hits={this.props.hits}
allowEmptyFilter={this.props.allowEmptyFilter}
emptyFilterWarning={this.props.emptyFilterWarning}
/>
<div className="querypanel" style={{maxHeight: this.props.maxHeight - 170}}>
<GroupField
Expand Down
28 changes: 20 additions & 8 deletions web/client/components/data/query/QueryToolbar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
*/
const React = require('react');

const {Button, Glyphicon, ButtonToolbar} = require('react-bootstrap');
const {Button, Glyphicon, ButtonToolbar, Tooltip} = require('react-bootstrap');

const Modal = require('../../misc/Modal');
const OverlayTrigger = require('../../misc/OverlayTrigger');

const I18N = require('../../I18N/I18N');

Expand All @@ -32,7 +33,9 @@ const QueryToolbar = React.createClass({
resultTitle: React.PropTypes.string,
pagination: React.PropTypes.object,
sortOptions: React.PropTypes.object,
hits: React.PropTypes.bool
hits: React.PropTypes.bool,
allowEmptyFilter: React.PropTypes.bool,
emptyFilterWarning: React.PropTypes.bool
},
getDefaultProps() {
return {
Expand All @@ -49,6 +52,8 @@ const QueryToolbar = React.createClass({
pagination: null,
sortOptions: null,
hits: false,
allowEmptyFilter: false,
emptyFilterWarning: false,
actions: {
onQuery: () => {},
onReset: () => {},
Expand All @@ -59,14 +64,24 @@ const QueryToolbar = React.createClass({
render() {
let fieldsExceptions = this.props.filterFields.filter((field) => field.exception).length > 0;
// let fieldsWithoutValues = this.props.filterFields.filter((field) => !field.value).length > 0;
let fieldsWithValues = this.props.filterFields.filter((field) => field.value).length > 0;
let fieldsWithValues = this.props.filterFields.filter((field) => field.value).length > 0 || this.props.allowEmptyFilter;

let queryDisabled =
// fieldsWithoutValues ||
fieldsExceptions ||
!this.props.toolbarEnabled ||
(!fieldsWithValues && !this.props.spatialField.geometry);

const tooltip = <Tooltip id="query-warning-tooltip"><I18N.Message msgId="queryform.emptyfilter"/></Tooltip>;
const btn = (<Button disabled={queryDisabled} bsSize="xs" id="query-toolbar-query" onClick={this.search}>
<Glyphicon glyph="glyphicon glyphicon-search"/>
<span><strong><I18N.Message msgId={"queryform.query"}/></strong></span>
</Button>);
const showTooltip = this.props.emptyFilterWarning && this.props.filterFields.filter((field) => field.value).length === 0 && !this.props.spatialField.geometry;
const queryButton = showTooltip ? (
<OverlayTrigger placement="bottom" key="query-button-tooltip" overlay={tooltip}>
{btn}
</OverlayTrigger>
) : btn;
return (
<div className="container-fluid query-toolbar">
<div id="query-toolbar-title"><I18N.Message msgId={"queryform.title"}/></div>
Expand All @@ -75,10 +90,7 @@ const QueryToolbar = React.createClass({
<Glyphicon glyph="glyphicon glyphicon-refresh"/>
<span><strong><I18N.Message msgId={"queryform.reset"}/></strong></span>
</Button>
<Button disabled={queryDisabled} bsSize="xs" id="query" onClick={this.search}>
<Glyphicon glyph="glyphicon glyphicon-search"/>
<span><strong><I18N.Message msgId={"queryform.query"}/></strong></span>
</Button>
{queryButton}
</ButtonToolbar>
<Modal show={this.props.showGeneratedFilter ? true : false} bsSize="large">
<Modal.Header>
Expand Down
106 changes: 106 additions & 0 deletions web/client/components/data/query/__tests__/QueryBuilder-test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,55 @@ describe('QueryBuilder', () => {
expect(childNodes.length).toBe(2);
});

it('creates the QueryBuilder component no filter set', () => {
const groupLevels = 5;

const groupFields = [];

const filterFields = [{
rowId: 100,
groupId: 1,
attribute: "",
operator: null,
value: null,
exception: null
}];

const attributes = [{
id: "Attribute",
type: "list",
values: [
"attribute1",
"attribute2",
"attribute3",
"attribute4",
"attribute5"
]
}];

const querybuilder = ReactDOM.render(
<QueryBuilder
filterFields={filterFields}
attributes={attributes}
groupFields={groupFields}
groupLevels={groupLevels}
/>,
document.getElementById("container")
);

expect(querybuilder).toExist();

const queryBuilderDOMNode = expect(ReactDOM.findDOMNode(querybuilder));

expect(queryBuilderDOMNode).toExist();
let childNodes = queryBuilderDOMNode.actual.childNodes;
expect(childNodes.length).toBe(2);

const queryButton = document.getElementById('query-toolbar-query');
expect(queryButton).toExist();
expect(queryButton.getAttribute("disabled")).toBe('');
});

it('creates the QueryBuilder component in error state', () => {

let attributeFilterActions = {
Expand All @@ -111,4 +160,61 @@ describe('QueryBuilder', () => {
expect(querybuilder).toExist();
expect(spy.calls.length).toEqual(1);
});

it('creates the QueryBuilder component with empty filter support', () => {
const groupLevels = 5;

const groupFields = [{
id: 1,
logic: "OR",
index: 0
}];

const filterFields = [{
rowId: 100,
groupId: 1,
attribute: "",
operator: null,
value: null,
exception: null
}, {
rowId: 200,
groupId: 1,
attribute: "Attribute",
operator: "=",
value: "attribute1",
exception: null
}];

const attributes = [{
id: "Attribute",
type: "list",
values: [
"attribute1",
"attribute2",
"attribute3",
"attribute4",
"attribute5"
]
}];

const querybuilder = ReactDOM.render(
<QueryBuilder
filterFields={filterFields}
attributes={attributes}
groupFields={groupFields}
groupLevels={groupLevels}
allowEmptyFilter={true}
/>,
document.getElementById("container")
);

expect(querybuilder).toExist();

const queryBuilderDOMNode = expect(ReactDOM.findDOMNode(querybuilder));
expect(queryBuilderDOMNode).toExist();
const queryButton = document.getElementById('query-toolbar-query');
expect(queryButton).toExist();
expect(queryButton.getAttribute("disabled")).toNotExist();
});
});
2 changes: 2 additions & 0 deletions web/client/plugins/TOC.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ const SmartQueryForm = connect((state) => {
params: {typeName: state.query && state.query.typeName},
resultTitle: "Query Result",
showGeneratedFilter: false,
allowEmptyFilter: true,
emptyFilterWarning: true,
maxHeight: state.map && state.map.present && state.map.present.size && state.map.present.size.height
};
}, dispatch => {
Expand Down
1 change: 1 addition & 0 deletions web/client/translations/data.de-DE
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,7 @@
"header": "Finde im Datensatz",
"dataset_header": "Datensatz"
},
"emptyfilter": "Kein Filtersatz. Die Suche nach dem Timeout, wenn die Paginierung vom Server nicht unterstützt wird.",
"attributefilter":{
"add_condition": " Füge Bedingung hinzu",
"add_group": " Füge Gruppe hinzu",
Expand Down
1 change: 1 addition & 0 deletions web/client/translations/data.en-US
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,7 @@
"header": "Find in the dataset",
"dataset_header": "Dataset"
},
"emptyfilter": "No filter set. Searching could timeout if pagination is not supported by the server.",
"attributefilter":{
"add_condition": " Add Condition",
"add_group": " Add Group",
Expand Down
1 change: 1 addition & 0 deletions web/client/translations/data.fr-FR
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,7 @@
"header": "Rechercher dans les données",
"dataset_header": "Ensemble des données"
},
"emptyfilter": "Aucun ensemble de filtres. La recherche pourrait expirer si la pagination n'est pas prise en charge par le serveur.",
"attributefilter":{
"add_condition": " Ajouter une condition",
"add_group": " Ajouter un groupe",
Expand Down
1 change: 1 addition & 0 deletions web/client/translations/data.it-IT
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,7 @@
"header": "Cerca nel dataset",
"dataset_header": "Dataset"
},
"emptyfilter": "Nessun filtro selezionato. La ricerca potrebbe andare in timeout se il server non supporta la paginazione.",
"attributefilter":{
"add_condition": " Aggiungi Condizione",
"add_group": " Aggiungi Gruppo",
Expand Down

0 comments on commit 528e8f4

Please sign in to comment.