Skip to content
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

Merged
merged 28 commits into from
Dec 1, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
41696ad
Simplify promise setup logic
Nov 24, 2017
20b7beb
Import template from own file
Nov 24, 2017
8781d30
Use angular.element instead of jquery
Nov 24, 2017
0ea987f
Add documentation for loader methods
Nov 24, 2017
356b595
Add params.append
Nov 24, 2017
b952e17
Remove params.editorMode
Nov 24, 2017
80a3289
Clarify when returned promise resolves
Nov 24, 2017
5973c2f
Add element to handler
Nov 24, 2017
e0f5035
Allow setting CSS class via loader
Nov 24, 2017
1c87ef1
Use render-counter on visualize
Nov 24, 2017
8b891ad
Use Angular run method to get access to Private service
Nov 24, 2017
a017fd9
Allow adding data-attributes to the vis element
Nov 24, 2017
fbdb108
Refactor loader to return an EmbeddedVisualizeHandler instance
Nov 26, 2017
618a59b
Use this.destroy for previous API
Nov 26, 2017
b15b54a
Remove fallback then method, due to bugs
Nov 26, 2017
8b89264
Reject promise from withId when id not found
Nov 26, 2017
c1df85e
Add tests
Nov 26, 2017
dd65312
Change developer documentation
Nov 27, 2017
49ca6d4
Revert "Use Angular run method to get access to Private service"
Nov 27, 2017
c6f21b6
Rename parameter for more clarity
Nov 28, 2017
c667336
Add more documentation about appState
Nov 28, 2017
ecba46c
Fix broken test utils
Nov 30, 2017
cafdda8
Use chrome to get access to Angular
Nov 30, 2017
0f8ed06
Move loader to its own folder
Dec 1, 2017
30d2c75
Use a method instead of getter for element
Dec 1, 2017
71e3eb7
Add listeners for renderComplete events
Dec 1, 2017
01a673d
Use typedef to document params
Dec 1, 2017
fd0758a
Fix documentation
Dec 1, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,89 +1,71 @@
[[development-embedding-visualizations]]
=== Embedding Visualizations

There are two different angular directives you can use to insert a visualization in your page.
To display an already saved visualization, use the `<visualize>` directive.
To reuse an existing Visualization implementation for a more custom purpose, use the `<visualization>` directive instead.

==== VisualizeLoader
The `VisualizeLoader` class i the easiest way to embed a visualization into your plugin. It exposes
two methods:

- `getVisualizationList()`: which returns promise which gets resolved with list of saved visualizations
- `embedVisualizationWithId(container, savedId, params)`: which embeds visualization by id
- `embedVisualizationWithSavedObject(container, savedObject, params)`: which embeds visualization from saved object

`container` should be a dom element to which visualization should be embedded
`params` is a parameter object where the following properties can be defined:

- `timeRange`: time range to pass to `<visualize>` directive
- `uiState`: uiState to pass to `<visualize>` directive
- `appState`: appState to pass to `<visualize>` directive
- `showSpyPanel`: showSpyPanel property to pass to `<visualize>` directive
There are two different methods you can use to insert a visualization in your page.

To display an already saved visualization, use the `VisualizeLoader`.
To reuse an existing visualization implementation for a more custom purpose,
use the Angular `<visualization>` directive instead.

==== `<visualize>` directive
The `<visualize>` directive takes care of loading data, parsing data, rendering the editor
(if the Visualization is in edit mode) and rendering the visualization.
The directive takes a savedVis object for its configuration.
It is the easiest way to add visualization to your page under the assumption that
the visualization you are trying to display is saved in kibana.
If that is not the case, take a look at using `<visualization>` directive.

The simplest way is to just pass `saved-id` to `<visualize>`:

`<visualize saved-id="'447d2930-9eb2-11e7-a956-5558df96e706'"></visualize>`
==== VisualizeLoader

For the above to work with time based visualizations time picker must be present (enabled) on the page. For scenarios
where timepicker is not available time range can be passed in as additional parameter:
The `VisualizeLoader` class is the easiest way to embed a visualization into your plugin.
It will take care of loading the data and rendering the visualization.

`<visualize saved-id="'447d2930-9eb2-11e7-a956-5558df96e706'"
time-range="{ max: '2017-09-21T21:59:59.999Z', min: '2017-09-18T22:00:00.000Z' }"></visualize>`
To get an instance of the loader, do the following:

Once <visualize> is done rendering the element will emit `renderComplete` event.
["source","js"]
-----------
import { getVisualizeLoader } from 'ui/visualize/loader';

When more control is required over the visualization you may prefer to load the saved object yourself and then pass it
to `<visualize>`
getVisualizeLoader().then((loader) => {
// You now have access to the loader
});
-----------

`<visualize saved-obj='savedVis' app-state='appState' ui-state='uiState' editor-mode='false'></visualize>` where
The loader exposes the following methods:

`savedVis` is an instance of savedVisualization object, which can be retrieved using `savedVisualizations` service
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
Copy link
Member

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.

Copy link
Member

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


`appState` is an instance of `AppState`. <visualize> is expecting two keys defined on AppState:
Depending on which embed method you are using, you either pass in the id of the
saved object for the visualization, or a `savedObject`, that you can retrieve via
the `savedVisualizations` Angular service by its id. The `savedObject` give you access
to the filter and query logic and allows you to attach listeners to the visualizations.
For a more complex use-case you usually want to use that method.

- `filters` which is an instance of searchSource filter object and
- `query` which is an instance of searchSource query object
`container` should be a DOM element (jQuery wrapped or regular DOM element) into which the visualization should be embedded
`params` is a parameter object specifying several parameters, that influence rendering.

If `appState` is not provided, `<visualize>` will not monitor the `AppState`.
You will find a detailed description of all the parameters in the inline docs
in the {repo}blob/{branch}/src/ui/public/visualize/loader/loader.js[loader source code].

`uiState` should be an instance of `PersistedState`. if not provided visualize will generate one,
but you will have no access to it. It is used to store viewer specific information like whether the legend is toggled on or off.
Both methods return an `EmbeddedVisualizeHandler`, that gives you some access
to the visualization. The `embedVisualizationWithSavedObject` method will return
the handler immediately from the method call, whereas the `embedVisualizationWithId`
will return a promise, that resolves with the handler, as soon as the `id` could be
found. It will reject, if the `id` is invalid.

`editor-mode` defines if <visualize> should render in editor or in view mode.
The returned `EmbeddedVisualizeHandler` itself has the following methods and properties:

*code example: Showing a saved visualization, without linking to querybar or filterbar.*
["source","html"]
-----------
<div ng-controller="KbnTestController" class="test_vis">
<visualize saved-obj='savedVis'></visualize>
</div>
-----------
["source","js"]
-----------
import { uiModules } from 'ui/modules';
- `destroy()`: destroys the underlying Angualr scope of the visualization
- `getElement()`: a reference to the jQuery wrapped DOM element, that renders the visualization
- `whenFirstRenderComplete()`: will return a promise, that resolves as soon as the visualization has
finished rendering for the first time
- `addRenderCompleteListener(listener)`: will register a listener to be called whenever
a rendering of this visualization finished (not just the first one)
- `removeRenderCompleteListener(listener)`: removes an event listener from the handler again

uiModules.get('kibana')
.controller('KbnTestController', function ($scope, AppState, savedVisualizations) {
const visId = 'enter_your_vis_id';
savedVisualizations.get(visId).then(savedVis => $scope.savedObj = savedVis);
});
-----------
You can find the detailed `EmbeddedVisualizeHandler` documentation in its
{repo}blob/{branch}/src/ui/public/visualize/loader/embedded_visualize_handler.js[source code].

When <visualize> is done rendering it will emit `renderComplete` event on the element.
We recommend *not* to use the internal `<visualize>` Angular directive directly.

==== `<visualization>` directive
The `<visualization>` directive takes a visualization configuration and data.
It should be used, if you don't want to render a saved visualization, but specify
the config and data directly.

`<visualization vis='vis' vis-data='visData' ui-state='uiState' ></visualization>` where

Expand Down
4 changes: 2 additions & 2 deletions src/test_utils/public/stub_get_active_injector.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import sinon from 'sinon';
* This method setups the stub for chrome.dangerouslyGetActiveInjector. You must call it in
* a place where beforeEach is allowed to be called (read: inside your describe)
* method. You must call this AFTER you've called `ngMock.module` to setup the modules,
* but BEFORE you first execute code, that uses chrome.getActiveInjector.
* but BEFORE you first execute code, that uses chrome.dangerouslyGetActiveInjector.
*/
export function setupInjectorStub() {
beforeEach(ngMock.inject(($injector) => {
Expand All @@ -30,7 +30,7 @@ export function setupInjectorStub() {
*/
export function teardownInjectorStub() {
afterEach(() => {
chrome.getActiveInjector.restore();
chrome.dangerouslyGetActiveInjector.restore();
});
}

Expand Down
75 changes: 0 additions & 75 deletions src/ui/public/visualize/loader.js

This file was deleted.