-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
explicitly passing filters and query to visualize #19172
Conversation
863c153
to
c5473b9
Compare
a0e0dec
to
90e4013
Compare
@@ -177,6 +181,14 @@ export class DashboardStateManager { | |||
if (getDescription(state) !== this.getDescription()) { | |||
store.dispatch(updateDescription(this.getDescription())); | |||
} | |||
|
|||
if (getFilters(state) !== this.getFilterState().filterBars) { |
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.searchScope.columns = this.customization.columns || this.savedSearch.columns; | ||
this.searchScope.sort = this.customization.sort || this.savedSearch.sort; | ||
this.searchScope.sharedItemTitle = this.panelTitle; | ||
|
||
this.searchScope.searchSource.getParent().set('filter', this.filters); |
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 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.
Why setting it on the parent and not this.searchScope.searchSource
? Could you clarify a bit what search source is which in this case?
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 created a searchsource 'stack' (check below) where timeRangeSearchSource is the root
and filterSearchSouce inherits from it and our saved searchSource inherits from the filterSearchSource
- savedSearchSource will have filters and query saved with the search
- filterSearchSource will get dashboard filters and query
- timeRangeSearchSource will get the time range filter
we do this as we don't want to handle merging of filters and queries (if we would have only one level) and we let the searchsource handle 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.
Couldn't we change the inheritance order of the search sources to be: timeRangeSearchSource
← savedSearchSource
← filterSearchSource
(i.e. put the saved search source in the middle).
That way we could safely use this.searchScope.searchSource
instead of needing this kind of implementation detail based call to getParent()
? Also for the actual request, the inheritance order of those three shouldn't matter?
💔 Build Failed |
💔 Build Failed |
💔 Build Failed |
💔 Build Failed |
💔 Build Failed |
f986fa3
to
397f3cc
Compare
💔 Build Failed |
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 think the way itself look good to go, though we should carefully also test every of this scenarios. I would also be interested in @spalger overall thoughts about that, and we should at least when we are done with it (maybe already before for feedback) get a review by @stacey-gammon and @Bargs
@@ -182,6 +182,17 @@ function discoverController( | |||
.highlightAll(true) | |||
.version(true); | |||
|
|||
// searchSource which applies time range | |||
const timeRangeSearchSource = savedSearch.searchSource.clone(); |
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 we actually want to clone
here, and not just creating a new instance? I've got the feeling except the filter (and maybe the index) we don't want to have anything from that savedSearch.searchSource
? Wouldn't it be easier to create a new one, and copy this two things over rather than cloning and resetting some things (like query
) below, but might forget to reset some important things?
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 are the things you wouldn't want ? when i was thinking about it it was either:
- create a new one and make sure the parameters are set correctly (index ... ? not sure if anything else is needed ?)
- clone, and make sure the parameters are set correctly <-- sounded safer, as i don't need to worry about all parameters + i don't need to create a new SearchSource which means i don't need access to Private
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 agree with @timroes and think we should be explicit about what we want to copy over, rather than cloning and unsetting things.
How do you feel about these options?
// create a new searchSource, without needing Private
const timeRangeSearchSource = new savedSearch.searchSource.constructor()
// or a little less nasty, add a `.new()` method
const timeRangeSearchSource = savedSearch.searchSource.new()
// or add a `.reset()` method so we don't have to know what to unset
const timeRangeSearchSource = savedSearch.searchSource.clone().reset()
this.searchScope.columns = this.customization.columns || this.savedSearch.columns; | ||
this.searchScope.sort = this.customization.sort || this.savedSearch.sort; | ||
this.searchScope.sharedItemTitle = this.panelTitle; | ||
|
||
this.searchScope.searchSource.getParent().set('filter', this.filters); |
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.
Why setting it on the parent and not this.searchScope.searchSource
? Could you clarify a bit what search source is which in this case?
this.searchScope.description = this.savedSearch.description; | ||
this.searchScope.searchSource = this.savedSearch.searchSource; | ||
|
||
const timeRangeSearchSource = this.searchScope.searchSource.clone(); |
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.
Same question as above: cloning vs creating new one?
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.
same answer as above :)
}); | ||
|
||
const filtersSearchSource = this.searchScope.searchSource.clone(); | ||
filtersSearchSource.inherits(timeRangeSearchSource); |
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 one should still get this.filters
and this.query
in 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.
yes, this one will receive filters and query
@@ -220,6 +220,7 @@ function VisEditor($scope, $route, timefilter, AppState, $window, kbnUrl, courie | |||
|
|||
const updateTimeRange = () => { | |||
$scope.timeRange = timefilter.time; | |||
$scope.vis.forceReload(); |
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 discussed we should instead listen in visualize on the changes of filter/queries/timerange
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.
the $watch is there now .... however removing forceReload doesn't work (watch is never triggered) .... i didn't dig into what exactly is preventing it to work that way .... any ideas ?
src/ui/public/timefilter/get_time.js
Outdated
import _ from 'lodash'; | ||
import dateMath from '@kbn/datemath'; | ||
|
||
export function calculateBounds(timeRange, forceNow) { |
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 would be more explicit here for better readability and make forceNow = false
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.
forceNow should not be false, but undefined or a date ?
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 personally find unnamed boolean arguments hard to understand, what if we just allowed dateMathOptions
:
export function calculateBounds(timeRange, dateMathOptions = {}) {
return {
min: dateMath.parse(timeRange.from, { ...dateMathOptions }),
max: dateMath.parse(timeRange.to, { roundUp: true, ...dateMathOptions })
};
}
// ... somewhere else ...
calculateBounds(timeRange, {
forceNow: true
})
// vs
calculateBounds(timeRange, true)
``
// in editor mode we want to set filter and query on searchSource so they get | ||
// stored with visualization, however on dashboard we set them on requestSearchSource | ||
// so we don't override the stored ones | ||
if (vis.editorMode) { |
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 think it's okay for now, but we should still figure out, if we can find a better way than that.
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 feel like the editor just shouldn't pass in the filters or query to <visualize>
, instead the editor will set them on the vis searchSource
and <visualize>
will default to no extra filters or queries.
src/ui/public/visualize/visualize.js
Outdated
@@ -133,9 +135,8 @@ uiModules | |||
if ($scope.editorMode) { |
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 we still need this appState.vis
in there? Shouldn't that rather be something that the visualize editor directive now takes care about (and rather expose a callback we'll trigger every time we start a fetch?
Also why do we in general need to save the app state when we do a fetch?
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 need to propagate changes to the URL ...
i would prefer if visualize wouldn't know about appState but would rather receive a callback which it should call on props updates, and then visualize app can figure out if it wants to add it to url or not.
however i would suggest in a separate PR ?
src/ui/public/visualize/visualize.js
Outdated
stateMonitor.destroy(); | ||
}); | ||
} | ||
$scope.$watchGroup(['filters', 'query', 'timeRange'], fetch); |
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.
Shouldn't that be $scope.fetch
?
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 .... i guess thats the reason watch is not triggering :D lol, thanks!
💔 Build Failed |
💔 Build Failed |
024b516
to
c8822cd
Compare
💚 Build Succeeded |
💚 Build Succeeded |
hmm, synced with the latest and also cannot repro that bug anymore @ppisljar. |
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 super happy to see this working with so few lines changed (by some standards). Couple nits/questions but I pulled the code and things seem to work great!
if (_.has(agg, 'type.postFlightRequest')) { | ||
const nestedSearchSource = new SearchSource().inherits(requestSearchSource); | ||
resp = await agg.type.postFlightRequest(resp, vis.aggs, agg, nestedSearchSource); | ||
return new Promise(async (resolve, reject) => { |
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.
No need for async
here
searchSource.set('filter', queryFilter.getFilters()); | ||
searchSource.set('query', appState.query); | ||
} | ||
requestSearchSource.set('filter', filters); |
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 resolved? Best I can tell this is working.
|
||
export function getTime(indexPattern, timeRange, forceNow) { | ||
if (!indexPattern) { | ||
//in CI, we sometimes seem to fail here. |
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.
😬 Can you justify this a little better please? Not sure what this means by "sometimes seem to fail", but if you mean that some tests aren't properly stubbing indexPattern and that's causing issues I think we should update the indexPattern stubs, or stub out this method in tests, or something other than return undefined
if an index patter isn't passed. This type of silent failing has a tendency to bite back in weird ways down the road.
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.
no idea, just extracted this to its own file, i didn't write this code :)
💚 Build Succeeded |
💚 Build Succeeded |
filters and query are explicitly passed down to dashboard embeddables (visualize and saved search)
resolves #16641, resolves #16595