Building a monitoring dashboard with React and Python

Recently I needed to build a custom monitoring dashboard to present some realtime system updates. The dashboard interface needed to be flexible and maintainable in order to be customised.

Codepen.io developing

As a quick mockup I created this codepen using the React and ReactDOM CDN. It uses a static hashmap to represent the individual services. The content was written using JSX and ES7 synatx so it also requires a babel transpiler to convert before rendering.

See the pen on CodePen.

I tried to follow some of the recommended best practices for React development. One the main points in React development is to split your components into two separate types:

  • Presentational:
    • Are concerned with how things look
    • Should be written as functional components unless they need state, lifecycle hooks, or performance optimizations in which case Class is required
    • Examples: Page, Sidebar, Story, UserInfo, List
  • Container:
    • Are concerned with how things work
    • Provide the data and behavior to presentational or other container components

Benefits of This Approach

  • Better separation of concerns
  • Better reusability

The example could be improved by use of a state based framework such as Redux however this requires considerable setup.

Project developing

Mini Monitoring Dashboard - GitHub Project

The next stage was to combine the above changes into an all-in-one server side solution. For the most part this was just a copy and paste of the core HTML, CSS and JSX elements into my server side code base.

I should point out that I intentionally opted for Python as my server side solution rather than use Nodejs. In hindsight it would have been more convenient to use Nodejs especially for support of Common JS modules but I knew that at some point this project was going to have to be integrated into another python code base.

Updating JSX

With the dashboard code available in the python flask templates and static folders the next step was to provide a solution to transpile the ES7 and JSX syntax into a javascript file. If I had time I could have setup WebPack or some other javascript build tool to do this for me but since I was using Python this seemed overkill. My solution was to build the following script:

#!/bin/bash

npm install --save-dev babel-cli babel-plugin-transform-react-jsx babel-preset-es2017
babel src/static/js/app.jsx --plugins transform-react-jsx --presets es2017 --out-file src/static/js/app.js

Axios

In the past for Ajax calls I would use jQuery but these days its a little overkill when combined with other javascript frameworks. As an alternative I decided to go with Axios. I created the following function to call the /example endpoint asynchronously and set the state attribute services.

fetchData() {
    axios.get('/example')
    .then(({data}) => {
        this.setState(
            {services: data.services}
        );
    })
    .catch(function (error) {
        console.log(error);
    });
}

The next step was to periodically update the screen every 10 seconds or so. I could have just refreshed the page with window.reload or a html meta tag but the user experience isn’t very nice. React Components can use intervals to periodically update content so I went with that approach:

componentDidMount() {
    // on page load
    this.fetchData();
}

componentWillMount() {
    // updates every 10 seconds
    const id = setInterval(this.fetchData, 10000);
    this.setState({intervalId: id});
}

componentWillUnmount() {
    clearInterval(this.state.intervalId);
}

Configuration

The project contains the file example.json which ca be used to update the list of services.

At this point you can only edit the following:

Field Description
service.name Service Name displayed in the dashboard panel
service.measurements An array of measurements for display under the service panel. These are typically of the form {"Name":"Value"}
service.trends An array of trends for display under the service panel. These are typically of the form {"Type": "Value"}. The type here can be “UP” or “DOWN” in order to display the corresponding icon.

Example json file:

{
  "services": [
    {
      "name": "Service 0",
      "measurements": [
        {"Submissions": "49"},
        {"Completed": "4"}
      ],
      "trends": []
    },
    {
      "name": "Service 1",
      "measurements": [
        {"Completed": "10"}
      ],
      "trends": [
        {"UP": "30%"}
      ]
    }
  ]
}