-
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?
Conversation
bd08153
to
37b8d05
Compare
37b8d05
to
e6ad99e
Compare
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.
Amazing work, @footnoise!
I've left some questions here mostly for my own understanding of the code. I primarily want to make sure:
- Existing saved searches, quick filters, and links to filtered index pages (e.g. from reports) still work as previously (if I've read the code right, this should be the case)
- We use inline styles as little as possible, so anything can be overwritten at the application level
bower.json
Outdated
@@ -1,7 +1,7 @@ | |||
{ | |||
"name": "react-filterbar", | |||
"homepage": "https://github.com/jobready/react-filterbar", | |||
"version": "1.7.1", | |||
"version": "2.1", |
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?
docs/react-components-structure.md
Outdated
@@ -0,0 +1,29 @@ | |||
React Components Structure |
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.
Good to see this here ✨
<FilterList | ||
disabledFilters={this.context.filterBarStore.getDisabled()} | ||
/> |
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.
What was the purpose of this previously?
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.
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 this.context.filterBarStore.getDisabled()
and pass it as disabledFilters
property into component.
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 activeFilters
array. In this case I use groupKey
and inputKey
properties to manage values data. It's a double array, which has groupKey
as ID of the first array and inputKey
as ID for the second array.
So, that means we should hide filters from dropdown and we don't need to set property disabledFilters
anymore.
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.
Thanks for the explanation. I definitely like the change, but you're right that it's a big one.
filters.push( | ||
(<FilterGroup | ||
key={ idx } | ||
groupKey={ idx } | ||
filters={ groupFilters } | ||
/>) |
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.
So does this mean if there's no group specified, all filters get automatically added to a new first group?
If so, it seems like existing saved searches and existing links to filters will still work correctly? Would be amazing if so.
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.
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 comment
The 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.
|
||
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 comment
The 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 comment
The 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 comment
The 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.
@@ -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 comment
The reason will be displayed to describe this comment to others. Learn more.
So inputKey
used to just be "value"?
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.
Yes, groupKey
and inputKey
here are just IDs where exactly values should be set. Object filterBarActor has activeFIlters array with filters values which can be presented like that:
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 groupKey
as 0 (first index in array) and inputKey
as 1 (second index in array)
@@ -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 comment
The 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 comment
The 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 activeFilters
array.
for (var filterUid in enabledFilters) { | ||
this.disableFilter(filterUid); | ||
} | ||
this.activeFilters = [] |
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.
So we don't need to call disable filter on each individually now?
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.
Yes, because architecture and data-structure changed.
src/stores/FilterBarStore.js
Outdated
} | ||
|
||
updateFilter(groupKey, inputKey, value) { | ||
//this.deactivateQuickFiltersBasedOnFilterValue(filterUid, propValue, this.activeQuickFilters()); |
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.
Should this be removed?
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.
Oh yes, definitely!
src/stores/FilterBarStore.js
Outdated
this.activeFilters[groupKey][inputKey].value = value; | ||
} | ||
|
||
addGroupFilter(groupKey, filterUid) { |
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.
As mentioned elsewhere, changing the order of these params would allow you to pass groupKey
optionally, then just check for undefined
.
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.
Yep, that's a good point! I will follow your suggestion 👌
27c78de
to
0ad2738
Compare
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.
This is massive and neat. Great effort @footnoise !
bower.json
Outdated
@@ -1,7 +1,7 @@ | |||
{ | |||
"name": "react-filterbar", | |||
"homepage": "https://github.com/jobready/react-filterbar", | |||
"version": "1.7.1", | |||
"version": "2.1", |
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?
package.json
Outdated
@@ -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 comment
The 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 comment
The 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 👌
this.filterBarStore.enableQuickFilter(quickFilterName, blockName); | ||
this.enableFilter(filterName, value); |
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.
Do you still reference enableFilter()
in this file?
if (this.props.onBlur) { | ||
this.props.onBlur(); | ||
} else { | ||
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 comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't quite follow this change. Why filter types are being affected by groups? Is there any reason where a Filter needs to know the group it belongs to?
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.
@msxavi yes it's a bit tricky and most complicated part of the code.
As I mentioned in PR descripute now component has new data strucure it two-sized array activeFilters
in FilterBarStore
.
It can be presented like this:
this.activeFilters = [
[Filter1, Filter2], // <- Group1
[Filter3], // <- Group2
[Filter4, Filter5] // <- Group3
]
As you can see the external array presents groups and interal array presents filters inside each group.
Groups/Filters rendering based on that activeFitlers
variable and to identify correct pathway to manage data-values we heed groupKey
which represents group index in external array and we need inputKey
which represents filter index in internal array. When we change values in filter component we should update data in Store
and set updated values in activeFilters
and specially in this case we should use groupKey
and inputKey
like this:
this.activeFilters[groupKey][inputKey] = newFilterValue;
1489a93
to
eab2c74
Compare
106b84b
to
2b9579b
Compare
2b9579b
to
828327a
Compare
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.
I'm not Mr. React exactly, but apart from one file which Github refused to show me it looks fine.
4d12e5b
to
d194b8c
Compare
d194b8c
to
e0d3e29
Compare
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.
Much tidier. The comments are generally inconsequential.
filtersArr = filters; | ||
} else { | ||
filtersArr = Object.keys(filters).map(function (name) { | ||
if (!Array.isArray(savedSearchFilters)) { |
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.
For instance, why is this better than say if (savedSearchFilters instanceof Array)
?
return { | ||
uid: name | ||
}; | ||
}); | ||
} | ||
|
||
return new _FilterVerificator.FilterVerificator(this.filterBarStore.getFilters(), filtersArr).verify(); | ||
if (!Array.isArray(filters[0])) { |
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.
Is this overly defensive?
return filters; | ||
} | ||
}, { | ||
key: "verifySavedFilters", |
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.
I see. You've moved the filter 'grooming' to a new method.
_iterator.e(err); | ||
} finally { | ||
_iterator.f(); | ||
if (Array.isArray(activeFilters[0])) { |
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.
Might be slightly easier on the eye if it was if (!Array.isArray(activeFilters[0])) {
then it would ...parseQueryVersion1...
then ...parseQueryVersion2
.
field, type, value = nil | ||
|
||
if needle.is_a? Array | ||
# Case 1: Filters with new format |
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.
I like that these are sign-posted.
e0d3e29
to
4987cb3
Compare
4987cb3
to
d52e253
Compare
Original ticket: https://jobready.atlassian.net/browse/NEP-12629
Working on new version which allows using OR and AND operators with filters.
So, before we had registered filters in a hash and it was represented in FilterBarStore like that:
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
this.context.filterBarStore.getDisabled()
and pass it asdisabledFilters
property into component.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
activeFilters
array. In this case I usegroupKey
andinputKey
properties to manage values data. It's a double array, which hasgroupKey
as ID of the first array andinputKey
as ID for the second array.So, that means we should hide filters from dropdown and we don't need to set property
disabledFilters
anymore.