diff --git a/DEPENDENCIES b/DEPENDENCIES
index 4dac96350..ee102ef9e 100644
--- a/DEPENDENCIES
+++ b/DEPENDENCIES
@@ -492,7 +492,6 @@ find-up                                                          2.1.0
 find-versions                                                    3.2.0            MIT                                  https://github.com/sindresorhus/find-versions.git
 findup-sync                                                      3.0.0            MIT                                  https://github.com/gulpjs/findup-sync.git
 flat-cache                                                       2.0.1            MIT                                  https://github.com/royriojas/flat-cache.git
-flotr2                                                           0.1.0            MIT                                  https://github.com/HumbleSoftware/Flotr2.git
 flush-write-stream                                               1.1.1            MIT                                  https://github.com/mafintosh/flush-write-stream.git
 follow-redirects                                                 1.5.10           MIT                                  git@github.com:follow-redirects/follow-redirects.git
 for-in                                                           1.0.2            MIT                                  https://github.com/jonschlinkert/for-in.git
diff --git a/web/.eslintrc.js b/web/.eslintrc.js
index 795c8bcd0..622a949e8 100644
--- a/web/.eslintrc.js
+++ b/web/.eslintrc.js
@@ -16,12 +16,17 @@ module.exports = {
   },
   'extends': [
     'eslint:recommended',
+    'plugin:react/recommended',
   ],
   'parserOptions': {
     'ecmaVersion': 2018,
+    'ecmaFeatures': {
+      'jsx': true
+    },
     'sourceType': 'module',
   },
   'plugins': [
+    'react'
   ],
   'globals': {
     '_': true,
@@ -49,4 +54,9 @@ module.exports = {
     // We need to exclude below for RegEx case
     "no-useless-escape": 0,
   },
+  'settings': {
+    'react': {
+      'version': 'detect',
+    },
+  }
 };
diff --git a/web/package.json b/web/package.json
index f4c094751..71147404a 100644
--- a/web/package.json
+++ b/web/package.json
@@ -16,12 +16,16 @@
     "copy-webpack-plugin": "^5.1.0",
     "core-js": "^3.2.1",
     "cross-env": "^5.2.0",
+    "enzyme": "^3.11.0",
+    "enzyme-adapter-react-16": "^1.15.2",
     "eslint": "5.15.1",
+    "eslint-plugin-react": "^7.20.3",
     "file-loader": "^3.0.1",
     "iconfont-webpack-plugin": "^4.2.1",
     "image-webpack-loader": "^4.6.0",
     "is-docker": "^1.1.0",
     "jasmine-core": "~3.3.0",
+    "jasmine-enzyme": "^7.1.2",
     "karma": "^4.0.1",
     "karma-babel-preprocessor": "^8.0.0",
     "karma-browserify": "~6.0.0",
@@ -36,6 +40,7 @@
     "optimize-css-assets-webpack-plugin": "^5.0.1",
     "popper.js": "^1.14.7",
     "postcss-loader": "^3.0.0",
+    "prop-types": "^15.7.2",
     "raw-loader": "^1.0.0",
     "sass": "^1.24.4",
     "sass-loader": "^7.1.0",
@@ -50,6 +55,8 @@
     "yarn-audit-html": "^1.1.0"
   },
   "dependencies": {
+    "@babel/plugin-proposal-class-properties": "^7.10.4",
+    "@babel/preset-react": "^7.10.4",
     "@simonwep/pickr": "^1.5.1",
     "acitree": "git+https://github.com/imsurinder90/jquery-aciTree.git#rc.7",
     "alertifyjs": "git+https://github.com/EnterpriseDB/AlertifyJS/#72c1d794f5b6d4ec13a68d123c08f19021afe263",
@@ -67,12 +74,12 @@
     "bootstrap4-toggle": "3.4.0",
     "bowser": "2.1.2",
     "browserify": "~16.2.3",
+    "chart.js": "^2.9.3",
     "codemirror": "^5.54.0",
     "css-loader": "2.1.0",
     "cssnano": "^4.1.10",
     "dropzone": "^5.5.1",
     "exports-loader": "~0.7.0",
-    "flotr2": "git+https://github.com/EnterpriseDB/Flotr2.git",
     "font-awesome": "^4.7.0",
     "immutability-helper": "^3.0.0",
     "imports-loader": "^0.8.0",
@@ -85,6 +92,8 @@
     "moment": "^2.24.0",
     "moment-timezone": "^0.5.23",
     "mousetrap": "^1.6.3",
+    "react": "^16.13.1",
+    "react-dom": "^16.13.1",
     "requirejs": "~2.3.6",
     "select2": "^4.0.6-rc.1",
     "shim-loader": "^1.0.1",
diff --git a/web/pgadmin/dashboard/static/css/dashboard.css b/web/pgadmin/dashboard/static/css/dashboard.css
index 91ab75b62..d951fca97 100644
--- a/web/pgadmin/dashboard/static/css/dashboard.css
+++ b/web/pgadmin/dashboard/static/css/dashboard.css
@@ -24,11 +24,6 @@
     line-height: 30px;
 }
 
-.graph-container {
-    margin-top: 10px;
-    height: 150px;
-}
-
 .icon-postgres:before {
     height: 43px;
     margin-top: 13px;
diff --git a/web/pgadmin/dashboard/static/js/ChartsDOM.js b/web/pgadmin/dashboard/static/js/ChartsDOM.js
new file mode 100644
index 000000000..ee1c5b7fe
--- /dev/null
+++ b/web/pgadmin/dashboard/static/js/ChartsDOM.js
@@ -0,0 +1,37 @@
+import React from 'react';
+import ReactDOM from 'react-dom';
+import Graphs from './Graphs';
+
+export default class ChartsDOM {
+  constructor(container, preferences, sid, did) {
+    this.container = container;
+    this.preferences = preferences;
+    this.sid = sid;
+    this.did = did;
+  }
+
+  mount() {
+    if(this.container) {
+      ReactDOM.render(<Graphs sid={this.sid} did={this.did} preferences={this.preferences}/>, this.container);
+    }
+  }
+
+  unmount() {
+    this.container && ReactDOM.unmountComponentAtNode(this.container);
+  }
+
+  setSidDid(sid, did) {
+    this.sid = sid;
+    this.did = did;
+    this.mount();
+  }
+
+  reflectPreferences(preferences) {
+    this.preferences = preferences;
+    if(preferences.show_graphs) {
+      this.mount();
+    } else {
+      this.unmount();
+    }
+  }
+}
\ No newline at end of file
diff --git a/web/pgadmin/dashboard/static/js/Graphs.js b/web/pgadmin/dashboard/static/js/Graphs.js
new file mode 100644
index 000000000..37cda1279
--- /dev/null
+++ b/web/pgadmin/dashboard/static/js/Graphs.js
@@ -0,0 +1,364 @@
+import React, { useEffect, useRef, useState, useReducer, useCallback, useMemo } from 'react';
+import {LineChart} from 'sources/chartjs';
+import {ChartContainer, DashboardRowCol, DashboardRow} from './dashboard_components';
+import url_for from 'sources/url_for';
+import axios from 'axios';
+import gettext from 'sources/gettext';
+import {getGCD, getEpoch} from 'sources/utils';
+import {useInterval, usePrevious} from 'sources/custom_hooks';
+import PropTypes from 'prop-types';
+
+export const X_AXIS_LENGTH = 75;
+export const POINT_SIZE = 2;
+
+export function transformData(labels, refreshRate) {
+  const colors = ['#00BCD4', '#9CCC65', '#E64A19'];
+  let datasets = Object.keys(labels).map((label, i)=>{
+    return {
+      label: label,
+      data: labels[label] || [],
+      borderColor: colors[i],
+      backgroundColor: colors[i],
+      pointHitRadius: POINT_SIZE,
+    };
+  }) || [];
+
+  return {
+    labels: [...Array(X_AXIS_LENGTH).keys()],
+    datasets: datasets,
+    refreshRate: refreshRate,
+  };
+}
+
+export function legendCallback(chart) {
+  var text = [];
+  text.push('<div class="' + chart.id + '-legend d-flex">');
+  for (var i = 0; i < chart.data.datasets.length; i++) {
+    text.push('<div class="legend-value"><span style="background-color:' + chart.data.datasets[i].backgroundColor + '">&nbsp;&nbsp;&nbsp;&nbsp;</span>');
+    if (chart.data.datasets[i].label) {
+      text.push('<span class="legend-label">' + chart.data.datasets[i].label + '</span>');
+    }
+    text.push('</div>');
+  }
+  text.push('</div>');
+  return text.join('');
+}
+
+export function getStatsUrl(sid=-1, did=-1, chart_names=[]) {
+  let base_url = url_for('dashboard.dashboard_stats');
+  base_url += '/' + sid;
+  base_url += (did > 0) ? ('/' + did) : '';
+  base_url += '?chart_names=' + chart_names.join(',');
+  return base_url;
+}
+
+export function statsReducer(state, action) {
+  let newState = {};
+
+  if(action.reset) {
+    return action.reset;
+  }
+
+  if(!action.incoming) {
+    return state;
+  }
+
+  if(!action.counterData) {
+    action.counterData = action.incoming;
+  }
+
+  Object.keys(action.incoming).forEach(label => {
+    if(state[label]) {
+      if(state[label].length >= X_AXIS_LENGTH) {
+        state[label].unshift();
+      }
+      newState[label] = [
+        action.counter ?  action.incoming[label] - action.counterData[label] : action.incoming[label],
+        ...state[label],
+      ];
+    } else {
+      newState[label] = [
+        action.counter ?  action.incoming[label] - action.counterData[label] : action.incoming[label],
+      ];
+    }
+  });
+  return newState;
+}
+
+const chartsDefault = {
+  'session_stats': {'Total': [], 'Active': [], 'Idle': []},
+  'tps_stats': {'Transactions': [], 'Commits': [], 'Rollbacks': []},
+  'ti_stats': {'Inserts': [], 'Updates': [], 'Delete': []},
+  'to_stats': {'Fetched': [], 'Returned': []},
+  'bio_stats': {'Reads': [], 'Hits': []},
+};
+
+export default function Graphs({preferences, sid, did, enablePoll=true}) {
+  const refreshOn = useRef(null);
+  const prevPrefernces = usePrevious(preferences);
+
+  const [sessionStats, sessionStatsReduce] = useReducer(statsReducer, chartsDefault['session_stats']);
+  const [tpsStats, tpsStatsReduce] = useReducer(statsReducer, chartsDefault['tps_stats']);
+  const [tiStats, tiStatsReduce] = useReducer(statsReducer, chartsDefault['ti_stats']);
+  const [toStats, toStatsReduce] = useReducer(statsReducer, chartsDefault['to_stats']);
+  const [bioStats, bioStatsReduce] = useReducer(statsReducer, chartsDefault['bio_stats']);
+
+  const [counterData, setCounterData] = useState({});
+
+  const [errorMsg, setErrorMsg] = useState(null);
+  const [pollDelay, setPollDelay] = useState(1000);
+
+  useEffect(()=>{
+    let calcPollDelay = false;
+    if(prevPrefernces) {
+      if(prevPrefernces['session_stats_refresh'] != preferences['session_stats_refresh']) {
+        sessionStatsReduce({reset: chartsDefault['session_stats']});
+        calcPollDelay = true;
+      }
+      if(prevPrefernces['tps_stats_refresh'] != preferences['tps_stats_refresh']) {
+        tpsStatsReduce({reset:chartsDefault['tps_stats']});
+        calcPollDelay = true;
+      }
+      if(prevPrefernces['ti_stats_refresh'] != preferences['ti_stats_refresh']) {
+        tiStatsReduce({reset:chartsDefault['ti_stats']});
+        calcPollDelay = true;
+      }
+      if(prevPrefernces['to_stats_refresh'] != preferences['to_stats_refresh']) {
+        toStatsReduce({reset:chartsDefault['to_stats']});
+        calcPollDelay = true;
+      }
+      if(prevPrefernces['bio_stats_refresh'] != preferences['bio_stats_refresh']) {
+        bioStatsReduce({reset:chartsDefault['bio_stats']});
+        calcPollDelay = true;
+      }
+    } else {
+      calcPollDelay = true;
+    }
+    if(calcPollDelay) {
+      setPollDelay(
+        getGCD(Object.keys(chartsDefault).map((name)=>preferences[name+'_refresh']))*1000
+      );
+    }
+  }, [preferences]);
+
+  useInterval(()=>{
+    const currEpoch = getEpoch();
+    if(refreshOn.current === null) {
+      let tmpRef = {};
+      Object.keys(chartsDefault).forEach((name)=>{
+        tmpRef[name] = currEpoch;
+      });
+      refreshOn.current = tmpRef;
+    }
+
+    let getFor = [];
+    Object.keys(chartsDefault).forEach((name)=>{
+      if(currEpoch >= refreshOn.current[name]) {
+        getFor.push(name);
+        refreshOn.current[name] = currEpoch + preferences[name+'_refresh'];
+      }
+    });
+
+    let path = getStatsUrl(sid, did, getFor);
+    axios.get(path)
+      .then((resp)=>{
+        let data = resp.data;
+        setErrorMsg(null);
+        sessionStatsReduce({incoming: data['session_stats']});
+        tpsStatsReduce({incoming: data['tps_stats'], counter: true, counterData: counterData['tps_stats']});
+        tiStatsReduce({incoming: data['ti_stats'], counter: true, counterData: counterData['ti_stats']});
+        toStatsReduce({incoming: data['to_stats'], counter: true, counterData: counterData['to_stats']});
+        bioStatsReduce({incoming: data['bio_stats'], counter: true, counterData: counterData['bio_stats']});
+
+        setCounterData((prevCounterData)=>{
+          return {
+            ...prevCounterData,
+            ...data,
+          };
+        });
+      })
+      .catch((error)=>{
+        if(!errorMsg) {
+          sessionStatsReduce({reset: chartsDefault['session_stats']});
+          tpsStatsReduce({reset:chartsDefault['tps_stats']});
+          tiStatsReduce({reset:chartsDefault['ti_stats']});
+          toStatsReduce({reset:chartsDefault['to_stats']});
+          bioStatsReduce({reset:chartsDefault['bio_stats']});
+          setCounterData({});
+          if(error.response) {
+            if (error.response.status === 428) {
+              setErrorMsg(gettext('Please connect to the selected server to view the graph.'));
+            } else {
+              setErrorMsg(gettext('An error occurred whilst rendering the graph.'));
+            }
+          } else if(error.request) {
+            setErrorMsg(gettext('Not connected to the server or the connection to the server has been closed.'));
+            return;
+          } else {
+            console.error(error);
+          }
+        }
+      });
+  }, enablePoll ? pollDelay : -1);
+
+  return (
+    <>
+      <div data-testid='graph-poll-delay' className='d-none'>{pollDelay}</div>
+      <GraphsWrapper
+        sessionStats={transformData(sessionStats, preferences['session_stats_refresh'])}
+        tpsStats={transformData(tpsStats, preferences['tps_stats_refresh'])}
+        tiStats={transformData(tiStats, preferences['ti_stats_refresh'])}
+        toStats={transformData(toStats, preferences['to_stats_refresh'])}
+        bioStats={transformData(bioStats, preferences['bio_stats_refresh'])}
+        errorMsg={errorMsg}
+        showTooltip={preferences['graph_mouse_track']}
+        showDataPoints={preferences['graph_data_points']}
+        isDatabase={did > 0}
+      />
+    </>
+  );
+}
+
+Graphs.propTypes = {
+  preferences: PropTypes.object.isRequired,
+  sid: PropTypes.oneOfType([
+    PropTypes.string.isRequired,
+    PropTypes.number.isRequired,
+  ]),
+  did: PropTypes.oneOfType([
+    PropTypes.string.isRequired,
+    PropTypes.number.isRequired,
+  ]),
+  enablePoll: PropTypes.bool,
+};
+
+export function GraphsWrapper(props) {
+  const sessionStatsLegendRef = useRef();
+  const tpsStatsLegendRef = useRef();
+  const tiStatsLegendRef = useRef();
+  const toStatsLegendRef = useRef();
+  const bioStatsLegendRef = useRef();
+  const options = useMemo(()=>({
+    legendCallback: legendCallback,
+    animation: {
+      duration: 0,
+    },
+    hover: {
+      animationDuration: 0,
+    },
+    responsiveAnimationDuration: 0,
+    legend: {
+      display: false,
+    },
+    elements: {
+      point: {
+        radius: props.showDataPoints ? POINT_SIZE : 0,
+      },
+    },
+    tooltips: {
+      enabled: props.showTooltip,
+      callbacks: {
+        title: function(tooltipItem, data) {
+          let title = '';
+          try {
+            title = parseInt(tooltipItem[0].xLabel)*data.refreshRate + gettext(' seconds ago');
+          } catch (error) {
+            title = '';
+          }
+          return title;
+        },
+      },
+    },
+    scales: {
+      yAxes: [{
+        ticks: {
+          min: 0,
+          userCallback: function(label) {
+            if (Math.floor(label) === label) {
+              return label;
+            }
+          },
+          fontColor: getComputedStyle(document.documentElement).getPropertyValue('--color-fg'),
+        },
+        gridLines: {
+          drawBorder: false,
+          zeroLineColor: getComputedStyle(document.documentElement).getPropertyValue('--border-color'),
+          color: getComputedStyle(document.documentElement).getPropertyValue('--border-color'),
+        },
+      }],
+      xAxes: [{
+        display: false,
+        gridLines: {
+          display: false,
+        },
+        ticks: {
+          display: false,
+          reverse: true,
+        },
+      }],
+    },
+  }), [props.showTooltip, props.showDataPoints]);
+  const updateOptions = useMemo(()=>({duration: 0}), []);
+
+  const onInitCallback = useCallback(
+    (legendRef)=>(chart)=>{
+      legendRef.current.innerHTML = chart.generateLegend();
+    }
+  );
+
+  return (
+    <>
+    <DashboardRow>
+      <DashboardRowCol breakpoint='md' parts={6}>
+        <ChartContainer id='sessions-graph' title={props.isDatabase ?  gettext('Database sessions') : gettext('Server sessions')} legendRef={sessionStatsLegendRef} errorMsg={props.errorMsg}>
+          <LineChart options={options} data={props.sessionStats} updateOptions={updateOptions}
+            onInit={onInitCallback(sessionStatsLegendRef)}/>
+        </ChartContainer>
+      </DashboardRowCol>
+      <DashboardRowCol breakpoint='md' parts={6}>
+        <ChartContainer id='tps-graph' title={gettext('Transactions per second')} legendRef={tpsStatsLegendRef} errorMsg={props.errorMsg}>
+          <LineChart options={options} data={props.tpsStats} updateOptions={updateOptions}
+            onInit={onInitCallback(tpsStatsLegendRef)}/>
+        </ChartContainer>
+      </DashboardRowCol>
+    </DashboardRow>
+    <DashboardRow>
+      <DashboardRowCol breakpoint='md' parts={4}>
+        <ChartContainer id='ti-graph' title={gettext('Tuples in')} legendRef={tiStatsLegendRef} errorMsg={props.errorMsg}>
+          <LineChart options={options} data={props.tiStats} updateOptions={updateOptions}
+            onInit={onInitCallback(tiStatsLegendRef)}/>
+        </ChartContainer>
+      </DashboardRowCol>
+      <DashboardRowCol breakpoint='md' parts={4}>
+        <ChartContainer id='to-graph' title={gettext('Tuples out')} legendRef={toStatsLegendRef} errorMsg={props.errorMsg}>
+          <LineChart options={options} data={props.toStats} updateOptions={updateOptions}
+            onInit={onInitCallback(toStatsLegendRef)}/>
+        </ChartContainer>
+      </DashboardRowCol>
+      <DashboardRowCol breakpoint='md' parts={4}>
+        <ChartContainer id='bio-graph' title={gettext('Block I/O')} legendRef={bioStatsLegendRef} errorMsg={props.errorMsg}>
+          <LineChart options={options} data={props.bioStats} updateOptions={updateOptions}
+            onInit={onInitCallback(bioStatsLegendRef)}/>
+        </ChartContainer>
+      </DashboardRowCol>
+    </DashboardRow>
+    </>
+  );
+}
+
+const propTypeStats = PropTypes.shape({
+  labels: PropTypes.array.isRequired,
+  datasets: PropTypes.array,
+  refreshRate: PropTypes.number.isRequired,
+});
+GraphsWrapper.propTypes = {
+  sessionStats: propTypeStats.isRequired,
+  tpsStats: propTypeStats.isRequired,
+  tiStats: propTypeStats.isRequired,
+  toStats: propTypeStats.isRequired,
+  bioStats: propTypeStats.isRequired,
+  errorMsg: PropTypes.string,
+  showTooltip: PropTypes.bool.isRequired,
+  showDataPoints: PropTypes.bool.isRequired,
+  isDatabase: PropTypes.bool.isRequired,
+};
\ No newline at end of file
diff --git a/web/pgadmin/dashboard/static/js/charting.js b/web/pgadmin/dashboard/static/js/charting.js
deleted file mode 100644
index 4d40421f0..000000000
--- a/web/pgadmin/dashboard/static/js/charting.js
+++ /dev/null
@@ -1,121 +0,0 @@
-/////////////////////////////////////////////////////////////
-//
-// pgAdmin 4 - PostgreSQL Tools
-//
-// Copyright (C) 2013 - 2020, The pgAdmin Development Team
-// This software is released under the PostgreSQL Licence
-//
-//////////////////////////////////////////////////////////////
-
-export class Chart {
-  constructor(container, options) {
-    let self = this;
-
-    require.ensure(['flotr2'], function(require) {
-      self.chartApi = require('flotr2');
-    }, function(error){
-      throw(error);
-    }, 'chart');
-
-    /* Html Node where the graph goes */
-    this._container = container;
-    /* Graph library options */
-    this._options = {};
-    this._defaultOptions = {
-      legend: {
-        position: 'nw',
-        backgroundColor: '#D2E8FF',
-      },
-      lines: {
-        show: true,
-        lineWidth: 2,
-      },
-      shadowSize: 0,
-      resolution : 3,
-      grid: {
-        color: 'transparent',
-        tickColor: '#8f8f8f',
-      },
-    };
-
-    this._dataset = null;
-    this._tooltipFormatter = null;
-    /* Just to store other data related to charts. Used nowhere here in the module */
-    this._otherData = {};
-    this.setOptions(options);
-  }
-
-  getContainer() {
-    return this._container;
-  }
-
-  getContainerDimensions() {
-    return {
-      height: this._container.clientHeight,
-      width: this._container.clientWidth,
-    };
-  }
-
-  getOptions() {
-    return this._options;
-  }
-
-  /* This should be changed if library changed */
-  setOptions(options, mergeOptions=true) {
-    /* If mergeOptions then merge the options, else replace existing options */
-    if(mergeOptions) {
-      this._options = {...this._defaultOptions, ...this._options, ...options};
-    } else {
-      this._options = {...this._defaultOptions, ...options};
-    }
-  }
-
-  removeOptions(optionKey) {
-    if(this._options[optionKey]) {
-      delete this._options[optionKey];
-    }
-  }
-
-  getOtherData(key) {
-    if(this._otherData[key]) {
-      return this._otherData[key];
-    }
-  }
-
-  setOtherData(key, value) {
-    this._otherData[key] = value;
-  }
-
-  isVisible() {
-    let dim = this.getContainerDimensions();
-    return (dim.height > 0 && dim.width > 0);
-  }
-
-  isInPage() {
-    return (this._container === document.body) ? false : document.body.contains(this._container);
-  }
-
-  setTooltipFormatter(tooltipFormatter) {
-    let opt = this.getOptions();
-
-    this._tooltipFormatter = tooltipFormatter;
-
-    if(this._tooltipFormatter) {
-      this.setOptions({
-        mouse: {
-          ...opt.mouse,
-          trackFormatter: this._tooltipFormatter,
-        },
-      });
-    }
-  }
-
-  draw(dataset) {
-    this._dataset = dataset;
-    if(this._container) {
-      if(this.chartApi) {
-        this.chartApi.draw(this._container, this._dataset, this._options);
-      }
-    }
-  }
-}
diff --git a/web/pgadmin/dashboard/static/js/dashboard.js b/web/pgadmin/dashboard/static/js/dashboard.js
index bb2503feb..b854823cc 100644
--- a/web/pgadmin/dashboard/static/js/dashboard.js
+++ b/web/pgadmin/dashboard/static/js/dashboard.js
@@ -9,12 +9,12 @@
 
 define('pgadmin.dashboard', [
   'sources/url_for', 'sources/gettext', 'require', 'jquery', 'underscore',
-  'sources/pgadmin', 'backbone', 'backgrid', './charting',
+  'sources/pgadmin', 'backbone', 'backgrid',
   'pgadmin.alertifyjs', 'pgadmin.backform', 'sources/nodes/dashboard',
-  'sources/utils', 'sources/window', 'pgadmin.browser', 'bootstrap', 'wcdocker',
+  'sources/window', './ChartsDOM', 'pgadmin.browser', 'bootstrap', 'wcdocker',
 ], function(
-  url_for, gettext, r, $, _, pgAdmin, Backbone, Backgrid, charting,
-  Alertify, Backform, NodesDashboard, commonUtils, pgWindow
+  url_for, gettext, r, $, _, pgAdmin, Backbone, Backgrid,
+  Alertify, Backform, NodesDashboard, pgWindow, ChartsDOM
 ) {
 
   pgAdmin.Browser = pgAdmin.Browser || {};
@@ -203,6 +203,7 @@ define('pgadmin.dashboard', [
         return;
 
       this.initialized = true;
+      this.chartsDomObj = null;
 
       this.sid = this.did = -1;
       this.version = -1;
@@ -221,10 +222,6 @@ define('pgadmin.dashboard', [
       // Load the default welcome dashboard
       var url = url_for('dashboard.index');
 
-      /* Store the chart objects, refresh freq and next refresh time */
-      this.chart_store = {};
-      this.charts_poller_int_id = -1;
-
       var dashboardPanel = pgBrowser.panels['dashboard'].panel;
       if (dashboardPanel) {
         var div = dashboardPanel.layout().scene().find('.pg-panel-content');
@@ -355,11 +352,9 @@ define('pgadmin.dashboard', [
                   $(dashboardPanel).data('server_status') == false
                 )
               ) {
+                this.chartsDomObj && this.chartsDomObj.unmount();
                 $(div).empty();
 
-                /* Clear all the charts previous dashboards */
-                self.clearChartFromStore();
-
                 let ajaxHook = function() {
                   $.ajax({
                     url: url,
@@ -393,14 +388,8 @@ define('pgadmin.dashboard', [
                 $(dashboardPanel).data('server_status', true);
               }
             } else {
+              this.chartsDomObj && this.chartsDomObj.unmount();
               $(div).empty();
-              if (
-                !_.isUndefined(itemData.connected) &&
-                  itemData.connected !== true
-              ) {
-                /* Clear all the charts previous dashboards */
-                self.clearChartFromStore();
-              }
               $(div).html(
                 '<div class="pg-panel-message" role="alert">' + gettext('Please connect to the selected server to view the dashboard.') + '</div>'
               );
@@ -413,218 +402,6 @@ define('pgadmin.dashboard', [
       }
     },
 
-    // Render the charts
-    renderCharts: function(charts_config) {
-
-      let self = this,
-        tooltipFormatter = function(refresh, currVal) {
-          return(`Seconds ago: ${parseInt(currVal.x * refresh)}</br>
-                  Value: ${currVal.y}`);
-        },
-        curr_epoch=commonUtils.getEpoch();
-
-      self.stopChartsPoller();
-
-      charts_config.map((chart_config) => {
-        if(self.chart_store[chart_config.chart_name]
-          && self.old_preferences[chart_config.refresh_pref_name] !=
-            self.preferences[chart_config.refresh_pref_name]) {
-          self.clearChartFromStore(chart_config.chart_name);
-        }
-
-        if(self.chart_store[chart_config.chart_name]) {
-          let chart_obj = self.chart_store[chart_config.chart_name].chart_obj;
-          chart_obj.setOptions(chart_config.options, false);
-          chart_obj.setTooltipFormatter(
-            tooltipFormatter.bind(null, self.preferences[chart_config.refresh_pref_name])
-          );
-        }
-
-        if(!self.chart_store[chart_config.chart_name]) {
-          let chart_obj = new charting.Chart(chart_config.container, chart_config.options);
-
-          chart_obj.setTooltipFormatter(
-            tooltipFormatter.bind(null, self.preferences[chart_config.refresh_pref_name])
-          );
-
-          chart_obj.setOtherData('counter', chart_config.counter);
-
-          self.chart_store[chart_config.chart_name] = {
-            'chart_obj' : chart_obj,
-            'refresh_on': curr_epoch,
-            'refresh_rate': self.preferences[chart_config.refresh_pref_name],
-          };
-        }
-      });
-
-      self.startChartsPoller(self.chart_store, self.sid, self.did);
-    },
-
-    getStatsUrl: function(sid=-1, did=-1, chart_names=[]) {
-      let base_url = url_for('dashboard.dashboard_stats');
-      base_url += '/' + sid;
-      base_url += (did > 0) ? ('/' + did) : '';
-      base_url += '?chart_names=' + chart_names.join(',');
-      return base_url;
-    },
-
-    updateChart: function(chart_obj, new_data){
-      // Dataset format:
-      // [
-      //     { data: [[0, y0], [1, y1]...], label: 'Label 1', [options] },
-      //     { data: [[0, y0], [1, y1]...], label: 'Label 2', [options] },
-      //     { data: [[0, y0], [1, y1]...], label: 'Label 3', [options] }
-      // ]
-      let dataset = chart_obj.getOtherData('dataset') || [],
-        counter_prev_data = chart_obj.getOtherData('counter_prev_data') || new_data,
-        counter = chart_obj.getOtherData('counter') || false;
-
-      if (dataset.length == 0) {
-        // Create the initial data structure
-        for (let label in new_data) {
-          dataset.push({
-            'data': [
-              [0, counter ? (new_data[label] - counter_prev_data[label]) : new_data[label]],
-            ],
-            'label': label,
-          });
-        }
-      } else {
-        Object.keys(new_data).forEach((label, label_ind) => {
-          // Push new values onto the existing data structure
-          // If this is a counter stat, we need to subtract the previous value
-          if (!counter) {
-            dataset[label_ind]['data'].unshift([0, new_data[label]]);
-          } else {
-            // Store the current value, minus the previous one we stashed.
-            // It's possible the tab has been reloaded, in which case out previous values are gone
-            if (_.isUndefined(counter_prev_data))
-              return;
-
-            dataset[label_ind]['data'].unshift([0, new_data[label] - counter_prev_data[label]]);
-          }
-
-          // Reset the time index to get a proper scrolling display
-          for (var time_ind = 0; time_ind < dataset[label_ind]['data'].length; time_ind++) {
-            dataset[label_ind]['data'][time_ind][0] = time_ind;
-          }
-        });
-        counter_prev_data = new_data;
-      }
-
-      // Remove old data points
-      for (let label_ind = 0; label_ind < dataset.length; label_ind++) {
-        if (dataset[label_ind]['data'].length > 101) {
-          dataset[label_ind]['data'].pop();
-        }
-      }
-
-      chart_obj.setOtherData('dataset', dataset);
-      chart_obj.setOtherData('counter_prev_data', counter_prev_data);
-
-      if (chart_obj.isInPage()) {
-        if (chart_obj.isVisible()) {
-          chart_obj.draw(dataset);
-        }
-      } else {
-        return;
-      }
-    },
-
-    stopChartsPoller: function() {
-      clearInterval(this.charts_poller_int_id);
-    },
-
-    startChartsPoller: function(chart_store, sid, did) {
-      let self = this;
-      /* polling will the greatest common divisor of the refresh rates*/
-      let poll_interval = commonUtils.getGCD(
-        Object.values(chart_store).map(item => item.refresh_rate)
-      );
-      const WAIT_COUNTER = 3;
-      let last_poll_wait_counter = 0;
-      let resp_not_received_counter = 0;
-
-      /* Stop if running, only one poller lives */
-      self.stopChartsPoller();
-
-      var thePollingFunc = function() {
-        let curr_epoch = commonUtils.getEpoch();
-        let chart_names_to_get = [];
-
-        for(let chart_name in chart_store) {
-          /* when its time to get the data */
-          if(chart_store[chart_name].refresh_on <= curr_epoch) {
-            /* set the next trigger point */
-            chart_store[chart_name].refresh_on = curr_epoch + chart_store[chart_name].refresh_rate;
-            chart_names_to_get.push(chart_name);
-          }
-        }
-
-        /* If none of the chart wants data, don't trouble
-         * If response not received from prev poll, don't trouble !!
-         */
-        if(chart_names_to_get.length == 0 || last_poll_wait_counter > 0 || resp_not_received_counter >= WAIT_COUNTER) {
-          /* reduce the number of tries, request should be sent if last_poll_wait_counter
-           * completes WAIT_COUNTER times.*/
-          last_poll_wait_counter--;
-          return;
-        }
-
-        var path = self.getStatsUrl(sid, did, chart_names_to_get);
-        resp_not_received_counter++;
-        $.ajax({
-          url: path,
-          type: 'GET',
-        })
-          .done(function(resp) {
-            for(let chart_name in resp) {
-              let chart_obj = chart_store[chart_name].chart_obj;
-              $(chart_obj.getContainer()).removeClass('graph-error');
-              self.updateChart(chart_obj, resp[chart_name]);
-            }
-          })
-          .fail(function(xhr) {
-            let err = '';
-            let msg = '';
-            let cls = 'info';
-
-            if (xhr.readyState === 0) {
-              msg = gettext('Not connected to the server or the connection to the server has been closed.');
-            } else {
-              err = JSON.parse(xhr.responseText);
-              msg = err.errormsg;
-
-              // If we get a 428, it means the server isn't connected
-              if (xhr.status === 428) {
-                if (_.isUndefined(msg) || _.isNull(msg)) {
-                  msg = gettext('Please connect to the selected server to view the graph.');
-                }
-              } else {
-                msg = gettext('An error occurred whilst rendering the graph.');
-                cls = 'error';
-              }
-            }
-
-            for(let chart_name in chart_store) {
-              let chart_obj = chart_store[chart_name].chart_obj;
-              $(chart_obj.getContainer()).addClass('graph-error');
-              $(chart_obj.getContainer()).html(
-                '<div class="pg-panel-' + cls + ' pg-panel-message" role="alert">' + msg + '</div>'
-              );
-            }
-          })
-          .always(function() {
-            last_poll_wait_counter = 0;
-            resp_not_received_counter--;
-          });
-        last_poll_wait_counter = WAIT_COUNTER;
-      };
-      /* Execute once for the first time as setInterval will not do */
-      thePollingFunc();
-      self.charts_poller_int_id = setInterval(thePollingFunc, poll_interval * 1000);
-    },
-
     // Handler function to support the "Add Server" link
     add_new_server: function() {
       if (pgBrowser && pgBrowser.tree) {
@@ -759,23 +536,17 @@ define('pgadmin.dashboard', [
       });
     },
 
-    clearChartFromStore: function(chartName) {
-      var self = this;
-      if(!chartName){
-        self.stopChartsPoller();
-        _.each(self.chart_store, function(chart, key) {
-          delete self.chart_store[key];
-        });
-      }
-      else {
-        delete self.chart_store[chartName];
-      }
-    },
-
     // Rock n' roll on the dashboard
     init_dashboard: function() {
       let self = this;
 
+      this.chartsDomObj = new ChartsDOM.default(
+        document.getElementById('new-dashboard-graphs'),
+        self.preferences,
+        self.sid,
+        self.did
+      );
+
       /* Cache may take time to load for the first time
        * Keep trying till available
        */
@@ -796,81 +567,14 @@ define('pgadmin.dashboard', [
       pgBrowser.onPreferencesChange('dashboards', function() {
         self.reflectPreferences();
       });
-
     },
 
     reflectPreferences: function() {
       var self = this;
-      var tickColor = getComputedStyle(document.documentElement).getPropertyValue('--border-color');
-
-      /* We will use old preferences for selective graph updates on preference change */
-      if(self.preferences) {
-        self.old_preferences = self.preferences;
-        self.preferences = pgWindow.default.pgAdmin.Browser.get_preferences_for_module('dashboards');
-      }
-      else {
-        self.preferences = pgWindow.default.pgAdmin.Browser.get_preferences_for_module('dashboards');
-        self.old_preferences = self.preferences;
-      }
+      self.preferences = pgWindow.default.pgAdmin.Browser.get_preferences_for_module('dashboards');
+      this.chartsDomObj.reflectPreferences(self.preferences);
 
       if(is_server_dashboard || is_database_dashboard) {
-        /* Common things can come here */
-        var div_sessions = $('.dashboard-container').find('#graph-sessions')[0];
-        var div_tps = $('.dashboard-container').find('#graph-tps')[0];
-        var div_ti = $('.dashboard-container').find('#graph-ti')[0];
-        var div_to = $('.dashboard-container').find('#graph-to')[0];
-        var div_bio = $('.dashboard-container').find('#graph-bio')[0];
-        var options_line = {
-          parseFloat: false,
-          xaxis: {
-            min: 100,
-            max: 0,
-            autoscale: 0,
-          },
-          yaxis: {
-            autoscale: 1,
-          },
-          grid: {
-            color: 'transparent',
-            tickColor: tickColor,
-          },
-        };
-
-        if(self.preferences.graph_data_points) {
-          /* Merge data points related options */
-          options_line = {
-            ...options_line,
-            ...{
-              points: {
-                show:true,
-                radius: 1,
-                hitRadius: 3,
-              },
-            },
-          };
-        }
-
-        if(self.preferences.graph_mouse_track) {
-          /* Merge mouse track related options */
-          options_line = {
-            ...options_line,
-            ...{
-              mouse: {
-                track:true,
-                position: 'sw',
-              },
-            },
-          };
-        }
-
-        if(self.preferences.show_graphs && $('#dashboard-graphs').hasClass('dashboard-hidden')) {
-          $('#dashboard-graphs').removeClass('dashboard-hidden');
-        }
-        else if(!self.preferences.show_graphs) {
-          $('#dashboard-graphs').addClass('dashboard-hidden');
-          self.clearChartFromStore();
-        }
-
         if (self.preferences.show_activity && $('#dashboard-activity').hasClass('dashboard-hidden')) {
           $('#dashboard-activity').removeClass('dashboard-hidden');
         }
@@ -878,46 +582,11 @@ define('pgadmin.dashboard', [
           $('#dashboard-activity').addClass('dashboard-hidden');
         }
 
-        if(self.preferences.show_graphs) {
-          // Render the graphs
-          pgAdmin.Dashboard.renderCharts([{
-            chart_name: 'session_stats',
-            container: div_sessions,
-            options: options_line,
-            counter: false,
-            refresh_pref_name: 'session_stats_refresh',
-          }, {
-            chart_name: 'tps_stats',
-            container: div_tps,
-            options: options_line,
-            counter: true,
-            refresh_pref_name: 'tps_stats_refresh',
-          }, {
-            chart_name: 'ti_stats',
-            container: div_ti,
-            options: options_line,
-            counter: true,
-            refresh_pref_name: 'ti_stats_refresh',
-          }, {
-            chart_name: 'to_stats',
-            container: div_to,
-            options: options_line,
-            counter: true,
-            refresh_pref_name: 'to_stats_refresh',
-          }, {
-            chart_name: 'bio_stats',
-            container: div_bio,
-            options: options_line,
-            counter: true,
-            refresh_pref_name: 'bio_stats_refresh',
-          }]);
-        }
-
-        if(!self.preferences.show_graphs && !self.preferences.show_activity) {
-          $('#dashboard-none-show').removeClass('dashboard-hidden');
+        if (self.preferences.show_activity && $('#dashboard-activity').hasClass('dashboard-hidden')) {
+          $('#dashboard-activity').removeClass('dashboard-hidden');
         }
-        else {
-          $('#dashboard-none-show').addClass('dashboard-hidden');
+        else if(!self.preferences.show_activity) {
+          $('#dashboard-activity').addClass('dashboard-hidden');
         }
 
         /* Dashboard specific preferences can be updated in the
diff --git a/web/pgadmin/dashboard/static/js/dashboard_components.js b/web/pgadmin/dashboard/static/js/dashboard_components.js
new file mode 100644
index 000000000..f6aa35e94
--- /dev/null
+++ b/web/pgadmin/dashboard/static/js/dashboard_components.js
@@ -0,0 +1,65 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+export function ChartContainer(props) {
+  return (
+    <div className="card dashboard-graph" role="object-document" tabIndex="0" aria-labelledby={props.id}>
+      <div className="card-header">
+        <div className="d-flex">
+          <div id={props.id}>{props.title}</div>
+          <div className="ml-auto my-auto legend" ref={props.legendRef}></div>
+        </div>
+      </div>
+      <div className="card-body dashboard-graph-body">
+        <div className={'chart-wrapper ' + (props.errorMsg ? 'd-none': '')}>
+          {props.children}
+        </div>
+        <ChartError message={props.errorMsg} />
+      </div>
+    </div>
+  );
+}
+ChartContainer.propTypes = {
+  id: PropTypes.string.isRequired,
+  title: PropTypes.string.isRequired,
+  legendRef: PropTypes.oneOfType([
+    PropTypes.func,
+    PropTypes.shape({ current: PropTypes.any }),
+  ]).isRequired,
+  children: PropTypes.node.isRequired,
+  errorMsg: PropTypes.string,
+};
+
+export function ChartError(props) {
+  if(props.message === null) {
+    return  <></>;
+  }
+  return (
+    <div className="pg-panel-error pg-panel-message" role="alert">{props.message}</div>
+  );
+}
+
+ChartError.propTypes = {
+  message: PropTypes.string,
+};
+
+export function DashboardRow({children}) {
+  return (
+    <div className="row dashboard-row">{children}</div>
+  );
+}
+DashboardRow.propTypes = {
+  children: PropTypes.node.isRequired,
+};
+
+export function DashboardRowCol({breakpoint, parts, children}) {
+  return (
+    <div className={`col-${breakpoint}-${parts}`}>{children}</div>
+  );
+}
+
+DashboardRowCol.propTypes = {
+  breakpoint: PropTypes.oneOf(['xs', 'sm', 'md', 'lg', 'xl']).isRequired,
+  parts: PropTypes.number.isRequired,
+  children: PropTypes.node.isRequired,
+};
\ No newline at end of file
diff --git a/web/pgadmin/dashboard/static/scss/_dashboard.scss b/web/pgadmin/dashboard/static/scss/_dashboard.scss
index 0bc240be7..e1269ae77 100644
--- a/web/pgadmin/dashboard/static/scss/_dashboard.scss
+++ b/web/pgadmin/dashboard/static/scss/_dashboard.scss
@@ -35,8 +35,22 @@
     color: $color-fg;
 }
 
+.dashboard-graph {
+    & .legend {
+        font-size: $tree-font-size;
+        & .legend-value {
+            font-weight: normal;
+            margin-left: 0.25rem;
+            & .legend-label {
+                margin-left: 0.25rem;
+            }
+        }
+    }
+}
+
 .dashboard-graph-body {
     padding: 0.25rem 0.5rem;
+    height: 175px;
 
     & .flotr-labels {
         color: $color-fg !important;
diff --git a/web/pgadmin/dashboard/templates/dashboard/database_dashboard.html b/web/pgadmin/dashboard/templates/dashboard/database_dashboard.html
index 0f9e7d80b..979962bd2 100644
--- a/web/pgadmin/dashboard/templates/dashboard/database_dashboard.html
+++ b/web/pgadmin/dashboard/templates/dashboard/database_dashboard.html
@@ -1,60 +1,5 @@
 <div class="container-fluid dashboard-container negative-space">
-    <div id="dashboard-graphs" class="dashboard-hidden">
-        <div class="row dashboard-row">
-            <div class="col-md-6 col-12">
-                <div class="card" role="object-document" tabindex="0" aria-labelledby="database-session-graph">
-                    <div class="card-header" id="database-session-graph">
-                        {{ _('Database sessions') }}
-                    </div>
-                    <div class="card-body dashboard-graph-body">
-                        <div id="graph-sessions" class="graph-container"></div>
-                    </div>
-                </div>
-            </div>
-            <div class="col-md-6 col-12">
-                <div class="card" role="object-document" tabindex="0" aria-labelledby="transactions-per-second-graph">
-                    <div class="card-header" id="transactions-per-second-graph">
-                        {{ _('Transactions per second') }}
-                    </div>
-                    <div class="card-body dashboard-graph-body">
-                        <div id="graph-tps" class="graph-container"></div>
-                    </div>
-                </div>
-            </div>
-        </div>
-        <div class="row dashboard-row">
-            <div class="col-md-4 col-12">
-                <div class="card" role="object-document" tabindex="0" aria-labelledby="tuples-in-graph">
-                    <div class="card-header" id="tuples-in-graph">
-                        {{ _('Tuples in') }}
-                    </div>
-                    <div class="card-body dashboard-graph-body">
-                        <div id="graph-ti" class="graph-container"></div>
-                    </div>
-                </div>
-            </div>
-            <div class="col-md-4 col-12">
-                <div class="card" role="object-document" tabindex="0" aria-labelledby="tuples-out-graph">
-                    <div class="card-header" id="tuples-out-graph">
-                        {{ _('Tuples out') }}
-                    </div>
-                    <div class="card-body dashboard-graph-body">
-                        <div id="graph-to" class="graph-container"></div>
-                    </div>
-                </div>
-            </div>
-            <div class="col-md-4 col-12">
-                <div class="card" role="object-document" tabindex="0" aria-labelledby="block-io-graph">
-                    <div class="card-header" id="block-io-graph">
-                        {{ _('Block I/O') }}
-                    </div>
-                    <div class="card-body dashboard-graph-body">
-                        <div id="graph-bio" class="graph-container"></div>
-                    </div>
-                </div>
-            </div>
-        </div>
-    </div>
+    <div id="new-dashboard-graphs"></div>
     <div id="dashboard-activity" class="card dashboard-row dashboard-hidden">
         <div class="card-header">
             <span id="dashboard-activity-header">{{ _('Server activity') }}</span>
diff --git a/web/pgadmin/dashboard/templates/dashboard/server_dashboard.html b/web/pgadmin/dashboard/templates/dashboard/server_dashboard.html
index 08addc1db..50396a148 100644
--- a/web/pgadmin/dashboard/templates/dashboard/server_dashboard.html
+++ b/web/pgadmin/dashboard/templates/dashboard/server_dashboard.html
@@ -1,59 +1,5 @@
 <div class="container-fluid dashboard-container negative-space">
-    <div id="dashboard-graphs" class="dashboard-hidden">
-        <div class="row dashboard-row">
-            <div class="col-md-6 col-12">
-                <div class="card" role="object-document" tabindex="0" aria-labelledby="server-sessions-graph">
-                    <div class="card-header" id="server-sessions-graph">
-                        {{ _('Server sessions') }}
-                    </div>
-                    <div class="card-body dashboard-graph-body">
-                        <div id="graph-sessions" class="graph-container"></div>
-                    </div>
-                </div>
-            </div>
-            <div class="col-md-6 col-12">
-                <div class="card" role="object-document" tabindex="0" aria-labelledby="transactions-per-second-graph">
-                    <div class="card-header" id="transactions-per-second-graph">
-                        {{ _('Transactions per second') }}
-                    </div>
-                    <div class="card-body dashboard-graph-body">
-                        <div id="graph-tps" class="graph-container"></div>
-                    </div>
-                </div>
-            </div>
-        </div>
-        <div class="row dashboard-row">
-            <div class="col-md-4 col-12">
-                <div class="card" role="object-document" tabindex="0" aria-labelledby="tuples-in-graph">
-                    <div class="card-header" id="tuples-in-graph">
-                        {{ _('Tuples in') }}
-                    </div>
-                    <div class="card-body dashboard-graph-body">
-                        <div id="graph-ti" class="graph-container"></div>
-                    </div>
-                </div>
-            </div>
-            <div class="col-md-4 col-12">
-                <div class="card" role="object-document" tabindex="0" aria-labelledby="tuples-out-graph">
-                    <div class="card-header" id="tuples-out-graph">
-                        {{ _('Tuples out') }}
-                    </div>
-                    <div class="card-body dashboard-graph-body">
-                        <div id="graph-to" class="graph-container"></div>
-                    </div>
-                </div>
-            </div>
-            <div class="col-md-4 col-12">
-                <div class="card" role="object-document" tabindex="0" aria-labelledby="block-o-graph">
-                    <div class="card-header" id="block-o-graph">
-                        {{ _('Block I/O') }}
-                    </div>
-                    <div class="card-body dashboard-graph-body">
-                        <div id="graph-bio" class="graph-container"></div>
-                    </div>
-                </div>
-            </div>
-        </div>
+    <div id="new-dashboard-graphs">
     </div>
     <div id="dashboard-activity" class="card dashboard-row dashboard-hidden">
         <div class="card-header">
diff --git a/web/pgadmin/static/js/chartjs/index.js b/web/pgadmin/static/js/chartjs/index.js
new file mode 100644
index 000000000..a336f7626
--- /dev/null
+++ b/web/pgadmin/static/js/chartjs/index.js
@@ -0,0 +1,70 @@
+import React, { useEffect } from 'react';
+import Chart from 'chart.js';
+import PropTypes from 'prop-types';
+
+const defaultOptions = {
+  maintainAspectRatio: false,
+  elements: {
+    line: {
+      tension: 0,
+      borderWidth: 2,
+      fill: false,
+    },
+  },
+  layout: {
+    padding: 8,
+  },
+  hover: {
+    animationDuration:0,
+  },
+};
+
+export default function BaseChart({type='line', options, data, ...props}) {
+  const chartRef = React.useRef();
+  const chartObj = React.useRef();
+  let optionsMerged = Chart.helpers.configMerge(defaultOptions, options);
+
+  useEffect(()=>{
+    let chartContext = chartRef.current.getContext('2d');
+    chartObj.current = new Chart(chartContext, {
+      type: type,
+      data: data,
+      options: optionsMerged,
+    });
+    props.onInit && props.onInit(chartObj.current);
+  }, []);
+
+  useEffect(()=>{
+    if(typeof(chartObj.current) != 'undefined') {
+      chartObj.current.data = data;
+      for(let i=0; i<chartObj.current.data.datasets.length; i++) {
+        chartObj.current.data.datasets[i] = {
+          ...chartObj.current.data.datasets[i],
+          ...data.datasets[i],
+        };
+      }
+      chartObj.current.options = optionsMerged;
+      chartObj.current.update(props.updateOptions || {});
+      props.onUpdate && props.onUpdate(chartObj.current);
+    }
+  }, [data, options]);
+
+  return (
+    <canvas ref={chartRef}></canvas>
+  );
+}
+
+BaseChart.propTypes = {
+  type: PropTypes.string.isRequired,
+  data: PropTypes.object.isRequired,
+  options: PropTypes.object,
+  updateOptions: PropTypes.object,
+  onInit: PropTypes.func,
+  onUpdate: PropTypes.func,
+};
+
+export function LineChart(props) {
+  return (
+    <BaseChart {...props} type='line'/>
+  );
+}
\ No newline at end of file
diff --git a/web/pgadmin/static/js/custom_hooks.js b/web/pgadmin/static/js/custom_hooks.js
new file mode 100644
index 000000000..9163f0d6c
--- /dev/null
+++ b/web/pgadmin/static/js/custom_hooks.js
@@ -0,0 +1,29 @@
+import {useRef, useEffect} from 'react';
+
+/* React hook for setInterval */
+export function useInterval(callback, delay) {
+  const savedCallback = useRef();
+
+  useEffect(() => {
+    savedCallback.current = callback;
+  });
+
+  useEffect(() => {
+    function tick() {
+      savedCallback.current();
+    }
+
+    if(delay > -1) {
+      let id = setInterval(tick, delay);
+      return () => clearInterval(id);
+    }
+  }, [delay]);
+}
+
+export function usePrevious(value) {
+  const ref = useRef();
+  useEffect(() => {
+    ref.current = value;
+  });
+  return ref.current;
+}
\ No newline at end of file
diff --git a/web/pgadmin/static/scss/pgadmin.scss b/web/pgadmin/static/scss/pgadmin.scss
index 118554ba8..420e354a4 100644
--- a/web/pgadmin/static/scss/pgadmin.scss
+++ b/web/pgadmin/static/scss/pgadmin.scss
@@ -7,6 +7,7 @@ $theme-colors: (
 
 /* Certain variables are required in JS directly */
 :root {
+  --color-fg: #{$color-fg};
   --border-color: #{$border-color};
 }
 
diff --git a/web/regression/javascript/dashboard/charting_spec.js b/web/regression/javascript/dashboard/charting_spec.js
deleted file mode 100644
index 7fdeb6b46..000000000
--- a/web/regression/javascript/dashboard/charting_spec.js
+++ /dev/null
@@ -1,100 +0,0 @@
-/////////////////////////////////////////////////////////////
-//
-// pgAdmin 4 - PostgreSQL Tools
-//
-// Copyright (C) 2013 - 2020, The pgAdmin Development Team
-// This software is released under the PostgreSQL Licence
-//
-//////////////////////////////////////////////////////////////
-
-import $ from 'jquery';
-import {Chart} from 'top/dashboard/static/js/charting';
-
-describe('In charting related testcases', ()=> {
-  let chartObj = undefined,
-    chartDiv = undefined,
-    options = {};
-
-  beforeEach(()=> {
-    $('body').append(
-      '<div id="charting-test-container"></div>'
-    );
-    chartDiv = $('#charting-test-container')[0];
-    chartObj = new Chart(chartDiv, options);
-  });
-
-  it('Return the correct container', ()=>{
-    expect(chartObj.getContainer()).toEqual(chartDiv);
-  });
-
-  it('Returns the container dimensions', ()=>{
-    let dim = chartObj.getContainerDimensions();
-    expect(dim.height).toBeDefined();
-    expect(dim.width).toBeDefined();
-  });
-
-  it('Check if options are set', ()=>{
-    chartObj.setOptions({
-      mouse: {
-        track:true,
-      },
-    });
-
-    let opt = chartObj.getOptions();
-
-    expect(opt.mouse).toBeDefined();
-  });
-
-  it('Check if options are set with mergeOptions false', ()=>{
-    let overOpt = {
-      mouse: {
-        track:true,
-      },
-    };
-    chartObj.setOptions(overOpt, false);
-
-    let newOptShouldBe = {...chartObj._defaultOptions, ...overOpt};
-
-    let opt = chartObj.getOptions();
-    expect(JSON.stringify(opt)).toEqual(JSON.stringify(newOptShouldBe));
-  });
-
-  it('Check if other data is set', ()=>{
-    chartObj.setOtherData('some_val', 1);
-    expect(chartObj._otherData['some_val']).toEqual(1);
-  });
-
-  it('Check if other data is get', ()=>{
-    chartObj.setOtherData('some_val', 1);
-    expect(chartObj.getOtherData('some_val')).toEqual(1);
-  });
-
-  it('Check if other data returns undefined for not set', ()=>{
-    expect(chartObj.getOtherData('some_val_not_set')).toEqual(undefined);
-  });
-
-  it('Check if isVisible returns correct', ()=>{
-    let dimSpy = spyOn(chartObj, 'getContainerDimensions');
-
-    dimSpy.and.returnValue({
-      height: 1, width: 1,
-    });
-    expect(chartObj.isVisible()).toEqual(true);
-    dimSpy.and.stub();
-
-    dimSpy.and.returnValue({
-      height: 0, width: 0,
-    });
-    expect(chartObj.isVisible()).toEqual(false);
-  });
-
-  it('Check if isInPage returns correct', ()=>{
-    expect(chartObj.isInPage()).toEqual(true);
-    $('body').find('#charting-test-container').remove();
-    expect(chartObj.isInPage()).toEqual(false);
-  });
-
-  afterEach(()=>{
-    $('body').find('#charting-test-container').remove();
-  });
-});
diff --git a/web/regression/javascript/dashboard/graphs_spec.js b/web/regression/javascript/dashboard/graphs_spec.js
new file mode 100644
index 000000000..f3d028f4d
--- /dev/null
+++ b/web/regression/javascript/dashboard/graphs_spec.js
@@ -0,0 +1,169 @@
+import jasmineEnzyme from 'jasmine-enzyme';
+import React from 'react';
+import {mount} from 'enzyme';
+import '../helper/enzyme.helper';
+
+import Graphs, {GraphsWrapper} from '../../../pgadmin/dashboard/static/js/Graphs';
+import {X_AXIS_LENGTH, POINT_SIZE, transformData, legendCallback,
+  getStatsUrl, statsReducer} from '../../../pgadmin/dashboard/static/js/Graphs';
+
+describe('Graphs.js', ()=>{
+  it('transformData', ()=>{
+    expect(transformData({'Label1': [], 'Label2': []}, 1)).toEqual({
+      labels: [...Array(X_AXIS_LENGTH).keys()],
+      datasets: [{
+        label: 'Label1',
+        data: [],
+        borderColor: '#00BCD4',
+        backgroundColor: '#00BCD4',
+        pointHitRadius: POINT_SIZE,
+      },{
+        label: 'Label2',
+        data: [],
+        borderColor: '#9CCC65',
+        backgroundColor: '#9CCC65',
+        pointHitRadius: POINT_SIZE,
+      }],
+      refreshRate: 1,
+    });
+  });
+
+  it('legendCallback', ()=>{
+    expect(legendCallback({
+      id: 1,
+      data: {
+        datasets: [{
+          label: 'Label1',
+          backgroundColor: '#00BCD4',
+        },{
+          label: 'Label2',
+          backgroundColor: '#9CCC65',
+        }],
+      },
+    })).toEqual([
+      '<div class="1-legend d-flex">',
+      '<div class="legend-value"><span style="background-color:#00BCD4">&nbsp;&nbsp;&nbsp;&nbsp;</span>',
+      '<span class="legend-label">Label1</span>',
+      '</div>',
+      '<div class="legend-value"><span style="background-color:#9CCC65">&nbsp;&nbsp;&nbsp;&nbsp;</span>',
+      '<span class="legend-label">Label2</span>',
+      '</div>',
+      '</div>',
+    ].join(''));
+  });
+
+  describe('getStatsUrl', ()=>{
+    it('for server', ()=>{
+      expect(getStatsUrl(432, -1, ['chart1'])).toEqual('/dashboard/dashboard_stats/432?chart_names=chart1');
+    });
+    it('for database', ()=>{
+      expect(getStatsUrl(432, 123, ['chart1'])).toEqual('/dashboard/dashboard_stats/432/123?chart_names=chart1');
+    });
+    it('for multiple graphs', ()=>{
+      expect(getStatsUrl(432, 123, ['chart1', 'chart2'])).toEqual('/dashboard/dashboard_stats/432/123?chart_names=chart1,chart2');
+    });
+  });
+
+  describe('statsReducer', ()=>{
+    it('with incoming no counter', ()=>{
+      let state = {
+        'Label1': [], 'Label2': [],
+      };
+      let action = {
+        incoming: {
+          'Label1': 1, 'Label2': 2,
+        },
+      };
+      let newState = {
+        'Label1': [1], 'Label2': [2],
+      };
+      state = statsReducer(state, action);
+      expect(state).toEqual(newState);
+    });
+
+    it('with incoming with counter', ()=>{
+      let state = {
+        'Label1': [1], 'Label2': [2],
+      };
+      let action = {
+        incoming: {
+          'Label1': 1, 'Label2': 3,
+        },
+        counter: true,
+        counterData: {'Label1': 1, 'Label2': 2},
+      };
+      let newState = {
+        'Label1': [0, 1], 'Label2': [1, 2],
+      };
+      state = statsReducer(state, action);
+      expect(state).toEqual(newState);
+    });
+
+    it('with reset', ()=>{
+      let state = {
+        'Label1': [0, 1], 'Label2': [1, 2],
+      };
+      let action = {
+        reset: {
+          'Label1': [2], 'Label2': [2],
+        },
+      };
+      let newState = {
+        'Label1': [2], 'Label2': [2],
+      };
+      state = statsReducer(state, action);
+      expect(state).toEqual(newState);
+    });
+  });
+
+  describe('<Graphs /> component', ()=>{
+    let graphComp = null;
+    let sid = 1;
+    let did = 1;
+    beforeEach(()=>{
+      jasmineEnzyme();
+      let dashboardPref = {
+        session_stats_refresh: 1,
+        tps_stats_refresh: 1,
+        ti_stats_refresh: 1,
+        to_stats_refresh: 1,
+        bio_stats_refresh: 1,
+        show_graphs: true,
+        graph_data_points: true,
+        graph_mouse_track: true,
+      };
+
+      graphComp = mount(<Graphs preferences={dashboardPref} sid={sid} did={did} enablePoll={false} />);
+    });
+
+    it('GraphsWrapper is rendered',  (done)=>{
+      let found = graphComp.find(GraphsWrapper);
+      expect(found.length).toBe(1);
+      done();
+    });
+
+    it('pollDelay is set',  (done)=>{
+      let found = graphComp.find('[data-testid="graph-poll-delay"]');
+      expect(found).toHaveClassName('d-none');
+      expect(found).toHaveText('1000');
+      done();
+    });
+
+    it('pollDelay on preference update',  (done)=>{
+      let dashboardPref = {
+        session_stats_refresh: 5,
+        tps_stats_refresh: 10,
+        ti_stats_refresh: 5,
+        to_stats_refresh: 10,
+        bio_stats_refresh: 10,
+        show_graphs: true,
+        graph_data_points: true,
+        graph_mouse_track: true,
+      };
+      graphComp.setProps({preferences: dashboardPref});
+      let found = graphComp.find('[data-testid="graph-poll-delay"]');
+      expect(found).toHaveText('5000');
+      done();
+    });
+  });
+});
\ No newline at end of file
diff --git a/web/regression/javascript/dashboard/graphs_wrapper_spec.js b/web/regression/javascript/dashboard/graphs_wrapper_spec.js
new file mode 100644
index 000000000..3e9f6f286
--- /dev/null
+++ b/web/regression/javascript/dashboard/graphs_wrapper_spec.js
@@ -0,0 +1,90 @@
+import jasmineEnzyme from 'jasmine-enzyme';
+import React from 'react';
+import {mount} from 'enzyme';
+import '../helper/enzyme.helper';
+
+import {GraphsWrapper, X_AXIS_LENGTH, POINT_SIZE} from '../../../pgadmin/dashboard/static/js/Graphs';
+
+describe('<GraphsWrapper /> component', ()=>{
+  let graphComp = null;
+  let defaultStats = {
+    labels: [...Array(X_AXIS_LENGTH).keys()],
+    datasets: [{
+      label: 'Label1',
+      data: [],
+      borderColor: '#00BCD4',
+      backgroundColor: '#00BCD4',
+      pointHitRadius: POINT_SIZE,
+    },{
+      label: 'Label2',
+      data: [],
+      borderColor: '#9CCC65',
+      backgroundColor: '#9CCC65',
+      pointHitRadius: POINT_SIZE,
+    }],
+    refreshRate: 1,
+  };
+  beforeEach(()=>{
+    jasmineEnzyme();
+    graphComp = mount(<GraphsWrapper sessionStats={defaultStats}
+      tpsStats={defaultStats}
+      tiStats={defaultStats}
+      toStats={defaultStats}
+      bioStats={defaultStats}
+      errorMsg={null}
+      showTooltip={true}
+      showDataPoints={true}
+      isDatabase={false} />);
+  });
+
+  it('graph containers are rendered', (done)=>{
+    let found = graphComp.find('.card.dashboard-graph');
+    expect(found.length).toBe(5);
+    done();
+  });
+
+  it('graph headers are correct', (done)=>{
+    let found = graphComp.find('.card.dashboard-graph');
+    expect(found.at(0)).toIncludeText('Server sessions');
+    expect(found.at(1)).toIncludeText('Transactions per second');
+    expect(found.at(2)).toIncludeText('Tuples in');
+    expect(found.at(3)).toIncludeText('Tuples out');
+    expect(found.at(4)).toIncludeText('Block I/O');
+    done();
+  });
+
+  it('graph headers when database', (done)=>{
+    let found = graphComp.find('.card.dashboard-graph');
+    graphComp.setProps({isDatabase: true});
+    expect(found.at(0)).toIncludeText('Database sessions');
+    done();
+  });
+
+  it('graph body has the canvas', (done)=>{
+    let found = graphComp.find('.card.dashboard-graph .dashboard-graph-body canvas');
+    expect(found.at(0).length).toBe(1);
+    expect(found.at(1).length).toBe(1);
+    expect(found.at(2).length).toBe(1);
+    expect(found.at(3).length).toBe(1);
+    expect(found.at(4).length).toBe(1);
+    done();
+  });
+
+  it('graph body shows the error', (done)=>{
+    graphComp.setProps({errorMsg: 'Some error occurred'});
+    let found = graphComp.find('.card.dashboard-graph .dashboard-graph-body .chart-wrapper');
+    expect(found.at(0)).toHaveClassName('d-none');
+    expect(found.at(1)).toHaveClassName('d-none');
+    expect(found.at(2)).toHaveClassName('d-none');
+    expect(found.at(3)).toHaveClassName('d-none');
+    expect(found.at(4)).toHaveClassName('d-none');
+
+    found = graphComp.find('.card.dashboard-graph .dashboard-graph-body .pg-panel-error.pg-panel-message');
+    expect(found.at(0)).toIncludeText('Some error occurred');
+    expect(found.at(1)).toIncludeText('Some error occurred');
+    expect(found.at(2)).toIncludeText('Some error occurred');
+    expect(found.at(3)).toIncludeText('Some error occurred');
+    expect(found.at(4)).toIncludeText('Some error occurred');
+    done();
+  });
+});
\ No newline at end of file
diff --git a/web/regression/javascript/fake_endpoints.js b/web/regression/javascript/fake_endpoints.js
index 157a34863..806f59001 100644
--- a/web/regression/javascript/fake_endpoints.js
+++ b/web/regression/javascript/fake_endpoints.js
@@ -21,5 +21,6 @@ define(function () {
     'datagrid.panel': '/panel/<int:trans_id>',
     'search_objects.types': '/search_objects/types/<int:sid>/<int:did>',
     'search_objects.search': '/search_objects/search/<int:sid>/<int:did>',
+    'dashboard.dashboard_stats': '/dashboard/dashboard_stats',
   };
 });
diff --git a/web/regression/javascript/helper/enzyme.helper.js b/web/regression/javascript/helper/enzyme.helper.js
new file mode 100644
index 000000000..dbe9b4cab
--- /dev/null
+++ b/web/regression/javascript/helper/enzyme.helper.js
@@ -0,0 +1,4 @@
+import Enzyme from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+
+Enzyme.configure({adapter: new Adapter()});
\ No newline at end of file
diff --git a/web/webpack.config.js b/web/webpack.config.js
index 6d2e00b2b..e723e5da4 100644
--- a/web/webpack.config.js
+++ b/web/webpack.config.js
@@ -309,11 +309,6 @@ var getThemeWebpackConfig = function(theme_name) {
       // Module and Rules: https://webpack.js.org/configuration/module/
       // Loaders: https://webpack.js.org/loaders/
       //
-      // imports-loader: it adds dependent modules(use:imports-loader?module1)
-      // at the beginning of module it is dependency of like:
-      // var jQuery = require('jquery'); var browser = require('pgadmin.browser')
-      // It solves number of problems
-      // Ref: http:/github.com/webpack-contrib/imports-loader/
       rules: themeCssRules(theme_name),
     },
     resolve: {
@@ -398,7 +393,8 @@ module.exports = [{
       use: {
         loader: 'babel-loader',
         options: {
-          presets: [['@babel/preset-env', {'modules': 'commonjs', 'useBuiltIns': 'usage', 'corejs': 3}]],
+          presets: [['@babel/preset-env', {'modules': 'commonjs', 'useBuiltIns': 'usage', 'corejs': 3}], '@babel/preset-react'],
+          plugins: ['@babel/plugin-proposal-class-properties'],
         },
       },
     }, {
@@ -420,6 +416,11 @@ module.exports = [{
       query: webpackShimConfig,
       include: path.join(__dirname, '/pgadmin/browser'),
     }, {
+      // imports-loader: it adds dependent modules(use:imports-loader?module1)
+      // at the beginning of module it is dependency of like:
+      // var jQuery = require('jquery'); var browser = require('pgadmin.browser')
+      // It solves number of problems
+      // Ref: http:/github.com/webpack-contrib/imports-loader/
       test: require.resolve('./pgadmin/tools/datagrid/static/js/datagrid'),
       use: {
         loader: 'imports-loader?' +
diff --git a/web/webpack.shim.js b/web/webpack.shim.js
index 9854f0deb..da19b6897 100644
--- a/web/webpack.shim.js
+++ b/web/webpack.shim.js
@@ -82,9 +82,6 @@ var webpackShimConfig = {
       'deps': ['jquery', 'jquery.ui', 'jquery.event.drag'],
       'exports': 'Slick',
     },
-    'flotr2': {
-      deps: ['bean'],
-    },
     'alertify': {
       'exports': 'alertify',
     },
@@ -141,8 +138,6 @@ var webpackShimConfig = {
     'moment': path.join(__dirname, './node_modules/moment/moment'),
     'jquery.event.drag': path.join(__dirname, './node_modules/slickgrid/lib/jquery.event.drag-2.3.0'),
     'jquery.ui': path.join(__dirname, './node_modules/slickgrid/lib/jquery-ui-1.11.3'),
-    'flotr2': path.join(__dirname, './node_modules/flotr2/flotr2.amd'),
-    'bean': path.join(__dirname, './node_modules/flotr2/lib/bean'),
     'jqueryui.position': path.join(__dirname, './node_modules/jquery-contextmenu/dist/jquery.ui.position'),
     'jquery.contextmenu': path.join(__dirname, './node_modules/jquery-contextmenu/dist/jquery.contextMenu'),
     'dropzone': path.join(__dirname, './node_modules/dropzone/dist/dropzone'),
diff --git a/web/webpack.test.config.js b/web/webpack.test.config.js
index b48d104ba..750fffc70 100644
--- a/web/webpack.test.config.js
+++ b/web/webpack.test.config.js
@@ -36,7 +36,8 @@ module.exports = {
         use: {
           loader: 'babel-loader',
           options: {
-            presets: [['@babel/preset-env', {'modules': 'commonjs', 'useBuiltIns': 'usage', 'corejs': 3}]],
+            presets: [['@babel/preset-env', {'modules': 'commonjs', 'useBuiltIns': 'usage', 'corejs': 3}], '@babel/preset-react'],
+            plugins: ['@babel/plugin-proposal-class-properties'],
             sourceMap: 'inline',
           },
         },
@@ -90,8 +91,6 @@ module.exports = {
       'slickgrid': nodeModulesDir + '/slickgrid/',
       'slickgrid.plugins': nodeModulesDir + '/slickgrid/plugins/',
       'slickgrid.grid': nodeModulesDir + '/slickgrid/slick.grid',
-      'bean': path.join(__dirname, './node_modules/flotr2/lib/bean'),
-      'flotr2': path.join(__dirname, './node_modules/flotr2/flotr2.amd'),
       'moment': path.join(__dirname, './node_modules/moment/moment'),
       'browser': path.resolve(__dirname, 'pgadmin/browser/static/js'),
       'pgadmin': sourcesDir + '/js/pgadmin',
diff --git a/web/yarn.lock b/web/yarn.lock
index d22e998b2..1a0adeef7 100644
--- a/web/yarn.lock
+++ b/web/yarn.lock
@@ -25,6 +25,13 @@
   dependencies:
     "@babel/highlight" "^7.10.1"
 
+"@babel/code-frame@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a"
+  integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==
+  dependencies:
+    "@babel/highlight" "^7.10.4"
+
 "@babel/core@~7.6.0":
   version "7.6.4"
   resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.6.4.tgz#6ebd9fe00925f6c3e177bb726a188b5f578088ff"
@@ -55,6 +62,16 @@
     lodash "^4.17.13"
     source-map "^0.5.0"
 
+"@babel/generator@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.10.4.tgz#e49eeed9fe114b62fa5b181856a43a5e32f5f243"
+  integrity sha512-toLIHUIAgcQygFZRAQcsLQV3CBuX6yOIru1kJk/qqqvcRmZrYe6WavZTSG+bB8MxhnL9YPf+pKQfuiP161q7ng==
+  dependencies:
+    "@babel/types" "^7.10.4"
+    jsesc "^2.5.1"
+    lodash "^4.17.13"
+    source-map "^0.5.0"
+
 "@babel/helper-annotate-as-pure@^7.10.1":
   version "7.10.1"
   resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.1.tgz#f6d08acc6f70bbd59b436262553fb2e259a1a268"
@@ -62,6 +79,13 @@
   dependencies:
     "@babel/types" "^7.10.1"
 
+"@babel/helper-annotate-as-pure@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz#5bf0d495a3f757ac3bda48b5bf3b3ba309c72ba3"
+  integrity sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA==
+  dependencies:
+    "@babel/types" "^7.10.4"
+
 "@babel/helper-builder-binary-assignment-operator-visitor@^7.10.1":
   version "7.10.1"
   resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.1.tgz#0ec7d9be8174934532661f87783eb18d72290059"
@@ -70,6 +94,35 @@
     "@babel/helper-explode-assignable-expression" "^7.10.1"
     "@babel/types" "^7.10.1"
 
+"@babel/helper-builder-react-jsx-experimental@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-builder-react-jsx-experimental/-/helper-builder-react-jsx-experimental-7.10.4.tgz#d0ffb875184d749c63ffe1f4f65be15143ec322d"
+  integrity sha512-LyacH/kgQPgLAuaWrvvq1+E7f5bLyT8jXCh7nM67sRsy2cpIGfgWJ+FCnAKQXfY+F0tXUaN6FqLkp4JiCzdK8Q==
+  dependencies:
+    "@babel/helper-annotate-as-pure" "^7.10.4"
+    "@babel/helper-module-imports" "^7.10.4"
+    "@babel/types" "^7.10.4"
+
+"@babel/helper-builder-react-jsx@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.10.4.tgz#8095cddbff858e6fa9c326daee54a2f2732c1d5d"
+  integrity sha512-5nPcIZ7+KKDxT1427oBivl9V9YTal7qk0diccnh7RrcgrT/pGFOjgGw1dgryyx1GvHEpXVfoDF6Ak3rTiWh8Rg==
+  dependencies:
+    "@babel/helper-annotate-as-pure" "^7.10.4"
+    "@babel/types" "^7.10.4"
+
+"@babel/helper-create-class-features-plugin@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.10.4.tgz#2d4015d0136bd314103a70d84a7183e4b344a355"
+  integrity sha512-9raUiOsXPxzzLjCXeosApJItoMnX3uyT4QdM2UldffuGApNrF8e938MwNpDCK9CPoyxrEoCgT+hObJc3mZa6lQ==
+  dependencies:
+    "@babel/helper-function-name" "^7.10.4"
+    "@babel/helper-member-expression-to-functions" "^7.10.4"
+    "@babel/helper-optimise-call-expression" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-replace-supers" "^7.10.4"
+    "@babel/helper-split-export-declaration" "^7.10.4"
+
 "@babel/helper-create-regexp-features-plugin@^7.10.1", "@babel/helper-create-regexp-features-plugin@^7.8.3":
   version "7.10.1"
   resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.1.tgz#1b8feeab1594cbcfbf3ab5a3bbcabac0468efdbd"
@@ -105,6 +158,15 @@
     "@babel/template" "^7.10.1"
     "@babel/types" "^7.10.1"
 
+"@babel/helper-function-name@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz#d2d3b20c59ad8c47112fa7d2a94bc09d5ef82f1a"
+  integrity sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==
+  dependencies:
+    "@babel/helper-get-function-arity" "^7.10.4"
+    "@babel/template" "^7.10.4"
+    "@babel/types" "^7.10.4"
+
 "@babel/helper-get-function-arity@^7.10.1":
   version "7.10.1"
   resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.1.tgz#7303390a81ba7cb59613895a192b93850e373f7d"
@@ -112,6 +174,13 @@
   dependencies:
     "@babel/types" "^7.10.1"
 
+"@babel/helper-get-function-arity@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz#98c1cbea0e2332f33f9a4661b8ce1505b2c19ba2"
+  integrity sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==
+  dependencies:
+    "@babel/types" "^7.10.4"
+
 "@babel/helper-hoist-variables@^7.10.1":
   version "7.10.1"
   resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.1.tgz#7e77c82e5dcae1ebf123174c385aaadbf787d077"
@@ -126,6 +195,13 @@
   dependencies:
     "@babel/types" "^7.10.1"
 
+"@babel/helper-member-expression-to-functions@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.10.4.tgz#7cd04b57dfcf82fce9aeae7d4e4452fa31b8c7c4"
+  integrity sha512-m5j85pK/KZhuSdM/8cHUABQTAslV47OjfIB9Cc7P+PvlAoBzdb79BGNfw8RhT5Mq3p+xGd0ZfAKixbrUZx0C7A==
+  dependencies:
+    "@babel/types" "^7.10.4"
+
 "@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.10.1":
   version "7.10.1"
   resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.1.tgz#dd331bd45bccc566ce77004e9d05fe17add13876"
@@ -133,6 +209,13 @@
   dependencies:
     "@babel/types" "^7.10.1"
 
+"@babel/helper-module-imports@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz#4c5c54be04bd31670a7382797d75b9fa2e5b5620"
+  integrity sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw==
+  dependencies:
+    "@babel/types" "^7.10.4"
+
 "@babel/helper-module-transforms@^7.10.1":
   version "7.10.1"
   resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.10.1.tgz#24e2f08ee6832c60b157bb0936c86bef7210c622"
@@ -153,11 +236,23 @@
   dependencies:
     "@babel/types" "^7.10.1"
 
+"@babel/helper-optimise-call-expression@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz#50dc96413d594f995a77905905b05893cd779673"
+  integrity sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg==
+  dependencies:
+    "@babel/types" "^7.10.4"
+
 "@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.1", "@babel/helper-plugin-utils@^7.8.0":
   version "7.10.1"
   resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.1.tgz#ec5a5cf0eec925b66c60580328b122c01230a127"
   integrity sha512-fvoGeXt0bJc7VMWZGCAEBEMo/HAjW2mP8apF5eXK0wSqwLAVHAISCWRoLMBMUs2kqeaG77jltVqu4Hn8Egl3nA==
 
+"@babel/helper-plugin-utils@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375"
+  integrity sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==
+
 "@babel/helper-regex@^7.10.1":
   version "7.10.1"
   resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.10.1.tgz#021cf1a7ba99822f993222a001cc3fec83255b96"
@@ -186,6 +281,16 @@
     "@babel/traverse" "^7.10.1"
     "@babel/types" "^7.10.1"
 
+"@babel/helper-replace-supers@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz#d585cd9388ea06e6031e4cd44b6713cbead9e6cf"
+  integrity sha512-sPxZfFXocEymYTdVK1UNmFPBN+Hv5mJkLPsYWwGBxZAxaWfFu+xqp7b6qWD0yjNuNL2VKc6L5M18tOXUP7NU0A==
+  dependencies:
+    "@babel/helper-member-expression-to-functions" "^7.10.4"
+    "@babel/helper-optimise-call-expression" "^7.10.4"
+    "@babel/traverse" "^7.10.4"
+    "@babel/types" "^7.10.4"
+
 "@babel/helper-simple-access@^7.10.1":
   version "7.10.1"
   resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.10.1.tgz#08fb7e22ace9eb8326f7e3920a1c2052f13d851e"
@@ -201,11 +306,23 @@
   dependencies:
     "@babel/types" "^7.10.1"
 
+"@babel/helper-split-export-declaration@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.4.tgz#2c70576eaa3b5609b24cb99db2888cc3fc4251d1"
+  integrity sha512-pySBTeoUff56fL5CBU2hWm9TesA4r/rOkI9DyJLvvgz09MB9YtfIYe3iBriVaYNaPe+Alua0vBIOVOLs2buWhg==
+  dependencies:
+    "@babel/types" "^7.10.4"
+
 "@babel/helper-validator-identifier@^7.10.1":
   version "7.10.1"
   resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.1.tgz#5770b0c1a826c4f53f5ede5e153163e0318e94b5"
   integrity sha512-5vW/JXLALhczRCWP0PnFDMCJAchlBvM7f4uk/jXritBnIa6E1KmqmtrS3yn1LAnxFBypQ3eneLuXjsnfQsgILw==
 
+"@babel/helper-validator-identifier@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2"
+  integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==
+
 "@babel/helper-wrap-function@^7.10.1":
   version "7.10.1"
   resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.10.1.tgz#956d1310d6696257a7afd47e4c42dfda5dfcedc9"
@@ -234,11 +351,25 @@
     chalk "^2.0.0"
     js-tokens "^4.0.0"
 
+"@babel/highlight@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143"
+  integrity sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==
+  dependencies:
+    "@babel/helper-validator-identifier" "^7.10.4"
+    chalk "^2.0.0"
+    js-tokens "^4.0.0"
+
 "@babel/parser@^7.10.1", "@babel/parser@^7.6.4", "@babel/parser@^7.7.0":
   version "7.10.2"
   resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.10.2.tgz#871807f10442b92ff97e4783b9b54f6a0ca812d0"
   integrity sha512-PApSXlNMJyB4JiGVhCOlzKIif+TKFTvu0aQAhnTvfP/z3vVSN6ZypH5bfUNwFXXjRQtUEBNFd2PtmCmG2Py3qQ==
 
+"@babel/parser@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.10.4.tgz#9eedf27e1998d87739fb5028a5120557c06a1a64"
+  integrity sha512-8jHII4hf+YVDsskTF6WuMB3X4Eh+PsUkC2ljq22so5rHvH+T8BzyL94VOdyFLNR8tBSVXOTbNHOKpR4TfRxVtA==
+
 "@babel/plugin-proposal-async-generator-functions@^7.2.0":
   version "7.10.1"
   resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.10.1.tgz#6911af5ba2e615c4ff3c497fe2f47b35bf6d7e55"
@@ -248,6 +379,14 @@
     "@babel/helper-remap-async-to-generator" "^7.10.1"
     "@babel/plugin-syntax-async-generators" "^7.8.0"
 
+"@babel/plugin-proposal-class-properties@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.10.4.tgz#a33bf632da390a59c7a8c570045d1115cd778807"
+  integrity sha512-vhwkEROxzcHGNu2mzUC0OFFNXdZ4M23ib8aRRcJSsW8BZK9pQMD7QB7csl97NBbgGZO7ZyHUyKDnxzOaP4IrCg==
+  dependencies:
+    "@babel/helper-create-class-features-plugin" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.10.4"
+
 "@babel/plugin-proposal-dynamic-import@^7.5.0":
   version "7.10.1"
   resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.10.1.tgz#e36979dc1dc3b73f6d6816fc4951da2363488ef0"
@@ -310,6 +449,13 @@
   dependencies:
     "@babel/helper-plugin-utils" "^7.8.0"
 
+"@babel/plugin-syntax-jsx@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.10.4.tgz#39abaae3cbf710c4373d8429484e6ba21340166c"
+  integrity sha512-KCg9mio9jwiARCB7WAcQ7Y1q+qicILjoK8LP/VkPkEKaf5dkaZZK1EcTe91a3JJlZ3qy6L5s9X52boEYi8DM9g==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.10.4"
+
 "@babel/plugin-syntax-object-rest-spread@^7.2.0", "@babel/plugin-syntax-object-rest-spread@^7.8.0":
   version "7.8.3"
   resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871"
@@ -509,6 +655,56 @@
   dependencies:
     "@babel/helper-plugin-utils" "^7.10.1"
 
+"@babel/plugin-transform-react-display-name@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.10.4.tgz#b5795f4e3e3140419c3611b7a2a3832b9aef328d"
+  integrity sha512-Zd4X54Mu9SBfPGnEcaGcOrVAYOtjT2on8QZkLKEq1S/tHexG39d9XXGZv19VfRrDjPJzFmPfTAqOQS1pfFOujw==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.10.4"
+
+"@babel/plugin-transform-react-jsx-development@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.10.4.tgz#6ec90f244394604623880e15ebc3c34c356258ba"
+  integrity sha512-RM3ZAd1sU1iQ7rI2dhrZRZGv0aqzNQMbkIUCS1txYpi9wHQ2ZHNjo5TwX+UD6pvFW4AbWqLVYvKy5qJSAyRGjQ==
+  dependencies:
+    "@babel/helper-builder-react-jsx-experimental" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/plugin-syntax-jsx" "^7.10.4"
+
+"@babel/plugin-transform-react-jsx-self@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.10.4.tgz#cd301a5fed8988c182ed0b9d55e9bd6db0bd9369"
+  integrity sha512-yOvxY2pDiVJi0axdTWHSMi5T0DILN+H+SaeJeACHKjQLezEzhLx9nEF9xgpBLPtkZsks9cnb5P9iBEi21En3gg==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/plugin-syntax-jsx" "^7.10.4"
+
+"@babel/plugin-transform-react-jsx-source@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.10.4.tgz#86baf0fcccfe58084e06446a80858e1deae8f291"
+  integrity sha512-FTK3eQFrPv2aveerUSazFmGygqIdTtvskG50SnGnbEUnRPcGx2ylBhdFIzoVS1ty44hEgcPoCAyw5r3VDEq+Ug==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/plugin-syntax-jsx" "^7.10.4"
+
+"@babel/plugin-transform-react-jsx@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.10.4.tgz#673c9f913948764a4421683b2bef2936968fddf2"
+  integrity sha512-L+MfRhWjX0eI7Js093MM6MacKU4M6dnCRa/QPDwYMxjljzSCzzlzKzj9Pk4P3OtrPcxr2N3znR419nr3Xw+65A==
+  dependencies:
+    "@babel/helper-builder-react-jsx" "^7.10.4"
+    "@babel/helper-builder-react-jsx-experimental" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/plugin-syntax-jsx" "^7.10.4"
+
+"@babel/plugin-transform-react-pure-annotations@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.10.4.tgz#3eefbb73db94afbc075f097523e445354a1c6501"
+  integrity sha512-+njZkqcOuS8RaPakrnR9KvxjoG1ASJWpoIv/doyWngId88JoFlPlISenGXjrVacZUIALGUr6eodRs1vmPnF23A==
+  dependencies:
+    "@babel/helper-annotate-as-pure" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.10.4"
+
 "@babel/plugin-transform-regenerator@^7.4.5":
   version "7.10.1"
   resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.10.1.tgz#10e175cbe7bdb63cc9b39f9b3f823c5c7c5c5490"
@@ -624,6 +820,19 @@
     js-levenshtein "^1.1.3"
     semver "^5.5.0"
 
+"@babel/preset-react@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.10.4.tgz#92e8a66d816f9911d11d4cc935be67adfc82dbcf"
+  integrity sha512-BrHp4TgOIy4M19JAfO1LhycVXOPWdDbTRep7eVyatf174Hff+6Uk53sDyajqZPu8W1qXRBiYOfIamek6jA7YVw==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/plugin-transform-react-display-name" "^7.10.4"
+    "@babel/plugin-transform-react-jsx" "^7.10.4"
+    "@babel/plugin-transform-react-jsx-development" "^7.10.4"
+    "@babel/plugin-transform-react-jsx-self" "^7.10.4"
+    "@babel/plugin-transform-react-jsx-source" "^7.10.4"
+    "@babel/plugin-transform-react-pure-annotations" "^7.10.4"
+
 "@babel/runtime@^7.8.4":
   version "7.10.2"
   resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.2.tgz#d103f21f2602497d38348a32e008637d506db839"
@@ -640,6 +849,15 @@
     "@babel/parser" "^7.10.1"
     "@babel/types" "^7.10.1"
 
+"@babel/template@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278"
+  integrity sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==
+  dependencies:
+    "@babel/code-frame" "^7.10.4"
+    "@babel/parser" "^7.10.4"
+    "@babel/types" "^7.10.4"
+
 "@babel/traverse@^7.10.1", "@babel/traverse@^7.6.3", "@babel/traverse@^7.7.0":
   version "7.10.1"
   resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.10.1.tgz#bbcef3031e4152a6c0b50147f4958df54ca0dd27"
@@ -655,6 +873,21 @@
     globals "^11.1.0"
     lodash "^4.17.13"
 
+"@babel/traverse@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.10.4.tgz#e642e5395a3b09cc95c8e74a27432b484b697818"
+  integrity sha512-aSy7p5THgSYm4YyxNGz6jZpXf+Ok40QF3aA2LyIONkDHpAcJzDUqlCKXv6peqYUs2gmic849C/t2HKw2a2K20Q==
+  dependencies:
+    "@babel/code-frame" "^7.10.4"
+    "@babel/generator" "^7.10.4"
+    "@babel/helper-function-name" "^7.10.4"
+    "@babel/helper-split-export-declaration" "^7.10.4"
+    "@babel/parser" "^7.10.4"
+    "@babel/types" "^7.10.4"
+    debug "^4.1.0"
+    globals "^11.1.0"
+    lodash "^4.17.13"
+
 "@babel/types@^7.10.1", "@babel/types@^7.10.2", "@babel/types@^7.6.3", "@babel/types@^7.7.0":
   version "7.10.2"
   resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.10.2.tgz#30283be31cad0dbf6fb00bd40641ca0ea675172d"
@@ -664,6 +897,15 @@
     lodash "^4.17.13"
     to-fast-properties "^2.0.0"
 
+"@babel/types@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.10.4.tgz#369517188352e18219981efd156bfdb199fff1ee"
+  integrity sha512-UTCFOxC3FsFHb7lkRMVvgLzaRVamXuAs2Tz4wajva4WxtVY82eZeaUBtC2Zt95FU9TiznuC0Zk35tsim8jeVpg==
+  dependencies:
+    "@babel/helper-validator-identifier" "^7.10.4"
+    lodash "^4.17.13"
+    to-fast-properties "^2.0.0"
+
 "@simonwep/pickr@^1.5.1":
   version "1.6.0"
   resolved "https://registry.yarnpkg.com/@simonwep/pickr/-/pickr-1.6.0.tgz#bc5e14bf29acb8e97a3b57652f98dc8e2ed60d8e"
@@ -913,6 +1155,21 @@ aggregate-error@^3.0.0:
     clean-stack "^2.0.0"
     indent-string "^4.0.0"
 
+airbnb-prop-types@^2.15.0:
+  version "2.16.0"
+  resolved "https://registry.yarnpkg.com/airbnb-prop-types/-/airbnb-prop-types-2.16.0.tgz#b96274cefa1abb14f623f804173ee97c13971dc2"
+  integrity sha512-7WHOFolP/6cS96PhKNrslCLMYAI8yB1Pp6u6XmxozQOiZbsI5ycglZr5cHhBFfuRcQQjzCMith5ZPZdYiJCxUg==
+  dependencies:
+    array.prototype.find "^2.1.1"
+    function.prototype.name "^1.1.2"
+    is-regex "^1.1.0"
+    object-is "^1.1.2"
+    object.assign "^4.1.0"
+    object.entries "^1.1.2"
+    prop-types "^15.7.2"
+    prop-types-exact "^1.2.0"
+    react-is "^16.13.1"
+
 ajv-errors@^1.0.0:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d"
@@ -1034,6 +1291,11 @@ arr-union@^3.1.0:
   resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4"
   integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=
 
+array-filter@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-1.0.0.tgz#baf79e62e6ef4c2a4c0b831232daffec251f9d83"
+  integrity sha1-uveeYubvTCpMC4MSMtr/7CUfnYM=
+
 array-find-index@^1.0.1:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
@@ -1044,6 +1306,15 @@ array-flatten@1.1.1:
   resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
   integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=
 
+array-includes@^3.1.1:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.1.tgz#cdd67e6852bdf9c1215460786732255ed2459348"
+  integrity sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==
+  dependencies:
+    define-properties "^1.1.3"
+    es-abstract "^1.17.0"
+    is-string "^1.0.5"
+
 array-union@^1.0.1:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39"
@@ -1061,6 +1332,31 @@ array-unique@^0.3.2:
   resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
   integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=
 
+array.prototype.find@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/array.prototype.find/-/array.prototype.find-2.1.1.tgz#3baca26108ca7affb08db06bf0be6cb3115a969c"
+  integrity sha512-mi+MYNJYLTx2eNYy+Yh6raoQacCsNeeMUaspFPh9Y141lFSsWxxB8V9mM2ye+eqiRs917J6/pJ4M9ZPzenWckA==
+  dependencies:
+    define-properties "^1.1.3"
+    es-abstract "^1.17.4"
+
+array.prototype.flat@^1.2.3:
+  version "1.2.3"
+  resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz#0de82b426b0318dbfdb940089e38b043d37f6c7b"
+  integrity sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==
+  dependencies:
+    define-properties "^1.1.3"
+    es-abstract "^1.17.0-next.1"
+
+array.prototype.flatmap@^1.2.3:
+  version "1.2.3"
+  resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.2.3.tgz#1c13f84a178566042dd63de4414440db9222e443"
+  integrity sha512-OOEk+lkePcg+ODXIpvuU9PAryCikCJyo7GlDG1upleEpQRx6mzL9puEBkozQ5iAx20KV0l3DbyQwqciJtqe5Pg==
+  dependencies:
+    define-properties "^1.1.3"
+    es-abstract "^1.17.0-next.1"
+    function-bind "^1.1.1"
+
 arraybuffer.slice@~0.0.7:
   version "0.0.7"
   resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675"
@@ -2227,11 +2523,46 @@ chardet@^0.7.0:
   resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
   integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
 
+chart.js@^2.9.3:
+  version "2.9.3"
+  resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-2.9.3.tgz#ae3884114dafd381bc600f5b35a189138aac1ef7"
+  integrity sha512-+2jlOobSk52c1VU6fzkh3UwqHMdSlgH1xFv9FKMqHiNCpXsGPQa/+81AFa+i3jZ253Mq9aAycPwDjnn1XbRNNw==
+  dependencies:
+    chartjs-color "^2.1.0"
+    moment "^2.10.2"
+
+chartjs-color-string@^0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/chartjs-color-string/-/chartjs-color-string-0.6.0.tgz#1df096621c0e70720a64f4135ea171d051402f71"
+  integrity sha512-TIB5OKn1hPJvO7JcteW4WY/63v6KwEdt6udfnDE9iCAZgy+V4SrbSxoIbTw/xkUIapjEI4ExGtD0+6D3KyFd7A==
+  dependencies:
+    color-name "^1.0.0"
+
+chartjs-color@^2.1.0:
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/chartjs-color/-/chartjs-color-2.4.1.tgz#6118bba202fe1ea79dd7f7c0f9da93467296c3b0"
+  integrity sha512-haqOg1+Yebys/Ts/9bLo/BqUcONQOdr/hoEr2LLTRl6C5LXctUdHxsCYfvQVg5JIxITrfCNUDr4ntqmQk9+/0w==
+  dependencies:
+    chartjs-color-string "^0.6.0"
+    color-convert "^1.9.3"
+
 check-types@^8.0.3:
   version "8.0.3"
   resolved "https://registry.yarnpkg.com/check-types/-/check-types-8.0.3.tgz#3356cca19c889544f2d7a95ed49ce508a0ecf552"
   integrity sha512-YpeKZngUmG65rLudJ4taU7VLkOCTMhNl/u4ctNC56LQS/zJTyNH0Lrtwm1tfTsbLlwvlfsA2d1c8vCf/Kh2KwQ==
 
+cheerio@^1.0.0-rc.3:
+  version "1.0.0-rc.3"
+  resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.3.tgz#094636d425b2e9c0f4eb91a46c05630c9a1a8bf6"
+  integrity sha512-0td5ijfUPuubwLUu0OBoe98gZj8C/AA+RW3v67GPlGOrvxWjZmBXiBCRU+I8VEiNyJzjth40POfHiz2RB3gImA==
+  dependencies:
+    css-select "~1.2.0"
+    dom-serializer "~0.1.1"
+    entities "~1.1.1"
+    htmlparser2 "^3.9.1"
+    lodash "^4.15.0"
+    parse5 "^3.0.1"
+
 "chokidar@>=2.0.0 <4.0.0", chokidar@^2.1.1, chokidar@^2.1.8:
   version "2.1.8"
   resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917"
@@ -2286,6 +2617,11 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
     inherits "^2.0.1"
     safe-buffer "^5.0.1"
 
+circular-json-es6@^2.0.1:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/circular-json-es6/-/circular-json-es6-2.0.2.tgz#e4f4a093e49fb4b6aba1157365746112a78bd344"
+  integrity sha512-ODYONMMNb3p658Zv+Pp+/XPa5s6q7afhz3Tzyvo+VRh9WIrJ64J76ZC4GQxnlye/NesTn09jvOiuE8+xxfpwhQ==
+
 class-utils@^0.3.5:
   version "0.3.6"
   resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
@@ -2360,7 +2696,7 @@ collection-visit@^1.0.0:
     map-visit "^1.0.0"
     object-visit "^1.0.0"
 
-color-convert@^1.9.0, color-convert@^1.9.1:
+color-convert@^1.9.0, color-convert@^1.9.1, color-convert@^1.9.3:
   version "1.9.3"
   resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
   integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
@@ -2403,7 +2739,7 @@ combine-source-map@^0.8.0, combine-source-map@~0.8.0:
     lodash.memoize "~3.0.3"
     source-map "~0.5.3"
 
-commander@^2.12.2, commander@^2.18.0, commander@^2.20.0:
+commander@^2.12.2, commander@^2.18.0, commander@^2.19.0, commander@^2.20.0:
   version "2.20.3"
   resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
   integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
@@ -2712,6 +3048,16 @@ css-select@^2.0.0:
     domutils "^1.7.0"
     nth-check "^1.0.2"
 
+css-select@~1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858"
+  integrity sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=
+  dependencies:
+    boolbase "~1.0.0"
+    css-what "2.1"
+    domutils "1.5.1"
+    nth-check "~1.0.1"
+
 css-tree@1.0.0-alpha.37:
   version "1.0.0-alpha.37"
   resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.37.tgz#98bebd62c4c1d9f960ec340cf9f7522e30709a22"
@@ -2728,6 +3074,11 @@ css-tree@1.0.0-alpha.39:
     mdn-data "2.0.6"
     source-map "^0.6.1"
 
+css-what@2.1:
+  version "2.1.3"
+  resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2"
+  integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==
+
 css-what@^3.2.1:
   version "3.3.0"
   resolved "https://registry.yarnpkg.com/css-what/-/css-what-3.3.0.tgz#10fec696a9ece2e591ac772d759aacabac38cd39"
@@ -2952,6 +3303,13 @@ decompress@^4.0.0, decompress@^4.2.0:
     pify "^2.3.0"
     strip-dirs "^2.0.0"
 
+deep-equal-ident@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/deep-equal-ident/-/deep-equal-ident-1.1.1.tgz#06f4b89e53710cd6cea4a7781c7a956642de8dc9"
+  integrity sha1-BvS4nlNxDNbOpKd4HHqVZkLejck=
+  dependencies:
+    lodash.isequal "^3.0"
+
 deep-is@~0.1.3:
   version "0.1.3"
   resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
@@ -3054,6 +3412,18 @@ dir-glob@^2.0.0:
   dependencies:
     path-type "^3.0.0"
 
+discontinuous-range@1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/discontinuous-range/-/discontinuous-range-1.0.0.tgz#e38331f0844bba49b9a9cb71c771585aab1bc65a"
+  integrity sha1-44Mx8IRLukm5qctxx3FYWqsbxlo=
+
+doctrine@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
+  integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==
+  dependencies:
+    esutils "^2.0.2"
+
 doctrine@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961"
@@ -3079,12 +3449,20 @@ dom-serializer@0:
     domelementtype "^2.0.1"
     entities "^2.0.0"
 
+dom-serializer@~0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.1.tgz#1ec4059e284babed36eec2941d4a970a189ce7c0"
+  integrity sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==
+  dependencies:
+    domelementtype "^1.3.0"
+    entities "^1.1.1"
+
 domain-browser@^1.1.1, domain-browser@^1.2.0:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda"
   integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==
 
-domelementtype@1:
+domelementtype@1, domelementtype@^1.3.0, domelementtype@^1.3.1:
   version "1.3.1"
   resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f"
   integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==
@@ -3094,7 +3472,22 @@ domelementtype@^2.0.1:
   resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.0.1.tgz#1f8bdfe91f5a78063274e803b4bdcedf6e94f94d"
   integrity sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ==
 
-domutils@^1.7.0:
+domhandler@^2.3.0:
+  version "2.4.2"
+  resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803"
+  integrity sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==
+  dependencies:
+    domelementtype "1"
+
+domutils@1.5.1:
+  version "1.5.1"
+  resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf"
+  integrity sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=
+  dependencies:
+    dom-serializer "0"
+    domelementtype "1"
+
+domutils@^1.5.1, domutils@^1.7.0:
   version "1.7.0"
   resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a"
   integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==
@@ -3299,11 +3692,87 @@ ent@~2.2.0:
   resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d"
   integrity sha1-6WQhkyWiHQX0RGai9obtbOX13R0=
 
+entities@^1.1.1, entities@~1.1.1:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56"
+  integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==
+
 entities@^2.0.0:
   version "2.0.3"
   resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.3.tgz#5c487e5742ab93c15abb5da22759b8590ec03b7f"
   integrity sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==
 
+enzyme-adapter-react-16@^1.15.2:
+  version "1.15.2"
+  resolved "https://registry.yarnpkg.com/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.15.2.tgz#b16db2f0ea424d58a808f9df86ab6212895a4501"
+  integrity sha512-SkvDrb8xU3lSxID8Qic9rB8pvevDbLybxPK6D/vW7PrT0s2Cl/zJYuXvsd1EBTz0q4o3iqG3FJhpYz3nUNpM2Q==
+  dependencies:
+    enzyme-adapter-utils "^1.13.0"
+    enzyme-shallow-equal "^1.0.1"
+    has "^1.0.3"
+    object.assign "^4.1.0"
+    object.values "^1.1.1"
+    prop-types "^15.7.2"
+    react-is "^16.12.0"
+    react-test-renderer "^16.0.0-0"
+    semver "^5.7.0"
+
+enzyme-adapter-utils@^1.13.0:
+  version "1.13.0"
+  resolved "https://registry.yarnpkg.com/enzyme-adapter-utils/-/enzyme-adapter-utils-1.13.0.tgz#01c885dde2114b4690bf741f8dc94cee3060eb78"
+  integrity sha512-YuEtfQp76Lj5TG1NvtP2eGJnFKogk/zT70fyYHXK2j3v6CtuHqc8YmgH/vaiBfL8K1SgVVbQXtTcgQZFwzTVyQ==
+  dependencies:
+    airbnb-prop-types "^2.15.0"
+    function.prototype.name "^1.1.2"
+    object.assign "^4.1.0"
+    object.fromentries "^2.0.2"
+    prop-types "^15.7.2"
+    semver "^5.7.1"
+
+enzyme-matchers@^7.1.2:
+  version "7.1.2"
+  resolved "https://registry.yarnpkg.com/enzyme-matchers/-/enzyme-matchers-7.1.2.tgz#d80530a61f22d28bb993dd7588abba38bd4de282"
+  integrity sha512-03WqAg2XDl7id9rARIO97HQ1JIw9F2heJ3R4meGu/13hx0ULTDEgl0E67MGl2Uq1jq1DyRnJfto1/VSzskdV5A==
+  dependencies:
+    circular-json-es6 "^2.0.1"
+    deep-equal-ident "^1.1.1"
+
+enzyme-shallow-equal@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/enzyme-shallow-equal/-/enzyme-shallow-equal-1.0.1.tgz#7afe03db3801c9b76de8440694096412a8d9d49e"
+  integrity sha512-hGA3i1so8OrYOZSM9whlkNmVHOicJpsjgTzC+wn2JMJXhq1oO4kA4bJ5MsfzSIcC71aLDKzJ6gZpIxrqt3QTAQ==
+  dependencies:
+    has "^1.0.3"
+    object-is "^1.0.2"
+
+enzyme@^3.11.0:
+  version "3.11.0"
+  resolved "https://registry.yarnpkg.com/enzyme/-/enzyme-3.11.0.tgz#71d680c580fe9349f6f5ac6c775bc3e6b7a79c28"
+  integrity sha512-Dw8/Gs4vRjxY6/6i9wU0V+utmQO9kvh9XLnz3LIudviOnVYDEe2ec+0k+NQoMamn1VrjKgCUOWj5jG/5M5M0Qw==
+  dependencies:
+    array.prototype.flat "^1.2.3"
+    cheerio "^1.0.0-rc.3"
+    enzyme-shallow-equal "^1.0.1"
+    function.prototype.name "^1.1.2"
+    has "^1.0.3"
+    html-element-map "^1.2.0"
+    is-boolean-object "^1.0.1"
+    is-callable "^1.1.5"
+    is-number-object "^1.0.4"
+    is-regex "^1.0.5"
+    is-string "^1.0.5"
+    is-subset "^0.1.1"
+    lodash.escape "^4.0.1"
+    lodash.isequal "^4.5.0"
+    object-inspect "^1.7.0"
+    object-is "^1.0.2"
+    object.assign "^4.1.0"
+    object.entries "^1.1.1"
+    object.values "^1.1.1"
+    raf "^3.4.1"
+    rst-selector-parser "^2.2.3"
+    string.prototype.trim "^1.2.1"
+
 errno@^0.1.3, errno@~0.1.7:
   version "0.1.7"
   resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618"
@@ -3318,7 +3787,7 @@ error-ex@^1.2.0, error-ex@^1.3.1:
   dependencies:
     is-arrayish "^0.2.1"
 
-es-abstract@^1.17.0-next.1, es-abstract@^1.17.2, es-abstract@^1.17.5:
+es-abstract@^1.17.0, es-abstract@^1.17.0-next.1, es-abstract@^1.17.2, es-abstract@^1.17.4, es-abstract@^1.17.5:
   version "1.17.6"
   resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.6.tgz#9142071707857b2cacc7b89ecb670316c3e2d52a"
   integrity sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==
@@ -3354,6 +3823,23 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
   resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
   integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
 
+eslint-plugin-react@^7.20.3:
+  version "7.20.3"
+  resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.20.3.tgz#0590525e7eb83890ce71f73c2cf836284ad8c2f1"
+  integrity sha512-txbo090buDeyV0ugF3YMWrzLIUqpYTsWSDZV9xLSmExE1P/Kmgg9++PD931r+KEWS66O1c9R4srLVVHmeHpoAg==
+  dependencies:
+    array-includes "^3.1.1"
+    array.prototype.flatmap "^1.2.3"
+    doctrine "^2.1.0"
+    has "^1.0.3"
+    jsx-ast-utils "^2.4.1"
+    object.entries "^1.1.2"
+    object.fromentries "^2.0.2"
+    object.values "^1.1.1"
+    prop-types "^15.7.2"
+    resolve "^1.17.0"
+    string.prototype.matchall "^4.0.2"
+
 eslint-scope@^4.0.2, eslint-scope@^4.0.3:
   version "4.0.3"
   resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848"
@@ -3896,10 +4382,6 @@ flatted@^2.0.0:
   resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138"
   integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==
 
-"flotr2@git+https://github.com/EnterpriseDB/Flotr2.git":
-  version "0.1.0"
-  resolved "git+https://github.com/EnterpriseDB/Flotr2.git#13dbb5c751ef8c7269c4cb190277b0d5eed8dc0f"
-
 flush-write-stream@^1.0.0:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8"
@@ -4016,11 +4498,25 @@ function-bind@^1.1.1:
   resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
   integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
 
+function.prototype.name@^1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.2.tgz#5cdf79d7c05db401591dfde83e3b70c5123e9a45"
+  integrity sha512-C8A+LlHBJjB2AdcRPorc5JvJ5VUoWlXdEHLOJdCI7kjHEtGTpHQUiqMvCIKUwIsGwZX2jZJy761AXsn356bJQg==
+  dependencies:
+    define-properties "^1.1.3"
+    es-abstract "^1.17.0-next.1"
+    functions-have-names "^1.2.0"
+
 functional-red-black-tree@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
   integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
 
+functions-have-names@^1.2.0:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.1.tgz#a981ac397fa0c9964551402cdc5533d7a4d52f91"
+  integrity sha512-j48B/ZI7VKs3sgeI2cZp7WXWmZXu7Iq5pl5/vptV5N2mq+DGFuS/ulaDjtaoLpYzuD6u8UgrUKHfgo7fDTSiBA==
+
 geometry-interfaces@^1.1.4:
   version "1.1.4"
   resolved "https://registry.yarnpkg.com/geometry-interfaces/-/geometry-interfaces-1.1.4.tgz#9e82af6700ca639a675299f08e1f5fbc4a79d48d"
@@ -4392,11 +4888,30 @@ html-comment-regex@^1.1.0, html-comment-regex@^1.1.2:
   resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.2.tgz#97d4688aeb5c81886a364faa0cad1dda14d433a7"
   integrity sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==
 
+html-element-map@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/html-element-map/-/html-element-map-1.2.0.tgz#dfbb09efe882806af63d990cf6db37993f099f22"
+  integrity sha512-0uXq8HsuG1v2TmQ8QkIhzbrqeskE4kn52Q18QJ9iAA/SnHoEKXWiUxHQtclRsCFWEUD2So34X+0+pZZu862nnw==
+  dependencies:
+    array-filter "^1.0.0"
+
 htmlescape@^1.1.0:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/htmlescape/-/htmlescape-1.1.1.tgz#3a03edc2214bca3b66424a3e7959349509cb0351"
   integrity sha1-OgPtwiFLyjtmQko+eVk0lQnLA1E=
 
+htmlparser2@^3.9.1:
+  version "3.10.1"
+  resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f"
+  integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==
+  dependencies:
+    domelementtype "^1.3.1"
+    domhandler "^2.3.0"
+    domutils "^1.5.1"
+    entities "^1.1.1"
+    inherits "^2.0.1"
+    readable-stream "^3.1.1"
+
 http-cache-semantics@3.8.1:
   version "3.8.1"
   resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2"
@@ -4716,6 +5231,15 @@ insert-module-globals@^7.0.0:
     undeclared-identifiers "^1.1.2"
     xtend "^4.0.0"
 
+internal-slot@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.2.tgz#9c2e9fb3cd8e5e4256c6f45fe310067fcfa378a3"
+  integrity sha512-2cQNfwhAfJIkU4KZPkDI+Gj5yNNnbqi40W9Gge6dfnk4TocEVm00B3bdiL+JINrbGJil2TeHvM4rETGzk/f/0g==
+  dependencies:
+    es-abstract "^1.17.0-next.1"
+    has "^1.0.3"
+    side-channel "^1.0.2"
+
 interpret@1.2.0:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296"
@@ -4798,6 +5322,11 @@ is-binary-path@~2.1.0:
   dependencies:
     binary-extensions "^2.0.0"
 
+is-boolean-object@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.0.1.tgz#10edc0900dd127697a92f6f9807c7617d68ac48e"
+  integrity sha512-TqZuVwa/sppcrhUCAYkGBk7w0yxfQQnxq28fjkO53tnK9FQXmdwz2JS5+GjsWQ6RByES1K40nI+yDic5c9/aAQ==
+
 is-buffer@^1.1.0, is-buffer@^1.1.5:
   version "1.1.6"
   resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
@@ -4808,7 +5337,7 @@ is-buffer@^2.0.2, is-buffer@^2.0.3:
   resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.4.tgz#3e572f23c8411a5cfd9557c849e3665e0b290623"
   integrity sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==
 
-is-callable@^1.1.4, is-callable@^1.2.0:
+is-callable@^1.1.4, is-callable@^1.1.5, is-callable@^1.2.0:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.0.tgz#83336560b54a38e35e3a2df7afd0454d691468bb"
   integrity sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==
@@ -4937,6 +5466,11 @@ is-natural-number@^4.0.1:
   resolved "https://registry.yarnpkg.com/is-natural-number/-/is-natural-number-4.0.1.tgz#ab9d76e1db4ced51e35de0c72ebecf09f734cde8"
   integrity sha1-q5124dtM7VHjXeDHLr7PCfc0zeg=
 
+is-number-object@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.4.tgz#36ac95e741cf18b283fc1ddf5e83da798e3ec197"
+  integrity sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==
+
 is-number@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195"
@@ -4976,7 +5510,7 @@ is-png@^1.0.0:
   resolved "https://registry.yarnpkg.com/is-png/-/is-png-1.1.0.tgz#d574b12bf275c0350455570b0e5b57ab062077ce"
   integrity sha1-1XSxK/J1wDUEVVcLDltXqwYgd84=
 
-is-regex@^1.1.0:
+is-regex@^1.0.5, is-regex@^1.1.0:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.0.tgz#ece38e389e490df0dc21caea2bd596f987f767ff"
   integrity sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==
@@ -4998,6 +5532,16 @@ is-stream@^1.0.0, is-stream@^1.1.0:
   resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
   integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
 
+is-string@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6"
+  integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==
+
+is-subset@^0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/is-subset/-/is-subset-0.1.1.tgz#8a59117d932de1de00f245fcdd39ce43f1e939a6"
+  integrity sha1-ilkRfZMt4d4A8kX83TnOQ/HpOaY=
+
 is-svg@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-3.0.0.tgz#9321dbd29c212e5ca99c4fa9794c714bcafa2f75"
@@ -5086,6 +5630,13 @@ jasmine-core@^3.3, jasmine-core@~3.3.0:
   resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-3.3.0.tgz#dea1cdc634bc93c7e0d4ad27185df30fa971b10e"
   integrity sha512-3/xSmG/d35hf80BEN66Y6g9Ca5l/Isdeg/j6zvbTYlTzeKinzmaTM4p9am5kYqOmE05D7s1t8FGjzdSnbUbceA==
 
+jasmine-enzyme@^7.1.2:
+  version "7.1.2"
+  resolved "https://registry.yarnpkg.com/jasmine-enzyme/-/jasmine-enzyme-7.1.2.tgz#a09ad4644841b2e402046dee5526253b961efa0f"
+  integrity sha512-4C9GeKgcJerRWBOt3nu9MAjjm5DK8kRbCBKLNWvDjbSfLWodomfjZA2lIpRcJkmof9tIfff2ZWa7DD53WLhyGA==
+  dependencies:
+    enzyme-matchers "^7.1.2"
+
 jest-worker@^25.4.0:
   version "25.5.0"
   resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-25.5.0.tgz#2611d071b79cea0f43ee57a3d118593ac1547db1"
@@ -5219,6 +5770,14 @@ jsonparse@^1.2.0:
   resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280"
   integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=
 
+jsx-ast-utils@^2.4.1:
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.4.1.tgz#1114a4c1209481db06c690c2b4f488cc665f657e"
+  integrity sha512-z1xSldJ6imESSzOjd3NNkieVJKRlKYSOtMG8SFyCj2FIrvSaSuli/WjpBkEzCBoR9bYYYFgqJw61Xhu7Lcgk+w==
+  dependencies:
+    array-includes "^3.1.1"
+    object.assign "^4.1.0"
+
 karma-babel-preprocessor@^8.0.0:
   version "8.0.1"
   resolved "https://registry.yarnpkg.com/karma-babel-preprocessor/-/karma-babel-preprocessor-8.0.1.tgz#63b33cc7b5b3b5c7815ec453f7df58fb88345af1"
@@ -5443,6 +6002,72 @@ locate-path@^5.0.0:
   dependencies:
     p-locate "^4.1.0"
 
+lodash._baseisequal@^3.0.0:
+  version "3.0.7"
+  resolved "https://registry.yarnpkg.com/lodash._baseisequal/-/lodash._baseisequal-3.0.7.tgz#d8025f76339d29342767dcc887ce5cb95a5b51f1"
+  integrity sha1-2AJfdjOdKTQnZ9zIh85cuVpbUfE=
+  dependencies:
+    lodash.isarray "^3.0.0"
+    lodash.istypedarray "^3.0.0"
+    lodash.keys "^3.0.0"
+
+lodash._bindcallback@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e"
+  integrity sha1-5THCdkTPi1epnhftlbNcdIeJOS4=
+
+lodash._getnative@^3.0.0:
+  version "3.9.1"
+  resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5"
+  integrity sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=
+
+lodash.escape@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-4.0.1.tgz#c9044690c21e04294beaa517712fded1fa88de98"
+  integrity sha1-yQRGkMIeBClL6qUXcS/e0fqI3pg=
+
+lodash.flattendeep@^4.4.0:
+  version "4.4.0"
+  resolved "https://registry.yarnpkg.com/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2"
+  integrity sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=
+
+lodash.isarguments@^3.0.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a"
+  integrity sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=
+
+lodash.isarray@^3.0.0:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55"
+  integrity sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=
+
+lodash.isequal@^3.0:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-3.0.4.tgz#1c35eb3b6ef0cd1ff51743e3ea3cf7fdffdacb64"
+  integrity sha1-HDXrO27wzR/1F0Pj6jz3/f/ay2Q=
+  dependencies:
+    lodash._baseisequal "^3.0.0"
+    lodash._bindcallback "^3.0.0"
+
+lodash.isequal@^4.5.0:
+  version "4.5.0"
+  resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
+  integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA=
+
+lodash.istypedarray@^3.0.0:
+  version "3.0.6"
+  resolved "https://registry.yarnpkg.com/lodash.istypedarray/-/lodash.istypedarray-3.0.6.tgz#c9a477498607501d8e8494d283b87c39281cef62"
+  integrity sha1-yaR3SYYHUB2OhJTSg7h8OSgc72I=
+
+lodash.keys@^3.0.0:
+  version "3.1.2"
+  resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a"
+  integrity sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=
+  dependencies:
+    lodash._getnative "^3.0.0"
+    lodash.isarguments "^3.0.0"
+    lodash.isarray "^3.0.0"
+
 lodash.memoize@^4.1.2:
   version "4.1.2"
   resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
@@ -5463,6 +6088,11 @@ lodash@^4.14.1, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.
   resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
   integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
 
+lodash@^4.15.0:
+  version "4.17.19"
+  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b"
+  integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==
+
 log4js@^4.0.0:
   version "4.5.1"
   resolved "https://registry.yarnpkg.com/log4js/-/log4js-4.5.1.tgz#e543625e97d9e6f3e6e7c9fc196dd6ab2cae30b5"
@@ -5487,7 +6117,7 @@ longest@^1.0.0:
   resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
   integrity sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=
 
-loose-envify@^1.0.0:
+loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0:
   version "1.4.0"
   resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
   integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
@@ -5877,6 +6507,16 @@ moment-timezone@^0.5.11, moment-timezone@^0.5.23:
   resolved "https://registry.yarnpkg.com/moment/-/moment-2.26.0.tgz#5e1f82c6bafca6e83e808b30c8705eed0dcbd39a"
   integrity sha512-oIixUO+OamkUkwjhAVE18rAMfRJNsNe/Stid/gwHSOfHrOtw9EhAY2AHvdKZ/k/MggcYELFCJz/Sn2pL8b8JMw==
 
+moment@^2.10.2:
+  version "2.27.0"
+  resolved "https://registry.yarnpkg.com/moment/-/moment-2.27.0.tgz#8bff4e3e26a236220dfe3e36de756b6ebaa0105d"
+  integrity sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ==
+
+moo@^0.5.0:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/moo/-/moo-0.5.1.tgz#7aae7f384b9b09f620b6abf6f74ebbcd1b65dbc4"
+  integrity sha512-I1mnb5xn4fO80BH9BLcF0yLypy2UKl+Cb01Fu0hJRkJjlCRtxZMWkTdAtDd5ZqCOxtCkhmRwyI57vWT+1iZ67w==
+
 mousetrap@^1.6.3:
   version "1.6.5"
   resolved "https://registry.yarnpkg.com/mousetrap/-/mousetrap-1.6.5.tgz#8a766d8c272b08393d5f56074e0b5ec183485bf9"
@@ -5950,6 +6590,17 @@ natural-compare@^1.4.0:
   resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
   integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
 
+nearley@^2.7.10:
+  version "2.19.5"
+  resolved "https://registry.yarnpkg.com/nearley/-/nearley-2.19.5.tgz#6be78e4942eeb9a043b17c563413111d4ad849b7"
+  integrity sha512-qoh1ZXXl0Kpn40tFhmgvffUAlbpRMcjLUagNVnT1JmliUIsB4tFabmCNhD97+tkf9FZ/SLhhYzNow0V3GitzDg==
+  dependencies:
+    commander "^2.19.0"
+    moo "^0.5.0"
+    railroad-diagrams "^1.0.0"
+    randexp "0.4.6"
+    semver "^5.4.1"
+
 neatequal@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/neatequal/-/neatequal-1.0.0.tgz#2ee1211bc9fa6e4c55715fd210bb05602eb1ae3b"
@@ -6062,7 +6713,7 @@ npm-run-path@^2.0.0:
   dependencies:
     path-key "^2.0.0"
 
-nth-check@^1.0.2:
+nth-check@^1.0.2, nth-check@~1.0.1:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c"
   integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==
@@ -6103,6 +6754,14 @@ object-inspect@^1.7.0:
   resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67"
   integrity sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==
 
+object-is@^1.0.2, object-is@^1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.2.tgz#c5d2e87ff9e119f78b7a088441519e2eec1573b6"
+  integrity sha512-5lHCz+0uufF6wZ7CRFWJN3hp8Jqblpgve06U5CMQ3f//6iDjPr2PEo9MWCjEssDsa+UZEL4PkFpr+BMop6aKzQ==
+  dependencies:
+    define-properties "^1.1.3"
+    es-abstract "^1.17.5"
+
 object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
@@ -6125,6 +6784,25 @@ object.assign@^4.1.0:
     has-symbols "^1.0.0"
     object-keys "^1.0.11"
 
+object.entries@^1.1.1, object.entries@^1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.2.tgz#bc73f00acb6b6bb16c203434b10f9a7e797d3add"
+  integrity sha512-BQdB9qKmb/HyNdMNWVr7O3+z5MUIx3aiegEIJqjMBbBf0YT9RRxTJSim4mzFqtyr7PDAHigq0N9dO0m0tRakQA==
+  dependencies:
+    define-properties "^1.1.3"
+    es-abstract "^1.17.5"
+    has "^1.0.3"
+
+object.fromentries@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.2.tgz#4a09c9b9bb3843dd0f89acdb517a794d4f355ac9"
+  integrity sha512-r3ZiBH7MQppDJVLx6fhD618GKNG40CZYH9wgwdhKxBDDbQgjeWGGd4AtkZad84d291YxvWe7bJGuE65Anh0dxQ==
+  dependencies:
+    define-properties "^1.1.3"
+    es-abstract "^1.17.0-next.1"
+    function-bind "^1.1.1"
+    has "^1.0.3"
+
 object.getownpropertydescriptors@^2.1.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz#369bf1f9592d8ab89d712dced5cb81c7c5352649"
@@ -6140,7 +6818,7 @@ object.pick@^1.3.0:
   dependencies:
     isobject "^3.0.1"
 
-object.values@^1.1.0:
+object.values@^1.1.0, object.values@^1.1.1:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.1.tgz#68a99ecde356b7e9295a3c5e0ce31dc8c953de5e"
   integrity sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==
@@ -6438,6 +7116,13 @@ parse-passwd@^1.0.0:
   resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
   integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=
 
+parse5@^3.0.1:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.3.tgz#042f792ffdd36851551cf4e9e066b3874ab45b5c"
+  integrity sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==
+  dependencies:
+    "@types/node" "*"
+
 parseqs@0.0.5:
   version "0.0.5"
   resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d"
@@ -6551,6 +7236,11 @@ pend@~1.2.0:
   resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
   integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA=
 
+performance-now@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
+  integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
+
 picomatch@^2.0.4, picomatch@^2.2.1:
   version "2.2.2"
   resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad"
@@ -7012,6 +7702,24 @@ promise-inflight@^1.0.1:
   resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
   integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM=
 
+prop-types-exact@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/prop-types-exact/-/prop-types-exact-1.2.0.tgz#825d6be46094663848237e3925a98c6e944e9869"
+  integrity sha512-K+Tk3Kd9V0odiXFP9fwDHUYRyvK3Nun3GVyPapSIs5OBkITAm15W0CPFD/YKTkMUAbc0b9CUwRQp2ybiBIq+eA==
+  dependencies:
+    has "^1.0.3"
+    object.assign "^4.1.0"
+    reflect.ownkeys "^0.2.0"
+
+prop-types@^15.6.2, prop-types@^15.7.2:
+  version "15.7.2"
+  resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
+  integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
+  dependencies:
+    loose-envify "^1.4.0"
+    object-assign "^4.1.1"
+    react-is "^16.8.1"
+
 proto-list@~1.2.1:
   version "1.2.4"
   resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849"
@@ -7121,6 +7829,26 @@ querystring@0.2.0:
   resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
   integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=
 
+raf@^3.4.1:
+  version "3.4.1"
+  resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39"
+  integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==
+  dependencies:
+    performance-now "^2.1.0"
+
+railroad-diagrams@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz#eb7e6267548ddedfb899c1b90e57374559cddb7e"
+  integrity sha1-635iZ1SN3t+4mcG5Dlc3RVnN234=
+
+randexp@0.4.6:
+  version "0.4.6"
+  resolved "https://registry.yarnpkg.com/randexp/-/randexp-0.4.6.tgz#e986ad5e5e31dae13ddd6f7b3019aa7c87f60ca3"
+  integrity sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==
+  dependencies:
+    discontinuous-range "1.0.0"
+    ret "~0.1.10"
+
 randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
@@ -7159,6 +7887,40 @@ raw-loader@^1.0.0:
     loader-utils "^1.1.0"
     schema-utils "^1.0.0"
 
+react-dom@^16.13.1:
+  version "16.13.1"
+  resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.13.1.tgz#c1bd37331a0486c078ee54c4740720993b2e0e7f"
+  integrity sha512-81PIMmVLnCNLO/fFOQxdQkvEq/+Hfpv24XNJfpyZhTRfO0QcmQIF/PgCa1zCOj2w1hrn12MFLyaJ/G0+Mxtfag==
+  dependencies:
+    loose-envify "^1.1.0"
+    object-assign "^4.1.1"
+    prop-types "^15.6.2"
+    scheduler "^0.19.1"
+
+react-is@^16.12.0, react-is@^16.13.1, react-is@^16.8.1, react-is@^16.8.6:
+  version "16.13.1"
+  resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
+  integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
+
+react-test-renderer@^16.0.0-0:
+  version "16.13.1"
+  resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.13.1.tgz#de25ea358d9012606de51e012d9742e7f0deabc1"
+  integrity sha512-Sn2VRyOK2YJJldOqoh8Tn/lWQ+ZiKhyZTPtaO0Q6yNj+QDbmRkVFap6pZPy3YQk8DScRDfyqm/KxKYP9gCMRiQ==
+  dependencies:
+    object-assign "^4.1.1"
+    prop-types "^15.6.2"
+    react-is "^16.8.6"
+    scheduler "^0.19.1"
+
+react@^16.13.1:
+  version "16.13.1"
+  resolved "https://registry.yarnpkg.com/react/-/react-16.13.1.tgz#2e818822f1a9743122c063d6410d85c1e3afe48e"
+  integrity sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w==
+  dependencies:
+    loose-envify "^1.1.0"
+    object-assign "^4.1.1"
+    prop-types "^15.6.2"
+
 read-only-stream@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/read-only-stream/-/read-only-stream-2.0.0.tgz#2724fd6a8113d73764ac288d4386270c1dbf17f0"
@@ -7206,7 +7968,7 @@ readable-stream@^1.0.33:
     isarray "0.0.1"
     string_decoder "~0.10.x"
 
-readable-stream@^3.6.0:
+readable-stream@^3.1.1, readable-stream@^3.6.0:
   version "3.6.0"
   resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
   integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
@@ -7239,6 +8001,11 @@ redent@^1.0.0:
     indent-string "^2.1.0"
     strip-indent "^1.0.1"
 
+reflect.ownkeys@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/reflect.ownkeys/-/reflect.ownkeys-0.2.0.tgz#749aceec7f3fdf8b63f927a04809e90c5c0b3460"
+  integrity sha1-dJrO7H8/34tj+SegSAnpDFwLNGA=
+
 regenerate-unicode-properties@^8.2.0:
   version "8.2.0"
   resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec"
@@ -7286,6 +8053,14 @@ regex-not@^1.0.0, regex-not@^1.0.2:
     extend-shallow "^3.0.2"
     safe-regex "^1.1.0"
 
+regexp.prototype.flags@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz#7aba89b3c13a64509dabcf3ca8d9fbb9bdf5cb75"
+  integrity sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==
+  dependencies:
+    define-properties "^1.1.3"
+    es-abstract "^1.17.0-next.1"
+
 regexpp@^2.0.1:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f"
@@ -7418,7 +8193,7 @@ resolve@1.1.7:
   resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
   integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=
 
-resolve@^1.1.4, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.3.2, resolve@^1.4.0:
+resolve@^1.1.4, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.17.0, resolve@^1.3.2, resolve@^1.4.0:
   version "1.17.0"
   resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444"
   integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==
@@ -7482,6 +8257,14 @@ ripemd160@^2.0.0, ripemd160@^2.0.1:
     hash-base "^3.0.0"
     inherits "^2.0.1"
 
+rst-selector-parser@^2.2.3:
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/rst-selector-parser/-/rst-selector-parser-2.2.3.tgz#81b230ea2fcc6066c89e3472de794285d9b03d91"
+  integrity sha1-gbIw6i/MYGbInjRy3nlChdmwPZE=
+  dependencies:
+    lodash.flattendeep "^4.4.0"
+    nearley "^2.7.10"
+
 run-async@^2.2.0:
   version "2.4.1"
   resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455"
@@ -7559,6 +8342,14 @@ sax@^1.2.4, sax@~1.2.4:
   resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
   integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
 
+scheduler@^0.19.1:
+  version "0.19.1"
+  resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196"
+  integrity sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==
+  dependencies:
+    loose-envify "^1.1.0"
+    object-assign "^4.1.1"
+
 schema-utils@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770"
@@ -7601,7 +8392,7 @@ semver-truncate@^1.1.2:
   dependencies:
     semver "^5.3.0"
 
-"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0:
+"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0, semver@^5.7.0, semver@^5.7.1:
   version "5.7.1"
   resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
   integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
@@ -7739,6 +8530,14 @@ shim-loader@^1.0.1:
     precond "^0.2.3"
     webpack-sources "^0.2.3"
 
+side-channel@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.2.tgz#df5d1abadb4e4bf4af1cd8852bf132d2f7876947"
+  integrity sha512-7rL9YlPHg7Ancea1S96Pa8/QWb4BtXL/TZvS6B8XFetGBeuhAsfmUspK6DokBeZ64+Kj9TCNRD/30pVz1BvQNA==
+  dependencies:
+    es-abstract "^1.17.0-next.1"
+    object-inspect "^1.7.0"
+
 signal-exit@^3.0.0, signal-exit@^3.0.2:
   version "3.0.3"
   resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
@@ -8121,6 +8920,27 @@ string.prototype.codepointat@^0.2.0:
   resolved "https://registry.yarnpkg.com/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz#004ad44c8afc727527b108cd462b4d971cd469bc"
   integrity sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==
 
+string.prototype.matchall@^4.0.2:
+  version "4.0.2"
+  resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.2.tgz#48bb510326fb9fdeb6a33ceaa81a6ea04ef7648e"
+  integrity sha512-N/jp6O5fMf9os0JU3E72Qhf590RSRZU/ungsL/qJUYVTNv7hTG0P/dbPjxINVN9jpscu3nzYwKESU3P3RY5tOg==
+  dependencies:
+    define-properties "^1.1.3"
+    es-abstract "^1.17.0"
+    has-symbols "^1.0.1"
+    internal-slot "^1.0.2"
+    regexp.prototype.flags "^1.3.0"
+    side-channel "^1.0.2"
+
+string.prototype.trim@^1.2.1:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.1.tgz#141233dff32c82bfad80684d7e5f0869ee0fb782"
+  integrity sha512-MjGFEeqixw47dAMFMtgUro/I0+wNqZB5GKXGt1fFr24u3TzDXCPu7J9Buppzoe3r/LqkSDLDDJzE15RGWDGAVw==
+  dependencies:
+    define-properties "^1.1.3"
+    es-abstract "^1.17.0-next.1"
+    function-bind "^1.1.1"
+
 string.prototype.trimend@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913"
