Skip to content

Instantly share code, notes, and snippets.

@siddharthlatest
Last active October 19, 2020 06:53
DejaVu - An ElasticSearch databrowser built with ReactJS

The unmet need

We wanted a lightweight ElasticSearch data browser to include within the Appbase.io dashboard. We started out with evaluating existing browsers to see if we could repurpose them for our needs.

We were primarily looking for -

  1. Client-side rendering: Introducing either server-side code or database coupling would introduce performance hits and make hosting more prone to more failure scenarios; we felt strongly about client-side rendering.
  2. Déjà vu: While a polished UI is starting to become the norm in modern apps, we found that some data browsers have yet to match up in this regards.

We evaluated the most popular data browsers and found them lacking with either their client-side rendering capabilities or their UI / Ux sensibilities.

  • Kibana is the defacto visualization tool for ElasticSearch and is very configurable. The deal breaker with Kibana for us was it's tight coupling with ElasticSearch, which comes with a significant performance penalty in a multi-tenant setting (one kibana index per tenant).

  • elasticsearch-head is a promising feature rich databrowser and more. After spending a couple of weeks tweaking the UI looks of elasticsearch-head (the default interface has a "back to Windows XP" feel), we felt less productive and it came with so many options we didn't care about.

  • elasticsearch-browser is yet another data browser - it misses both the charm of Kibana and the feature richness of elasticsearch-head.

DejaVu - The ElasticSearch data browser

DejaVu started out as a one week project to build a lightweight browser with no server-side dependencies and a modern minimalistic UI. It took us anything but, as we practical challenges with displaying data effectively and our goals expanded to improve the hackability and add support for streaming data feeds.

Full-width image of the databrowser

Streaming data feeds allow us to continuously update the data browser view (thanks to appbase.io!) as the underlying data changes.

GIF for showing a part of the databrowser with an insertion and an update operation


<Unmodified>

Why React ?

You can control the DOM without exactly telling how to reach there, but just by telling what it should look like in an object-oriented fashion. When the data changes, React conceptually hits the "refresh" button, and knows to only update the changed parts. Other options like angular and JQuery fall into the category of frameworks which let you manipulate the DOM "easily". This is sometimes bad since we just want the template to render the data in a particular fashion once we let it know what the data is. The basic problem with most front-end frameworks is letting the html know when to change its content, using the setState method for example. Take a look at how we render the types for example in the HomePage component:

    getStreamingTypes: function(){
        feed.getTypes( function(update){
            this.setState({types: update});
        }.bind(this));
    },

And then in the render we just do:

        return (
            <div className='left-tab'>
            <div className="app-desc"><span className="app-name">{appname}</span></div>
            <ul className='fa-ul types-list'>
                {rowObj}
            </ul>
            </div>
        );

One of my favourite blogs on react - http://jlongster.com/Removing-User-Interface-Complexity,-or-Why-React-is-Awesome

It looks like..... well nevermind !

We gave it very minimal styling and functionality so that you can tweak/modify this to your needs. Don't worry we won't sue you, its MIT licenced. A sneak peak into what it looks like and what it does: databrowser

Let's deep dive into the UI crux ?

Two main reasons :

  1. We had to build the whole table functionality ourselves The problem with most data tables out there is the amount of flexibility you get with respect to CSS transitions. For example take the case of http://griddlegriddle.github.io/Griddle/index.html. We felt it was a great tool but we couldn't show CSS transitions on new elements. Secondly we couldn't properly customise the layout of the elements("settings" for example). They simply break down when there are too many columns. Most tools like http://handsontable.com/ depended on jquery. Its not a good idea to use reactjs with jquery.
  2. Because its react .. You have to create a component for every small thing, like for dropdownn, checkboxes etc. For example see this piece of code that does just this before-copy --> after-copy
var Expire = React.createClass({
  getDefaultProps: function(){
    return {delay: 1000};
  },
  getInitialState: function(){
    return {visible: true};
  },
  componentWillReceiveProps: function(nextProps){
    // reset the timer if children are changed
    if (nextProps.children !== this.props.children) {
      this.setTimer();
      this.setState({visible: true});
    }
  },
  handleClick: function(){
    this.setTimer();
    var apply = document.getElementById('for-copy');
    execCommandOnElement(apply, "copy");

  },
  setTimer: function(){
    // clear any existing timer
    this._timer != null ? clearTimeout(this._timer) : null;

    // hide for `delay` milliseconds
    this.setState({visible: false});
    this._timer = setTimeout(function(){
      this.setState({visible: true});
      this._timer = null;
    }.bind(this), this.props.delay);
  },
  render: function(){
    return this.state.visible 
           ? <div>
                <a>
                    <i 
                    onClick={this.handleClick}
                    className='fa copy-board text-center fa-clipboard' 
                    id='normal-clipboard-before'/>
                </a>
             </div>
           : <i 
              className='fa fa-check' 
              id='normal-clipboard-after'/>;
  }
});
  1. It's on the frontend

##Implementation I will cover only the very important ones especially explaining why React is the new black in the front-end ecosystem.

Basic Structure

The way this app is structured is : So the data flows from the main parent component HomePage to its children components and so on. So who gives it the data ? The feed.js has get functions that fetch data using an elasticsearch client from an endpoint of streaming data and is used by HomePage Component.

feed.getData(typeName, function(update){
  var update = this.flatten(update, this.injectLink),
      key = rowKeyGen(update);

Then it's passed to the table. This is the render method of Table

    render: function() {
        if(this.props.renderRows.length <= 1){
            return(
                    <div id='table-container' className="waiting">
                        <i className="fa fa-spinner fa-pulse fa-5x centered"></i>
                    </div>
                )
        }
        return (
            <div id='table-container' className="table-container">
                <table id="data-table"
                className="table table-striped table-bordered">
                    <thead id='columns'>
                        <tr>
                            {this.props.renderColumns}
                        </tr>
                    </thead>
                    <tbody className='exp-scrollable'>
                            {this.props.renderRows}
                    </tbody>
                </table>
            </div>
        );
    }

If you observe carefully you can see this.props.<something>. This is basically the React's way of passing arguments to components (Remember components are just like objects). Every time you call the Table object i.e. every time change in data takes place, you don't have to tweak the html, React will take care of it automatically and update your DOM in the most efficient way. The working of the rest of the code is documented in-line on my github repo.

</unmodified>


If you have read this far ...

why not just use it and let us know what you think? It's as easy as

  • bower install dejavu-databrowser

  • update the config.json file with your ElasticSearch host URL and security credentials.

An example configuration from an appbase.io test app

JSON snippet with the configuration of createnewtestapp01 app.

Future Roadmap

Development

While DejaVu is self-sufficient, we would like to:

  1. Add commandline and GUI options for specifying ElasticSearch host URL configs.
  2. Add scrollspy effect on the databrowser top row.
  3. Add a search bar GUI.

Distribution

DejaVu is already available as a bower package and is hosted on github pages here. Down the road, we would like to:

  1. Package it as a Chrome extension.
  2. Package it as an ElasticSearch site plugin.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment