How to create drop down box with filter options for query on custom visualisation?

I have written a custom visualisation for Kibana 6.5, which has its own custom request and response handlers. It queries elasticsearch and returns all the data for the chosen time period in its raw format. My issue is that I need to apply a filter to this data when I do the search. I want these filters to be chosen on the screen via 2-3 drop down boxes (or something similar), and then once they are chosen I can execute the search.

So for example, my index has fields constellation and gms, both of which which are type text. They each have a certain number of values. So if I choose for constellation constellationValue1, and for gms gmsValue5, I then want to execute the search where constellation:"constellationValue1" and "gms:gmsValue5, and have all the data that matches this criteria returned (for the chosen time period).

So my question is 2 fold:

  1. How do I add to my UI the drop down boxes with the options for the filter values?
  2. How do I pass these choices into my request handler?

For the second part, I know that the requestHandler takes 3 parameters: params, queryFilter and timeFilter. I already use timeFilter to search for the given time period, but can I use the other two to pass the values from the drop down boxes into the query? Is that how it would work? I have seen in this documentation on filter context that you can add a filter to the query. Is this the correct approach?

My code is below for my current visualisation and the request handler, I've also attached a screenshot of what the visualisation looks like at the moment. I want to replace the current metrics and buckets schema with what I have described above. I simply found the code for those online as a placeholder for where I would like these to go, I don't know what they actually do or how they work at this time.

self_changing_vis.js

import { VisFactoryProvider } from 'ui/vis/vis_factory';
import { VisTypesRegistryProvider } from 'ui/registry/vis_types';

import { SelfChangingEditor } from './self_changing_editor';
import { SelfChangingComponent } from './self_changing_components';

import { Schemas } from 'ui/vis/editors/default/schemas';
import optionsTemplate from './options_template.html';
import { RequestHandlerProvider } from './requestHandler.js';
import handleResponse  from './responseHandler.js';


const myResponseHandler = (vis, response) => {
  // transform the response (based on vis object?)
  console.log('1: ', response);
  console.log('2 : ', vis);
  return response;
};

function SelfChangingVisType(Private) {
  const VisFactory = Private(VisFactoryProvider);
  const RequestHandler = Private(RequestHandlerProvider);

  return VisFactory.createReactVisualization({
    name: 'self_changing_vis',
    title: 'Skyplot',
    icon: 'visControls',
    description: 'This visualization is able to change its own settings, that you could also set in the editor.',
    visConfig: {
      component: SelfChangingComponent,
      defaults: {
        counter: 0,
        constellation: 'GPS'
      },
    },
    editor: 'default',
    editorConfig: {
      optionsTemplate: optionsTemplate,
      schemas: new Schemas([
        {
          group: 'metrics',
          name: 'metric',
          title: 'Metric',
          min: 1,
          aggFilter: ['!derivative', '!geo_centroid'],
          defaults: [
            { type: 'count', schema: 'metric' }
          ]
        }, {
          group: 'buckets',
          name: 'segment',
          title: 'Bucket Split',
          min: 0,
          max: 1,
          aggFilter: ['!geohash_grid', '!filter']
        }
      ]),
    },
    requestHandler: RequestHandler.handle,
    responseHandler: handleResponse,
  });
}

VisTypesRegistryProvider.register(SelfChangingVisType);

requestHandler.js

const getRequestBody = (params, queryFilter, timeFilter) => {
  console.log('params: ', params);
  console.log('queryFilter: ', queryFilter);
  const requestBody = {
    'query': {
      'bool': {
        'must': [
          {
            'range': {
              'timestamp': {
                'gte': timeFilter.from,
                'lte': timeFilter.to
              }
            }
          }
        ]
      }
    }
  };
  return requestBody;
};

export function RequestHandlerProvider(Private, es) {
  return {
    handle(vis) {
      const { timeFilter, queryFilter } = vis.API;
      return new Promise(resolve => {
        const params = vis.params;
        const requestBody = getRequestBody(params, queryFilter, timeFilter._time);
        es.search({
          index: 'observed_range_error',
          body: requestBody
        }).then(result => resolve(result));
      });
    }
  };
}

Screenshot

Hi @reillye,

Thanks for the detailed explanation! I'm happy to try to help sort this out with you, but first I just wanted to ask if you had tried playing around with the Controls visualization? It pretty much solves the exact use case you are describing, except it is designed for use alongside other visualizations in a dashboard, rather than in a single standalone visualization.

If you are ultimately aiming to add your visualization to a dashboard, I'd first recommend checking those out if you haven't yet to see if it saves you the trouble of building something custom. You might be able to get away with just building whatever visualization you want to create, and then configure a separate controls visualization to use in a dashboard, which should apply the filter for you.

If that doesn't work for your project, feel free to reply and I'll see if I can help you navigate further!

Thanks,

Luke

Hi @lukeelmers

No I wasn't aware of the Controls Visualisation. I just tried it, and it does look like it could potentially solve my issue, however nothing happens when I create a dashboard with it and my Skyplot. I can only assume this is because the query in the request handler does not accommodate filters? How can I add them to it? I'm guessing I need to use the queryFilter field somehow?

Hi @lukeelmers,

Are you able to help my filtering issue in any way? I'm quite stuck on it at the moment...