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.
Recommended best practices for React development
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
- Are concerned with
Container
:- Are concerned with
how things work
- Provide the data and behavior to presentational or other container components
- Are concerned with
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%"}
]
}
]
}