-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[NEP-12629] Ability to use "OR" between filters (+ filter groups) #108
base: develop
Are you sure you want to change the base?
Changes from 4 commits
e6ad99e
2a41da1
affdf0e
95206e3
d629f0f
0ad2738
df27902
828327a
d52e253
a4b3b44
b012d4f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
{ | ||
"name": "react-filterbar", | ||
"homepage": "https://github.com/jobready/react-filterbar", | ||
"version": "1.7.1", | ||
"version": "2.1", | ||
"authors": [ | ||
"Jacob Bass <[email protected]>" | ||
], | ||
|
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
React Components Structure | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good to see this here ✨ |
||
-------------------------- | ||
|
||
FilterBar | ||
-> FilterList | ||
-> FilterListOption | ||
-> ApplyFiltersButton | ||
-> ClearFiltersButton | ||
-> SaveFiltersButton | ||
-> SavedSearchesList | ||
-> ConfigurationButton * | ||
-> ExportResultsButton * | ||
-> BatchActionsList | ||
-> FilterDisplay | ||
-> FilterGroup | ||
-> FilterItem | ||
-> FilterButton | ||
-> FilterButton | ||
|
||
|
||
{} - available filters | ||
[] - default filters | ||
[ | ||
[filter1] -> when adding new add new filter1 | ||
] | ||
|
||
[ | ||
[filter1, filter2] -> when adding "ADD" button and add new filter2 | ||
] |
Large diffs are not rendered by default.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
{ | ||
"name": "react-filterbar", | ||
"version": "2.0", | ||
"version": "2.1", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As mentioned above, major upgrade perhaps? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @msxavi I'm happy with any version actually and if you think 3.0 better reflects current changes and improvements we can change it 👌 |
||
"description": "", | ||
"main": "dist/react-filterbar.js", | ||
"engines": { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,10 +18,6 @@ export class FilterBar extends React.Component { | |
<div> | ||
<div> | ||
<div className="btn-group margin-bottom-sm"> | ||
<FilterList | ||
disabledFilters={this.context.filterBarStore.getDisabled()} | ||
/> | ||
Comment on lines
-21
to
-23
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What was the purpose of this previously? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah @SyntheticDave sorry, potentially I should put that architectural changes in PR description, because it's a huge changes. Definitely will do it before moving PR into Release stage. So, before we had registered filters in a hash and it was represented in FilterBarStore like that: {
"some_filter_key1": {
"uid" : "some_filter_key1",
"value" : "",
"name" : "Some Filter Key 1",
...
}, {
"some_filter_key2" : {
"uid" : "some_filter_key2",
"value" : "",
"name" : "Some Filter Key 2",
...
}
} and if a User selected some filters, for example with the key some_filter_key1 we needed mark it somehow and don't allow user to select that filter again (it should be removed from dropdown) and to make it we should call method The new logic works in completely different way, we still have original registered hash of filters (as I described above) but data and values we have in the same FilterBarStore but in So, that means we should hide filters from dropdown and we don't need to set property There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the explanation. I definitely like the change, but you're right that it's a big one. |
||
|
||
<ApplyFiltersButton | ||
filterBarActor={this.context.filterBarActor} | ||
/> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import { FilterListOption } from "../FilterList/FilterListOption.react"; | ||
export class FilterButton extends React.Component { | ||
constructor(props) { | ||
super(props); | ||
|
||
this.state = { filters: props.filters }; | ||
} | ||
|
||
componentDidMount() { | ||
this.context.filterBarStore.addChangeListener(this.onChange.bind(this)); | ||
} | ||
|
||
onChange() { | ||
this.setState(this.getStateFromStores()); | ||
} | ||
|
||
getStateFromStores() { | ||
return { | ||
filters: this.context.filterBarStore.getFilters() | ||
}; | ||
} | ||
|
||
onClick(filterUid) { | ||
this.props.onClick(filterUid); | ||
} | ||
|
||
render() { | ||
var optionKey = ""; | ||
var filterOptions = Object.keys(this.state.filters).map(function(filterUid) { | ||
optionKey = "option-" + filterUid; | ||
return ( | ||
<FilterListOption | ||
onClick={ this.onClick.bind(this) } | ||
filterUid={filterUid} | ||
key={optionKey} | ||
label={this.state.filters[filterUid].label} | ||
/> | ||
); | ||
}, this); | ||
return ( | ||
<div className='btn-group'> | ||
<button className='btn btn-default dropdown-toggle' data-toggle='dropdown' type='button'> | ||
<span>{ this.props.title }</span> | ||
<i className='icon icon-add'></i> | ||
</button> | ||
<div className='dropdown-menu' role='menu'> | ||
<ul className='filter-options'> | ||
{filterOptions} | ||
</ul> | ||
</div> | ||
</div> | ||
) | ||
} | ||
} | ||
|
||
FilterButton.contextTypes = { | ||
filterBarActor: React.PropTypes.object, | ||
filterBarStore: React.PropTypes.object | ||
}; | ||
|
||
FilterButton.propTypes = { | ||
disabledFilters: React.PropTypes.object.isRequired | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
import {FilterInput} from "./FilterInput.react"; | ||
|
||
import {FilterButton} from "./FilterButton.react"; | ||
import {FilterGroup} from "./FilterGroup.react"; | ||
import { FilterList } from "../FilterList/FilterList.react"; | ||
export class FilterDisplay extends React.Component { | ||
constructor(props) { | ||
super(props); | ||
|
@@ -40,30 +42,68 @@ export class FilterDisplay extends React.Component { | |
}; | ||
} | ||
|
||
getActiveFilters() { | ||
return this.context.filterBarStore.getActiveFilters(); | ||
} | ||
|
||
getFilters() { | ||
return this.context.filterBarStore.getFilters(); | ||
} | ||
|
||
addGroup(filterUid) { | ||
this.context.filterBarStore.addGroupFilter(-1, filterUid); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not a big deal, but if you updated There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good thinking, will do that! |
||
} | ||
|
||
render() { | ||
var filters = Object.keys(this.state.filters).map(function(filterUid) { | ||
var filter = this.state.filters[filterUid]; | ||
var filters = []; | ||
this.getActiveFilters().map(function(groupFilters, idx) { | ||
if (idx > 0) { | ||
filters.push( | ||
( | ||
<div style={ { marginTop: 'auto', marginBottom: 'auto', padding: '10px'} }>OR</div> | ||
) | ||
) | ||
} | ||
|
||
return ( | ||
<FilterInput | ||
filterUid={filterUid} | ||
key={filterUid} | ||
label={filter.label} | ||
type={filter.type} | ||
value={filter.value} | ||
operator={filter.operator} | ||
/> | ||
filters.push( | ||
(<FilterGroup | ||
key={ idx } | ||
groupKey={ idx } | ||
filters={ groupFilters } | ||
/>) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So does this mean if there's no group specified, all filters get automatically added to a new first group? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, yeah, that's a good point about SavedSearches. My thinking was that SavedSearches should be presented as is with OLD format (w/o groups) and should be converted to NEW format (w/ groups) when new react component loads it the first time and SavedSearch should be saved in NEW format after if user decides to save it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We'll definitely want to make sure we don't break existing saved searches or links in the application that direct to filtered index pages (e.g. reports often link to an index page with the same filters as is used by that cell in the report), so we'll need to make sure this is backwards compatible with those. |
||
); | ||
}, this); | ||
|
||
}) | ||
|
||
if (filters.length === 0) { | ||
filters = (<div>No Filters Enabled!</div>); | ||
filters.push(( | ||
<div style={ { marginTop: 'auto', marginBottom: 'auto', padding: '10px'} }> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's a bunch of inline styling here. Is it instead worth creating classes for this so they can be overridden at the application level if needed? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, currently thinking how to make it better and replace inline styles with reusable css. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't stress too much about it. If it's too big a job to do so, I'd create a tech debt ticket to add that in later, as inline styles should be okay in the short term. |
||
<FilterButton | ||
filters={ this.getFilters() } | ||
title="ADD FILTER" | ||
onClick={ this.addGroup.bind(this) } | ||
/> | ||
</div>) | ||
); | ||
} else { | ||
filters.push( | ||
( | ||
<div style={ { marginTop: 'auto', marginBottom: 'auto', padding: '10px'} }> | ||
<FilterButton | ||
filters={ this.getFilters() } | ||
title="OR" | ||
onClick={ this.addGroup.bind(this) } | ||
/> | ||
</div> | ||
)); | ||
} | ||
|
||
return ( | ||
<div className="navbar filterbar"> | ||
<div className="panel panel-default"> | ||
{filters} | ||
<div className="panel panel-default" style={ { paddingTop: 'unset', paddingBottom: 'unset' } }> | ||
<div style={ { display: 'flex', float: 'left', flexWrap: 'wrap' } }> | ||
{filters} | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import { FilterInput } from "./FilterInput.react" | ||
import { FilterButton } from "./FilterButton.react" | ||
|
||
export class FilterGroup extends React.Component { | ||
constructor(props) { | ||
super(props); | ||
|
||
this.state = { filters: props.filters }; | ||
} | ||
|
||
getFilters() { | ||
return this.context.filterBarStore.getFilters(); | ||
} | ||
|
||
onButtonClick(filterUid) { | ||
this.context.filterBarStore.addGroupFilter(this.props.groupKey, filterUid); | ||
} | ||
|
||
render() { | ||
const { groupKey } = this.props; | ||
var filters = []; | ||
this.state.filters.map(function(filter, idx) { | ||
if (idx > 0) { | ||
filters.push( | ||
( | ||
<div style={ { marginTop: 'auto', marginBottom: 'auto', padding: '10px'} }>AND</div> | ||
) | ||
); | ||
} | ||
|
||
filters.push( | ||
( | ||
<div style={ { marginTop: 'auto', marginBottom: 'auto', padding: '10px'} }> | ||
<FilterInput | ||
groupKey={ groupKey } | ||
inputKey={ idx } | ||
filterUid={filter.uid} | ||
key={filter.uid} | ||
label={filter.label} | ||
type={filter.type} | ||
value={filter.value} | ||
operator={filter.operator} | ||
/> | ||
</div>) | ||
); | ||
}); | ||
|
||
filters.push( | ||
( | ||
<div style={ { marginTop: 'auto', marginBottom: 'auto', padding: '10px'} }> | ||
<FilterButton | ||
filters={ this.getFilters() } | ||
title="ADD" | ||
onClick={ this.onButtonClick.bind(this) } | ||
/> | ||
</div> | ||
) | ||
); | ||
|
||
return ( | ||
<div style={ { display: 'flex', flexWrap: 'wrap', borderRadius: '5px', border: '1px solid #c0c0c0', backgroundColor: '#eee', marginTop: '7px', marginBottom: '7px' } }> | ||
{filters} | ||
</div> | ||
) | ||
} | ||
} | ||
|
||
FilterGroup.contextTypes = { | ||
filterBarActor: React.PropTypes.object, | ||
filterBarStore: React.PropTypes.object | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,14 +6,17 @@ export class FilterInput extends React.Component { | |
} | ||
|
||
onClick() { | ||
this.context.filterBarActor.disableFilter(this.props.filterUid); | ||
const { groupKey, inputKey } = this.props; | ||
this.context.filterBarActor.disableFilter(groupKey, inputKey); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this mean I can't add a filter for the same property into the one group, but can still use it in other groups? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, I think it's a bad naming here. New logic allows you to use filter as many times as you want in one or many groups. Potentially method should be called There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, right. Yeah, I think remove or unset would be a more descriptive method name then. |
||
} | ||
|
||
objectProperties() { | ||
var key = Date.now(); | ||
return( | ||
{ | ||
filterUid: this.props.filterUid, | ||
groupKey: this.props.groupKey, | ||
inputKey: this.props.inputKey, | ||
key: key, | ||
value: this.props.value, | ||
type: this.props.type, | ||
|
@@ -26,11 +29,11 @@ export class FilterInput extends React.Component { | |
var propObject = this.objectProperties(); | ||
var inputs = new FilterInputFactory(propObject); | ||
return ( | ||
<div className="col-lg-3 col-md-4 col-sm-6 col-xs-12 filter"> | ||
<div className="filter"> | ||
<ul className={this.filterKey}> | ||
<li> | ||
<i | ||
className="btn btn-circle-primary btn-xs icon icon-close remove-filter" | ||
className="btn btn-circle-primary btn-xs icon icon-close remove-filter" style={ { lineHeight: '16px' } } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As with elsewhere, I'd really like to see this done with css classes to maintain flexibility. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, working on it! 👍 |
||
onClick={this.onClick.bind(this)} | ||
/> | ||
<label> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,7 +24,7 @@ export class DateInput extends React.Component { | |
} | ||
|
||
onBlur() { | ||
this.context.filterBarActor.updateFilter(this.props.filterUid, "value", this.state.value); | ||
this.context.filterBarActor.updateFilter(this.props.groupKey, this.props.inputKey, this.state.value); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, activeFIlters = [
["value1", "value2"],
["value3", "value4"]
] and if we need to update value for example for filter2 ("value2" is located in 1st group) we should pass |
||
} | ||
|
||
componentDidMount() { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -72,6 +72,7 @@ export class LazyMultiSelectInput extends React.Component { | |
} else { | ||
filter.value = event.target.value.split(","); | ||
} | ||
this.context.filterBarActor.updateFilter(this.props.groupKey, this.props.inputKey, filter.value); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you know why this was not needed for this filter type previously? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, because react-component and filters had different architecture & structure before (see my first comment above) but now we need to set selected data to |
||
} | ||
|
||
render() { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Odd that this was out of sync with the package file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would this be better represented by a major upgrade 3.0 since there may not exist backward compatibility with previous design?