Dev on Kibana plugin: navbar icon disappear when switching tabs

I'm very new to plugin development so I'm trying to figure the proper way to develop plugins. My goal is to add an icon to navbar.

I used navbarExtensions and it works great. The icon shows up in discover tab and that's what I want. The issue is: if I click on visualization tab and come back to discover tab, the icon disappeared. I have to actually refresh the discover page to get my icon back.

Admittedly I used a little hack to inject the icon, so I'm wondering if there's a better way to make the icon work, i.e. don't disappear when switching tabs.

Much appreciated.

Are you using the uiExports: { navbarExtensions: [...] } definition in your plugin, or are you using a hack? It's not really clear from your comment. If you are using navbarExtensions, then the control shouldn't disappear like that. If you're injecting it with a hack, using jquery or something, then that could explain what you're seeing.

Anyway, using navbarExtensions is actually pretty easy, if poorly documented (and not having a lot of examples). Essentially, you add the following to your plugin definition:

uiExports: {
      navbarExtensions: [
        'plugins/<your-plugin-name>/<path-to-file>',
      ]
}

Do that for every control you want to add. Next, you register your navbarExtension so that it loads in the app(s) you'd like. The comments in kbn_top_nav.js are helpful here, since that's where navbarExtensions inject themselves:

/*
* @param {Array<Object>|KbnTopNavController} config
* @param {string} config[].key
*        - the uniq key for this menu item.
* @param {string} [config[].label]
*        - optional, string that will be displayed for the menu button.
*        Defaults to the key
* @param {string} [config[].description]
*        - optional, used for the screen-reader description of this menu
*        item, defaults to "Toggle ${key} view" for templated menu items
*        and just "${key}" for programatic menu items
* @param {boolean} [config[].hideButton]
*        - optional, set to true to prevent a menu item from being created.
*        This allow injecting templates into the navbar that don't have
*        an associated template
* @param {function} [config[].run]
*        - optional, function to call when the menu item is clicked, defaults
*        to toggling the template
*/

You will need to define, at a minimum, an appName (the name of the app to inject into), a unique key, and I'd encourage you to add a label too since it'll display that text then, which can be more user-friendly. And for basic functionality, you'll probably want a run property as well. So we're left with something like this:

const navbarExtensions = require('ui/registry/navbar_extensions');

function discoverControlProvider() {
  return {
    appName: 'discover',
    key: 'plugin-name-discover',
    label: 'Click Me',
    run: () => { alert('hey, quit poking me!'); },
  };
}

navbarExtensions.register(discoverControlProvider);

Here, discoverControlProvider can use Angular's dependency injection, so if you need to inject any custom logic to customize the display, or add a tooltip, or show/hide/disable the button, that can be pretty handy. If you want to get really fancy, you can use the template property, which will be evaluated in Angular. With that you can run any custom directive you want, so you can open up a config menu with a bunch of custom controls, for example, which is exactly how Reporting works.

I hope that helps.

Great reply. Appreciate it Joe_Fleming! Yeah I'm using the navbar extension. But it looks like the run argument is only available in 5? I'm using Kibana 4.6.3

I followed 4.6.3 and found it's using a template but I couldn't find more details on it. Could you tell a little about that?

I think you're right, run is new in 5.0. I think it was introduced as a simpler way to add custom functionality. You can still do whatever you need by using template and a custom Angular directive though, since the template is $compiled when the navbar extension is loaded.

Note, however, that in 4.6, the navbar extensions appear to be tied pretty closely to "config templates," which are the added controls that you get underneath the navbar when you click on a button. Examples of this would be save and open menus.

Also note that the parameters for the extension's definition are different in 4.6. There, you will need to include: appName, name, icon, template, and description. You can see how they are used in the navbar extensions directive.

So the previous example could be done using a custom directive and the config-template, more or less as follows:

const module = require('ui/modules').get('myPlugin'); // myPlugin here is just a unique namespace

module.directive('myCustomControl', () => {
  return {
    restrict: 'E',
    scope: {},
    template: '<div><button ng-click="handleClick()">Click Me</button></div>',
    link($scope) {
      $scope.handleClick = function () { 
        alert('hey, quit poking me!'); 
      };
    }
  };
});
require('path/to/my_custom_control'); // directive from above
const navbarExtensions = require('ui/registry/navbar_extensions');

function discoverControlProvider() {
  return {
    appName: 'discover',
    name: 'plugin-name-discover',
    icon: 'fa-puzzle-piece',
    template: '<my-custom-control config-template="configTemplate"></my-custom-control>',
    description: 'custom control',
  };
}

navbarExtensions.register(discoverControlProvider);

There may be some errors in the above, I haven't actually tried to run this. And hopefully I got this right, I'm a bit rusty on the implementation in 4.6, but this is what I pieced together by digging through the source of working examples I have.

Assuming I got it right though, what you should see is a new button using the fa-puzzle-piece icon. Clicking on it should open a dialog underneath the navbar with a single button that says "Click Me", and doing so should show the alert.

This is so great. Thank you Joe_Fleming. Much appreciate it!

1 Like

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.