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
Refactor and improve Visualize Loader #15157
Conversation
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.
looks really nice, some small updates to the docs would make me very happy :)
src/ui/public/visualize/loader.js
Outdated
* @return {Promise.<EmbeddedVisualizeHandler>} A promise that resolves to the | ||
* handler for this visualization as soon as the saved object could be found. | ||
*/ | ||
embedVisualizationWithId: async (element, id, params) => { |
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.
id vs savedVisualizationId .... well i guess as we have the docs now its quite clear, but in general our style guide directs to using variable names that are descriptive
which is explained later in this documentation. | ||
- `getVisualizationList()`: which returns promise which gets resolved with a list of saved visualizations | ||
- `embedVisualizationWithId(container, savedId, params)`: which embeds visualization by id | ||
- `embedVisualizationWithSavedObject(container, savedObject, params)`: which embeds visualization from saved object |
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 parts describing the params of directive should be moved here as well (not just deleted) ...
like time-range, showSpyPanel, uiState and appState should probably have some explanation, as well as newly introduced class and data attributes that can be passed in.
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.
ah sorry, i missed the part where you reference the source code and that all parameters are actually described there. ignore my above comment
will this resolve the IE problem as well (#15150) ? |
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.
LGTM, waiting for green CI
can you test if IE problem is resolved (i think it should be, as the container.html('')
was actually causing that
I added more documentation on the |
Why is this labeled as blocked @timroes? Should I still review, or wait till it's unblocked? |
@stacey-gammon I am currently needing to fix the way we get access to angular with another PR. I will ping you once I need another review. Thanks! |
This reverts commit 160e47d.
d19cba5
to
cafdda8
Compare
@stacey-gammon @thomasneirynck This PR is now ready for a review. It now uses the I also fixed a small bug in the test_utils, that slipped that PR that time with this PR. |
src/ui/public/visualize/loader.js
Outdated
* This is especially useful if you used `append: true` in the parameters where | ||
* the visualization will be appended to the specified container. | ||
*/ | ||
get element() { |
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 a fan of native getters in Javascript, at least not now. They really hurt navigability in most IDEs, and do not make transparent if you are getting a direct reference to an object or a copy.
e.g. property access in Javascript is pretty straightforward. But with getters we introduce pseudo-properties, where the semantics are just unnecessarily convoluted (especially because IDEs aren't good at picking up on it)
if (myInstance.myProperty === myInstance.myProperty){
//?!?!?! maybe, maybe not.
}
When using a method call , e.g. myInstance.getMyProperty()
, users don't make as many assumptions. The other advantage is that most Javascript IDEs are getting pretty decent at navigating across types when using methods as opposed to property-access.
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.
My main reason to use a property was, to give read only access to the element. So I am fine by replacing it with a getElement()
method.
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 a pretty great change, 🙇♂️ !
Left some minor comments for your consideration.
src/ui/public/visualize/loader.js
Outdated
this._element = element; | ||
this._scope = scope; | ||
this._renderComplete = new Promise(resolve => { | ||
this._element.on('renderComplete', resolve); |
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 relies on the assumption visualizations only fire renderComplete once. Which they don't. (e.g. maps are interactive, and modify the UI-state, rerending).
I think we can make this assumption in this context (people need to embed and are just interested in the first "success" status), but then we should immediately remove the listener after resolving.
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.
Hmm good point. I am not sure if people will just need to listen for the first render. So I would actually check with some people actually already using this API, to see what their use cases would be. I would either use the promise, rename the method and only listen once, or alternatively implement a proper callback mechanism to register and deregister for renderComplete
events. But I would rather have people to use methods of this API, than needing to listen for the hardcoded string themselves, which will make it harder for us later to change implementations.
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.
Maybe we could also for convenience do both, offer the whenFirstRenderComplete()
promise and the event mechanism.
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.
@kobelb - care to pop in here and just make sure the renderComplete stuff should work? I confirmed the tests for print layout pass, and that reports with TSVB and timelion are generated as expected. I think that would trigger an issue if render complete wasn't being counted accurately, but I'm not 100% sure.
src/ui/public/visualize/loader.js
Outdated
* @returns {Promise} Promise, that resolves as soon as the visualization is done rendering. | ||
*/ | ||
onRenderComplete() { | ||
return this._renderComplete; |
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.
rename to whenRenderComplete, because it is only a single promise, set in the constructor.
src/ui/public/visualize/loader.js
Outdated
* You can alternatively pass a jQuery element instead. | ||
* @param {Object} savedObj The savedObject as it could be retrieved by the | ||
* `savedVisualizations` service. | ||
* @param {Object} params A list of paramters that will influence rendering. |
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.
Since we are rusing the shape of this options object, I'd consider using the typedef functionality to describe this shape instead. http://usejsdoc.org/tags-typedef.html
Then you can just reference it in your params, like
@typedef EmbedVisualizationParams
@property {AppState} appState
....
//and then reuse it in your method docs
@param {EmbedVisualizationParams} params
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.
Will change this, thanks.
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.
Just to confirm, the changes to how the embeddable_factory renders the visualize template is going to follow suit in a part 2?
I checked the sharing stuff, and all seems to work as expected.
I wonder how this will eventually fit in with the dashboard embeddable stuff. I actually just recently renamed a class called EmbeddableVisualizeHandler
to EmbeddableVisualizeFactory
, so no longer would be a naming conflict, though in my final vision (for now), I have a class called EmbeddableHandler
.
It all feels very similar, though I don't know enough about the visualize stuff right now to know how or whether it would converge.
src/ui/public/visualize/loader.js
Outdated
* A handler to the embedded visualization. It offers several methods to interact | ||
* with the visualization. | ||
*/ | ||
class EmbeddedVisualizeHandler { |
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.
nit, take it or leave it, but I think this class would be more discoverable in its own 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.
Yeah, I already thought about that too. And since you suggest it too, I will do so :)
src/ui/public/visualize/loader.js
Outdated
this._element = element; | ||
this._scope = scope; | ||
this._renderComplete = new Promise(resolve => { | ||
this._element.on('renderComplete', resolve); |
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.
@kobelb - care to pop in here and just make sure the renderComplete stuff should work? I confirmed the tests for print layout pass, and that reports with TSVB and timelion are generated as expected. I think that would trigger an issue if render complete wasn't being counted accurately, but I'm not 100% sure.
I created an own folder for the loader to split up files, added an listener interface for |
* Simplify promise setup logic * Import template from own file * Use angular.element instead of jquery * Add documentation for loader methods * Add params.append * Remove params.editorMode * Clarify when returned promise resolves * Add element to handler * Allow setting CSS class via loader * Use render-counter on visualize * Use Angular run method to get access to Private service * Allow adding data-attributes to the vis element * Refactor loader to return an EmbeddedVisualizeHandler instance * Use this.destroy for previous API * Remove fallback then method, due to bugs * Reject promise from withId when id not found * Add tests * Change developer documentation * Revert "Use Angular run method to get access to Private service" This reverts commit 160e47d. * Rename parameter for more clarity * Add more documentation about appState * Fix broken test utils * Use chrome to get access to Angular * Move loader to its own folder * Use a method instead of getter for element * Add listeners for renderComplete events * Use typedef to document params * Fix documentation
* Simplify promise setup logic * Import template from own file * Use angular.element instead of jquery * Add documentation for loader methods * Add params.append * Remove params.editorMode * Clarify when returned promise resolves * Add element to handler * Allow setting CSS class via loader * Use render-counter on visualize * Use Angular run method to get access to Private service * Allow adding data-attributes to the vis element * Refactor loader to return an EmbeddedVisualizeHandler instance * Use this.destroy for previous API * Remove fallback then method, due to bugs * Reject promise from withId when id not found * Add tests * Change developer documentation * Revert "Use Angular run method to get access to Private service" This reverts commit 160e47d. * Rename parameter for more clarity * Add more documentation about appState * Fix broken test utils * Use chrome to get access to Angular * Move loader to its own folder * Use a method instead of getter for element * Add listeners for renderComplete events * Use typedef to document params * Fix documentation
The 6.x backported was just reverted due to a bad backport, so please submit a new backport with the conflicts resolved. |
* Simplify promise setup logic * Import template from own file * Use angular.element instead of jquery * Add documentation for loader methods * Add params.append * Remove params.editorMode * Clarify when returned promise resolves * Add element to handler * Allow setting CSS class via loader * Use render-counter on visualize * Use Angular run method to get access to Private service * Allow adding data-attributes to the vis element * Refactor loader to return an EmbeddedVisualizeHandler instance * Use this.destroy for previous API * Remove fallback then method, due to bugs * Reject promise from withId when id not found * Add tests * Change developer documentation * Revert "Use Angular run method to get access to Private service" This reverts commit 160e47d. * Rename parameter for more clarity * Add more documentation about appState * Fix broken test utils * Use chrome to get access to Angular * Move loader to its own folder * Use a method instead of getter for element * Add listeners for renderComplete events * Use typedef to document params * Fix documentation
* Simplify promise setup logic * Import template from own file * Use angular.element instead of jquery * Add documentation for loader methods * Add params.append * Remove params.editorMode * Clarify when returned promise resolves * Add element to handler * Allow setting CSS class via loader * Use render-counter on visualize * Use Angular run method to get access to Private service * Allow adding data-attributes to the vis element * Refactor loader to return an EmbeddedVisualizeHandler instance * Use this.destroy for previous API * Remove fallback then method, due to bugs * Reject promise from withId when id not found * Add tests * Change developer documentation * Revert "Use Angular run method to get access to Private service" This reverts commit 160e47d. * Rename parameter for more clarity * Add more documentation about appState * Fix broken test utils * Use chrome to get access to Angular * Move loader to its own folder * Use a method instead of getter for element * Add listeners for renderComplete events * Use typedef to document params * Fix documentation
This PR refactors the
VisualizeLoader
. The aim is to use the loader instead of the<visualize>
directive in the future, so that we:This PR also adds all required methods and functionality, that we could refactor the dashboard to use this API instead of rendering a
<visualize>
directive itself.The PR changes roughly the following things:
embedVisualizationWithSavedObject
directly instead of after renderingcssClass
,dataAttrs
andappend
attributes (required for dashboard)editorMode
params, since this wasn't working properly anyway (due to us inheriting$rootScope
)angular.element
instead ofjQuery
With this PR we would also recommend not to use
<visualize>
directly anymore. That gives us the option to maybe remove the Angular directive altogether in the long run, or at least being able to "more safely" change it if needed.Fixes #15146 (the actual root cause - since this ticket is already closed)
This is required to implement #15153
Release Note: Do not use the
<visualize>
directive anymore to embed a visualization. Use the Visualize Loader instead.