Skip to content

Commit e6ad99e

Browse files
author
Sergei Aksiutin
committed
[NEP-12629] Rework filters logic by adding AND/OR conditions.
1 parent 54c646c commit e6ad99e

20 files changed

+2878
-4006
lines changed

docs/react-components-structure.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
React Components Structure
2+
--------------------------
3+
4+
FilterBar
5+
-> FilterList
6+
-> FilterListOption
7+
-> ApplyFiltersButton
8+
-> ClearFiltersButton
9+
-> SaveFiltersButton
10+
-> SavedSearchesList
11+
-> ConfigurationButton *
12+
-> ExportResultsButton *
13+
-> BatchActionsList
14+
-> FilterDisplay
15+
-> FilterGroup
16+
-> FilterItem
17+
-> FilterButton
18+
-> FilterButton
19+
20+
21+
{} - available filters
22+
[] - default filters
23+
[
24+
[filter1] -> when adding new add new filter1
25+
]
26+
27+
[
28+
[filter1, filter2] -> when adding "ADD" button and add new filter2
29+
]

example/public/js/react-filterbar.js

Lines changed: 2595 additions & 3951 deletions
Large diffs are not rendered by default.

src/actors/FilterBarActor.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,6 @@ export class FilterBarActor {
2323
this.filterBarStore.enableFilter(filterUid, value);
2424
}
2525

26-
disableFilter(filterUid) {
27-
this.filterBarStore.disableFilter(filterUid);
28-
}
29-
3026
disableAllFilters() {
3127
this.filterBarStore.disableAllFilters();
3228
this.filterBarStore.disableAllQuickFilters();
@@ -37,8 +33,12 @@ export class FilterBarActor {
3733
this.applyFilters();
3834
}
3935

40-
updateFilter(filterUid, propKey, propValue) {
41-
this.filterBarStore.updateFilter(filterUid, propKey, propValue);
36+
updateFilter(groupKey, inputKey, value) {
37+
this.filterBarStore.updateFilter(groupKey, inputKey, value);
38+
}
39+
40+
disableFilter(groupKey, inputKey) {
41+
this.filterBarStore.disableFilter(groupKey, inputKey)
4242
}
4343

4444
applyFilters() {

src/components/FilterBar/FilterBar.react.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,6 @@ export class FilterBar extends React.Component {
1818
<div>
1919
<div>
2020
<div className="btn-group margin-bottom-sm">
21-
<FilterList
22-
disabledFilters={this.context.filterBarStore.getDisabled()}
23-
/>
24-
2521
<ApplyFiltersButton
2622
filterBarActor={this.context.filterBarActor}
2723
/>
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { FilterListOption } from "../FilterList/FilterListOption.react";
2+
export class FilterButton extends React.Component {
3+
constructor(props) {
4+
super(props);
5+
6+
this.state = { filters: props.filters };
7+
}
8+
9+
componentDidMount() {
10+
this.context.filterBarStore.addChangeListener(this.onChange.bind(this));
11+
}
12+
13+
onChange() {
14+
this.setState(this.getStateFromStores());
15+
}
16+
17+
getStateFromStores() {
18+
return {
19+
filters: this.context.filterBarStore.getFilters()
20+
};
21+
}
22+
23+
onClick(filterUid) {
24+
this.props.onClick(filterUid);
25+
}
26+
27+
render() {
28+
var optionKey = "";
29+
var filterOptions = Object.keys(this.state.filters).map(function(filterUid) {
30+
optionKey = "option-" + filterUid;
31+
return (
32+
<FilterListOption
33+
onClick={ this.onClick.bind(this) }
34+
filterUid={filterUid}
35+
key={optionKey}
36+
label={this.state.filters[filterUid].label}
37+
/>
38+
);
39+
}, this);
40+
return (
41+
<div className='btn-group'>
42+
<button className='btn btn-default dropdown-toggle' data-toggle='dropdown' type='button'>
43+
<span>{ this.props.title }</span>
44+
<i className='icon icon-add'></i>
45+
</button>
46+
<div className='dropdown-menu' role='menu'>
47+
<ul className='filter-options'>
48+
{filterOptions}
49+
</ul>
50+
</div>
51+
</div>
52+
)
53+
}
54+
}
55+
56+
FilterButton.contextTypes = {
57+
filterBarActor: React.PropTypes.object,
58+
filterBarStore: React.PropTypes.object
59+
};
60+
61+
FilterButton.propTypes = {
62+
disabledFilters: React.PropTypes.object.isRequired
63+
};

src/components/FilterBar/FilterDisplay/FilterDisplay.react.js

Lines changed: 56 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import {FilterInput} from "./FilterInput.react";
2-
2+
import {FilterButton} from "./FilterButton.react";
3+
import {FilterGroup} from "./FilterGroup.react";
4+
import { FilterList } from "../FilterList/FilterList.react";
35
export class FilterDisplay extends React.Component {
46
constructor(props) {
57
super(props);
@@ -40,30 +42,68 @@ export class FilterDisplay extends React.Component {
4042
};
4143
}
4244

45+
getActiveFilters() {
46+
return this.context.filterBarStore.getActiveFilters();
47+
}
48+
49+
getFilters() {
50+
return this.context.filterBarStore.getFilters();
51+
}
52+
53+
addGroup(filterUid) {
54+
this.context.filterBarStore.addGroupFilter(-1, filterUid);
55+
}
56+
4357
render() {
44-
var filters = Object.keys(this.state.filters).map(function(filterUid) {
45-
var filter = this.state.filters[filterUid];
58+
var filters = [];
59+
this.getActiveFilters().map(function(groupFilters, idx) {
60+
if (idx > 0) {
61+
filters.push(
62+
(
63+
<div style={ { marginTop: 'auto', marginBottom: 'auto', padding: '10px'} }>OR</div>
64+
)
65+
)
66+
}
4667

47-
return (
48-
<FilterInput
49-
filterUid={filterUid}
50-
key={filterUid}
51-
label={filter.label}
52-
type={filter.type}
53-
value={filter.value}
54-
operator={filter.operator}
55-
/>
68+
filters.push(
69+
(<FilterGroup
70+
key={ idx }
71+
groupKey={ idx }
72+
filters={ groupFilters }
73+
/>)
5674
);
57-
}, this);
75+
76+
})
5877

5978
if (filters.length === 0) {
60-
filters = (<div>No Filters Enabled!</div>);
79+
filters.push((
80+
<div style={ { marginTop: 'auto', marginBottom: 'auto', padding: '10px'} }>
81+
<FilterButton
82+
filters={ this.getFilters() }
83+
title="ADD FILTER"
84+
onClick={ this.addGroup.bind(this) }
85+
/>
86+
</div>)
87+
);
88+
} else {
89+
filters.push(
90+
(
91+
<div style={ { marginTop: 'auto', marginBottom: 'auto', padding: '10px'} }>
92+
<FilterButton
93+
filters={ this.getFilters() }
94+
title="OR"
95+
onClick={ this.addGroup.bind(this) }
96+
/>
97+
</div>
98+
));
6199
}
62100

63101
return (
64102
<div className="navbar filterbar">
65-
<div className="panel panel-default">
66-
{filters}
103+
<div className="panel panel-default" style={ { paddingTop: 'unset', paddingBottom: 'unset' } }>
104+
<div style={ { display: 'flex', float: 'left', flexWrap: 'wrap' } }>
105+
{filters}
106+
</div>
67107
</div>
68108
</div>
69109
);
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { FilterInput } from "./FilterInput.react"
2+
import { FilterButton } from "./FilterButton.react"
3+
4+
export class FilterGroup extends React.Component {
5+
constructor(props) {
6+
super(props);
7+
8+
this.state = { filters: props.filters };
9+
}
10+
11+
getFilters() {
12+
return this.context.filterBarStore.getFilters();
13+
}
14+
15+
onButtonClick(filterUid) {
16+
this.context.filterBarStore.addGroupFilter(this.props.groupKey, filterUid);
17+
}
18+
19+
render() {
20+
const { groupKey } = this.props;
21+
var filters = [];
22+
this.state.filters.map(function(filter, idx) {
23+
if (idx > 0) {
24+
filters.push(
25+
(
26+
<div style={ { marginTop: 'auto', marginBottom: 'auto', padding: '10px'} }>AND</div>
27+
)
28+
);
29+
}
30+
31+
filters.push(
32+
(
33+
<div style={ { marginTop: 'auto', marginBottom: 'auto', padding: '10px'} }>
34+
<FilterInput
35+
groupKey={ groupKey }
36+
inputKey={ idx }
37+
filterUid={filter.uid}
38+
key={filter.uid}
39+
label={filter.label}
40+
type={filter.type}
41+
value={filter.value}
42+
operator={filter.operator}
43+
/>
44+
</div>)
45+
);
46+
});
47+
48+
filters.push(
49+
(
50+
<div style={ { marginTop: 'auto', marginBottom: 'auto', padding: '10px'} }>
51+
<FilterButton
52+
filters={ this.getFilters() }
53+
title="ADD"
54+
onClick={ this.onButtonClick.bind(this) }
55+
/>
56+
</div>
57+
)
58+
);
59+
60+
return (
61+
<div style={ { display: 'flex', flexWrap: 'wrap', borderRadius: '5px', border: '1px solid #c0c0c0', backgroundColor: '#eee', marginTop: '7px', marginBottom: '7px' } }>
62+
{filters}
63+
</div>
64+
)
65+
}
66+
}
67+
68+
FilterGroup.contextTypes = {
69+
filterBarActor: React.PropTypes.object,
70+
filterBarStore: React.PropTypes.object
71+
};

src/components/FilterBar/FilterDisplay/FilterInput.react.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,17 @@ export class FilterInput extends React.Component {
66
}
77

88
onClick() {
9-
this.context.filterBarActor.disableFilter(this.props.filterUid);
9+
const { groupKey, inputKey } = this.props;
10+
this.context.filterBarActor.disableFilter(groupKey, inputKey);
1011
}
1112

1213
objectProperties() {
1314
var key = Date.now();
1415
return(
1516
{
1617
filterUid: this.props.filterUid,
18+
groupKey: this.props.groupKey,
19+
inputKey: this.props.inputKey,
1720
key: key,
1821
value: this.props.value,
1922
type: this.props.type,
@@ -26,7 +29,7 @@ export class FilterInput extends React.Component {
2629
var propObject = this.objectProperties();
2730
var inputs = new FilterInputFactory(propObject);
2831
return (
29-
<div className="col-lg-3 col-md-4 col-sm-6 col-xs-12 filter">
32+
<div className="filter">
3033
<ul className={this.filterKey}>
3134
<li>
3235
<i

src/components/FilterBar/FilterDisplay/Inputs/DateInput.react.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export class DateInput extends React.Component {
2424
}
2525

2626
onBlur() {
27-
this.context.filterBarActor.updateFilter(this.props.filterUid, "value", this.state.value);
27+
this.context.filterBarActor.updateFilter(this.props.groupKey, this.props.inputKey, this.state.value);
2828
}
2929

3030
componentDidMount() {

src/components/FilterBar/FilterDisplay/Inputs/DateTimeInput.react.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export class DateTimeInput extends React.Component {
1818
}
1919

2020
onBlur() {
21-
this.context.filterBarActor.updateFilter(this.props.filterUid, "value", this.state.value);
21+
this.context.filterBarActor.updateFilter(this.props.groupKey, this.props.inputKey, this.state.value);
2222
}
2323

2424
componentDidMount() {

src/components/FilterBar/FilterDisplay/Inputs/LazyMultiSelectInput.react.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ export class LazyMultiSelectInput extends React.Component {
7272
} else {
7373
filter.value = event.target.value.split(",");
7474
}
75+
this.context.filterBarActor.updateFilter(this.props.groupKey, this.props.inputKey, filter.value);
7576
}
7677

7778
render() {

src/components/FilterBar/FilterDisplay/Inputs/LazySelectInput.react.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ export class LazySelectInput extends React.Component {
5252
onSelect(event) {
5353
let filter = this.context.filterBarStore.getFilter(this.props.filterUid);
5454
filter.value = event.target.value;
55+
this.context.filterBarActor.updateFilter(this.props.groupKey, this.props.inputKey, filter.value);
5556
}
5657

5758
render() {

src/components/FilterBar/FilterDisplay/Inputs/MultiSelectInput.react.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export class MultiSelectInput extends React.Component {
3737

3838
onSelect(event) {
3939
this.getFilterFromFilterBarStore().value = this.getSelectedValues()
40+
this.context.filterBarActor.updateFilter(this.props.groupKey, this.props.inputKey, this.getSelectedValues());
4041
}
4142

4243
getSelectedValues() {

src/components/FilterBar/FilterDisplay/Inputs/RangeInput.react.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export class RangeInput extends React.Component {
1616
}
1717

1818
onBlur() {
19-
this.context.filterBarActor.updateFilter(this.props.filterUid, "value", this.state.value);
19+
this.context.filterBarActor.updateFilter(this.props.groupKey, this.props.inputKey, this.state.value);
2020
}
2121

2222
render() {

src/components/FilterBar/FilterDisplay/Inputs/RelativeDateInput.react.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export class RelativeDateInput extends React.Component {
4949
}
5050

5151
updateFilter(newValue) {
52-
this.context.filterBarActor.updateFilter(this.props.filterUid, "value", newValue);
52+
this.context.filterBarActor.updateFilter(this.props.groupKey, this.props.inputKey, newValue);
5353
}
5454

5555
intToMoment(value) {

src/components/FilterBar/FilterDisplay/Inputs/SelectInput.react.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export class SelectInput extends React.Component {
3737

3838
onSelect(event) {
3939
this.setState({value: event.target.value});
40-
this.context.filterBarActor.updateFilter(this.props.filterUid, "value", event.target.value);
40+
this.context.filterBarActor.updateFilter(this.props.groupKey, this.props.inputKey, event.target.value);
4141
}
4242

4343
displayOption(option) {

0 commit comments

Comments
 (0)