/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
// Copyright (C) 2013 - 2024, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////
import React, { useEffect, useMemo, useState } from 'react';
import gettext from 'sources/gettext';
import PropTypes from 'prop-types';
import getApiInstance from 'sources/api_instance';
import PgTable from 'sources/components/PgTable';
import { InputCheckbox } from '../../../static/js/components/FormComponents';
import { makeStyles } from '@mui/styles';
import url_for from 'sources/url_for';
import Graphs from './Graphs';
import { Box, Tab, Tabs } from '@mui/material';
import { PgIconButton } from '../../../static/js/components/Buttons';
import CancelIcon from '@mui/icons-material/Cancel';
import StopSharpIcon from '@mui/icons-material/StopSharp';
import WelcomeDashboard from './WelcomeDashboard';
import ActiveQuery from './ActiveQuery.ui';
import _ from 'lodash';
import EmptyPanelMessage from '../../../static/js/components/EmptyPanelMessage';
import TabPanel from '../../../static/js/components/TabPanel';
import Summary from './SystemStats/Summary';
import CPU from './SystemStats/CPU';
import Memory from './SystemStats/Memory';
import Storage from './SystemStats/Storage';
import withStandardTabInfo from '../../../static/js/helpers/withStandardTabInfo';
import { BROWSER_PANELS } from '../../../browser/static/js/constants';
import { usePgAdmin } from '../../../static/js/BrowserComponent';
import usePreferences from '../../../preferences/static/js/store';
import ErrorBoundary from '../../../static/js/helpers/ErrorBoundary';
import { parseApiError } from '../../../static/js/api_instance';
import SectionContainer from './components/SectionContainer';
import Replication from './Replication';
import RefreshButton from './components/RefreshButtons';
import {getExpandCell } from '../../../static/js/components/PgTable';

function parseData(data) {
  let res = [];

  data.forEach((row) => {
    res.push({ ...row, icon: '' });
  });
  return res;
}

const useStyles = makeStyles((theme) => ({
  emptyPanel: {
    width: '100%',
    background: theme.otherVars.emptySpaceBg,
    overflow: 'auto',
    padding: '8px',
    display: 'flex',
  },
  dashboardPanel: {
    height: '100%',
    background: theme.palette.grey[400],
  },
  cardHeader: {
    padding: '0.25rem 0.5rem',
    fontWeight: 'bold !important',
    backgroundColor: theme.otherVars.tableBg,
    borderBottom: '1px solid',
    borderBottomColor: theme.otherVars.borderColor,
  },
  searchPadding: {
    display: 'flex',
    flex: 2.5,
  },
  component: {
    padding: '8px',
  },
  searchInput: {
    flex: 1,
  },
  panelIcon: {
    width: '80%',
    margin: '0 auto',
    marginTop: '25px !important',
    position: 'relative',
    textAlign: 'center',
  },
  panelMessage: {
    marginLeft: '0.5rem',
    fontSize: '0.875rem',
  },
  panelContent: {
    ...theme.mixins.panelBorder.all,
    display: 'flex',
    flexDirection: 'column',
    overflow: 'hidden !important',
    height: '100%',
    width: '100%',
    minHeight: '400px',
    padding: '4px'
  },
  mainTabs: {
    ...theme.mixins.panelBorder.all,
    height: '100%',
    display: 'flex',
    flexDirection: 'column'
  },
  terminateButton: {
    color: theme.palette.error.main
  },
  chartCard: {
    border: '1px solid '+theme.otherVars.borderColor,
  },
  chartCardContent: {
    padding: '0.25rem 0.5rem',
    height: '165px',
    display: 'flex',
  },
  chartLegend: {
    marginLeft: 'auto',
    '& > div': {
      display: 'flex',
      fontWeight: 'normal',
      flexWrap: 'wrap',

      '& .legend-value': {
        marginLeft: '4px',
        '& .legend-label': {
          marginLeft: '4px',
        }
      }
    }
  }
}));

function Dashboard({
  nodeItem, nodeData, node, treeNodeInfo,
  ...props
}) {
  const classes = useStyles();
  let tabs = [gettext('Sessions'), gettext('Locks'), gettext('Prepared Transactions')];
  let mainTabs = [gettext('General'), gettext('System Statistics')];
  if(treeNodeInfo?.server?.replication_type) {
    mainTabs.push(gettext('Replication'));
  }
  let systemStatsTabs = [gettext('Summary'), gettext('CPU'), gettext('Memory'), gettext('Storage')];
  const [dashData, setDashData] = useState([]);
  const [msg, setMsg] = useState('');
  const [ssMsg, setSsMsg] = useState('');
  const [tabVal, setTabVal] = useState(0);
  const [mainTabVal, setMainTabVal] = useState(0);
  const [refresh, setRefresh] = useState(false);
  const [activeOnly, setActiveOnly] = useState(false);
  const [schemaDict, setSchemaDict] = React.useState({});
  const [systemStatsTabVal, setSystemStatsTabVal] = useState(0);
  const [ldid, setLdid] = useState(0);

  const systemStatsTabChanged = (e, tabVal) => {
    setSystemStatsTabVal(tabVal);
  };
  const pgAdmin = usePgAdmin();
  const did = treeNodeInfo?.database?._id ?? 0;
  const sid = treeNodeInfo?.server?._id ?? 0;
  const dbConnected = treeNodeInfo?.database?.connected ?? false;
  const serverConnected = treeNodeInfo?.server?.connected ?? false;
  const prefStore = usePreferences();
  const preferences = _.merge(
    usePreferences().getPreferencesForModule('dashboards'),
    usePreferences().getPreferencesForModule('graphs'),
    usePreferences().getPreferencesForModule('misc')
  );

  if (!did) {
    tabs.push(gettext('Configuration'));
  }

  const tabChanged = (e, tabVal) => {
    setTabVal(tabVal);
  };

  const mainTabChanged = (e, tabVal) => {
    setMainTabVal(tabVal);
  };

  const serverConfigColumns = [
    {
      accessor: 'name',
      Header: gettext('Name'),
      sortable: true,
      resizable: true,
      disableGlobalFilter: false,
      minWidth: 50,
      width: 100,
      minResizeWidth: 150,
    },
    {
      accessor: 'category',
      Header: gettext('Category'),
      sortable: true,
      resizable: true,
      disableGlobalFilter: false,
      minWidth: 50,
    },
    {
      accessor: 'setting',
      Header: gettext('Value'),
      sortable: true,
      resizable: true,
      disableGlobalFilter: false,
      minWidth: 50,
      width: 100,
    },
    {
      accessor: 'unit',
      Header: gettext('Unit'),
      sortable: true,
      resizable: true,
      disableGlobalFilter: false,
      minWidth: 26,
      width: 30,
    },
    {
      accessor: 'short_desc',
      Header: gettext('Description'),
      sortable: true,
      resizable: true,
      disableGlobalFilter: false,
    },
  ];

  const activityColumns = [
    {
      accessor: 'terminate_query',
      Header: () => null,
      sortable: true,
      resizable: false,
      disableGlobalFilter: false,
      disableResizing: true,
      width: 35,
      maxWidth: 35,
      minWidth: 35,
      id: 'btn-terminate',
      // eslint-disable-next-line react/display-name
      Cell: ({ row }) => {
        let terminate_session_url =
          url_for('dashboard.index') + 'terminate_session' + '/' + sid,
          title = gettext('Terminate Session?'),
          txtConfirm = gettext(
            'Are you sure you wish to terminate the session?'
          ),
          txtSuccess = gettext('Session terminated successfully.'),
          txtError = gettext(
            'An error occurred whilst terminating the active query.'
          );
        const action_url = did
          ? terminate_session_url + '/' + did
          : terminate_session_url;

        const api = getApiInstance();

        return (
          <PgIconButton
            size="xs"
            noBorder
            icon={<CancelIcon />}
            className={classes.terminateButton}
            onClick={() => {
              if (
                !canTakeAction(row, 'terminate')
              )
                return;
              let url = action_url + '/' + row.values.pid;
              pgAdmin.Browser.notifier.confirm(
                title,
                txtConfirm,
                function () {
                  api
                    .delete(url)
                    .then(function (res) {
                      if (res.data == gettext('Success')) {
                        pgAdmin.Browser.notifier.success(txtSuccess);
                        setRefresh(!refresh);
                      } else {
                        pgAdmin.Browser.notifier.error(txtError);
                      }
                    })
                    .catch(function (error) {
                      pgAdmin.Browser.notifier.alert(
                        gettext('Failed to perform the operation.'),
                        parseApiError(error)
                      );
                    });
                },
                function () {
                  return true;
                }
              );
            }}
            aria-label="Terminate Session?"
            title={gettext('Terminate Session?')}
          ></PgIconButton>
        );
      },
    },
    {
      accessor: 'cancel_Query',
      Header: () => null,
      sortable: true,
      resizable: false,
      disableGlobalFilter: false,
      width: 35,
      minWidth: 0,
      id: 'btn-cancel',
      Cell: ({ row }) => {
        let cancel_query_url =
          url_for('dashboard.index') + 'cancel_query' + '/' + sid,
          title = gettext('Cancel Active Query?'),
          txtConfirm = gettext(
            'Are you sure you wish to cancel the active query?'
          ),
          txtSuccess = gettext('Active query cancelled successfully.'),
          txtError = gettext(
            'An error occurred whilst cancelling the active query.'
          );

        const action_url = did ? cancel_query_url + '/' + did : cancel_query_url;

        const api = getApiInstance();

        return (
          <PgIconButton
            size="xs"
            noBorder
            icon={<StopSharpIcon/>}
            onClick={() => {
              if (!canTakeAction(row, 'cancel'))
                return;
              let url = action_url + '/' + row.values.pid;
              pgAdmin.Browser.notifier.confirm(
                title,
                txtConfirm,
                function () {
                  api
                    .delete(url)
                    .then(function (res) {
                      if (res.data == gettext('Success')) {
                        pgAdmin.Browser.notifier.success(txtSuccess);
                        setRefresh(!refresh);
                      } else {
                        pgAdmin.Browser.notifier.error(txtError);
                        setRefresh(!refresh);

                      }
                    })
                    .catch(function (error) {
                      pgAdmin.Browser.notifier.alert(
                        gettext('Failed to perform the operation.'),
                        parseApiError(error)
                      );
                    });
                },
                function () {
                  return true;
                }
              );
            }}
            aria-label="Cancel the query"
            title={gettext('Cancel the active query')}
          ></PgIconButton>
        );
      },
    },
    {
      accessor: 'view_active_query',
      Header: () => null,
      sortable: true,
      resizable: false,
      disableGlobalFilter: false,
      width: 35,
      minWidth: 0,
      id: 'btn-edit',
      Cell: getExpandCell({
        onClick: (row) => {
          let schema = new ActiveQuery({
            query: row.original.query,
            backend_type: row.original.backend_type,
            state_change: row.original.state_change,
            query_start: row.original.query_start,
          });
          setSchemaDict(prevState => ({
            ...prevState,
            [row.id]: schema
          }));
        },
        title: gettext('View the active session details')
      }),
    },
    {
      accessor: 'pid',
      Header: gettext('PID'),
      sortable: true,
      resizable: true,
      disableGlobalFilter: false,
      minWidth: 26,
      width: 60,
    },
    {
      accessor: 'datname',
      Header: gettext('Database'),
      sortable: true,
      resizable: true,
      disableGlobalFilter: false,
      minWidth: 26,
      width: 80,
      isVisible: !did
    },
    {
      accessor: 'usename',
      Header: gettext('User'),
      sortable: true,
      resizable: true,
      disableGlobalFilter: false,
      minWidth: 26,
      width: 60
    },
    {
      accessor: 'application_name',
      Header: gettext('Application'),
      sortable: true,
      resizable: true,
      disableGlobalFilter: false,
      minWidth: 26,
    },
    {
      accessor: 'client_addr',
      Header: gettext('Client'),
      sortable: true,
      resizable: true,
      disableGlobalFilter: false,
      minWidth: 26,
    },
    {
      accessor: 'backend_start',
      Header: gettext('Backend start'),
      sortable: true,
      resizable: true,
      disableGlobalFilter: false,
      minWidth: 100,
    },
    {
      accessor: 'xact_start',
      Header: gettext('Transaction start'),
      sortable: true,
      resizable: true,
      disableGlobalFilter: false,
      minWidth: 26,
    },
    {
      accessor: 'state',
      Header: gettext('State'),
      sortable: true,
      resizable: true,
      disableGlobalFilter: false,
      minWidth: 26,
      width:40
    },

    {
      accessor: 'waiting',
      Header: gettext('Waiting'),
      sortable: true,
      resizable: true,
      disableGlobalFilter: false,
      isVisible: treeNodeInfo?.server?.version < 90600
    },
    {
      accessor: 'wait_event',
      Header: gettext('Wait event'),
      sortable: true,
      resizable: true,
      disableGlobalFilter: false,
    },
    {
      accessor: 'blocking_pids',
      Header: gettext('Blocking PIDs'),
      sortable: true,
      resizable: true,
      disableGlobalFilter: false,
    },
  ];

  const databaseLocksColumns = [
    {
      accessor: 'pid',
      Header: gettext('PID'),
      sortable: true,
      resizable: true,
      disableGlobalFilter: false,
      minWidth: 26,
      width: 50,
    },
    {
      accessor: 'datname',
      Header: gettext('Database'),
      sortable: true,
      resizable: true,
      disableGlobalFilter: false,
      minWidth: 26,
      isVisible: !did,
      width: 80
    },
    {
      accessor: 'locktype',
      Header: gettext('Lock type'),
      sortable: true,
      resizable: true,
      disableGlobalFilter: false,
      minWidth: 26,
      width: 80,
    },
    {
      accessor: 'relation',
      Header: gettext('Target relation'),
      sortable: true,
      resizable: true,
      disableGlobalFilter: false,
    },
    {
      accessor: 'page',
      Header: gettext('Page'),
      sortable: true,
      resizable: true,
      disableGlobalFilter: false,
      minWidth: 26,
      width: 80,
    },
    {
      accessor: 'tuple',
      Header: gettext('Tuple'),
      sortable: true,
      resizable: true,
      disableGlobalFilter: false,
      minWidth: 26,
    },
    {
      accessor: 'virtualxid',
      Header: gettext('vXID (target)'),
      sortable: true,
      resizable: true,
      disableGlobalFilter: false,
      minWidth: 50,
      width: 80
    },
    {
      accessor: 'transactionid',
      Header: gettext('XID (target)'),
      sortable: true,
      resizable: true,
      disableGlobalFilter: false,
      minWidth: 50,
      width: 80,
    },
    {
      accessor: 'classid',
      Header: gettext('Class'),
      sortable: true,
      resizable: true,
      disableGlobalFilter: false,
      minWidth: 26,
      width: 80,
    },
    {
      accessor: 'objid',
      Header: gettext('Object ID'),
      sortable: true,
      resizable: true,
      disableGlobalFilter: false,
      minWidth: 50,
      width: 80,

    },
    {
      accessor: 'virtualtransaction',
      Header: gettext('vXID (owner)'),
      sortable: true,
      resizable: true,
      disableGlobalFilter: false,
      minWidth: 50,
    },
    {
      accessor: 'mode',
      Header: gettext('Mode'),
      sortable: true,
      resizable: true,
      disableGlobalFilter: false,
    },
    {
      id: 'granted',
      accessor: 'granted',
      Header: gettext('Granted?'),
      sortable: true,
      resizable: true,
      disableGlobalFilter: false,
      minWidth: 30,
      width: 80,
      Cell: ({ value }) => String(value)
    },
  ];

  const databasePreparedColumns = [
    {
      accessor: 'git',
      Header: gettext('Name'),
      sortable: true,
      resizable: true,
      disableGlobalFilter: false,
    },
    {
      accessor: 'datname',
      Header: gettext('Database'),
      sortable: true,
      resizable: true,
      disableGlobalFilter: false,
      minWidth: 26,
      width: 80,
      isVisible: !did
    },
    {
      accessor: 'Owner',
      Header: gettext('Owner'),
      sortable: true,
      resizable: true,
      disableGlobalFilter: false,
    },
    {
      accessor: 'transaction',
      Header: gettext('XID'),
      sortable: true,
      resizable: true,
      disableGlobalFilter: false,
    },
    {
      accessor: 'prepared',
      Header: gettext('Prepared at'),
      sortable: true,
      resizable: true,
      disableGlobalFilter: false,
    },
  ];

  const canTakeAction = (row, cellAction) => {
    // We will validate if user is allowed to cancel the active query
    // If there is only one active session means it probably our main
    // connection session
    cellAction = cellAction || null;
    let pg_version = treeNodeInfo.server.version || null,
      is_cancel_session = cellAction === 'cancel',
      txtMessage,
      maintenance_database = treeNodeInfo.server.db;

    let maintenanceActiveSessions = dashData.filter((data) => data.state === 'active'&&
      maintenance_database === data.datname);

    // With PG10, We have background process showing on dashboard
    // We will not allow user to cancel them as they will fail with error
    // anyway, so better usability we will throw our on notification

    // Background processes do not have database field populated
    if (pg_version && pg_version >= 100000 && !row.original.datname) {
      if (is_cancel_session) {
        txtMessage = gettext('You cannot cancel background worker processes.');
      } else {
        txtMessage = gettext(
          'You cannot terminate background worker processes.'
        );
      }
      pgAdmin.Browser.notifier.info(txtMessage);
      return false;
      // If it is the last active connection on maintenance db then error out
    } else if (
      maintenance_database == row.original.datname &&
      row.original.state == 'active' &&
      maintenanceActiveSessions.length === 1
    ) {
      if (is_cancel_session) {
        txtMessage = gettext(
          'You are not allowed to cancel the main active session.'
        );
      } else {
        txtMessage = gettext(
          'You are not allowed to terminate the main active session.'
        );
      }
      pgAdmin.Browser.notifier.error(txtMessage);
      return false;
    } else if (is_cancel_session && row.original.state == 'idle') {
      // If this session is already idle then do nothing
      pgAdmin.Browser.notifier.info(gettext('The session is already in idle state.'));
      return false;
    } else {
      // Will return true and let the backend handle all the cases.
      // Added as fix of #7217
      return true;
    }
  };
  useEffect(() => {
    // Reset Tab values to 0, so that it will select "Sessions" on node changed.
    nodeData?._type === 'database' && setTabVal(0);
  },[nodeData]);

  useEffect(() => {
    // disable replication tab
    if(!treeNodeInfo?.server?.replication_type && mainTabVal == 2) {
      setMainTabVal(0);
    }

    let url,
      ssExtensionCheckUrl = url_for('dashboard.check_system_statistics'),
      message = gettext(
        'Please connect to the selected server to view the dashboard.'
      );

    if(tabVal == 3 && did) {
      setTabVal(0);
    }

    if (sid && serverConnected) {
      if (tabVal === 0) {
        url = url_for('dashboard.activity');
      } else if (tabVal === 1) {
        url = url_for('dashboard.locks');
      } else if (tabVal === 2) {
        url = url_for('dashboard.prepared');
      } else {
        url = url_for('dashboard.config');
      }

      message = gettext('Loading dashboard...');
      if (did && !dbConnected) return;
      if (did) url += sid + '/' + did;
      else url += sid;

      if (did && !dbConnected) return;
      if (did && did > 0) ssExtensionCheckUrl += '/' + sid + '/' + did;
      else ssExtensionCheckUrl += '/' + sid;

      const api = getApiInstance();
      if (node) {
        if (mainTabVal == 0) {
          api({
            url: url,
            type: 'GET',
          })
            .then((res) => {
              setDashData(parseData(res.data));
            })
            .catch((error) => {
              pgAdmin.Browser.notifier.alert(
                gettext('Failed to retrieve data from the server.'),
                _.isUndefined(error.response) ? error.message : error.response.data.errormsg
              );
              // show failed message.
              setMsg(gettext('Failed to retrieve data from the server.'));
            });
        }
        else if (mainTabVal == 1) {
          api({
            url: ssExtensionCheckUrl,
            type: 'GET',
          })
            .then((res) => {
              const data = res.data;
              if(!data['ss_present']){
                setSsMsg(gettext('The system_stats extension is not installed. You can install the extension in a database using the "CREATE EXTENSION system_stats;" SQL command. Reload pgAdmin once it is installed.'));
                setLdid(0);
              } else {
                setSsMsg('installed');
                setLdid(did);
              }
            })
            .catch(() => {
              setSsMsg(gettext('Failed to verify the presence of system stats extension.'));
              setLdid(0);
            });
        } else {
          setSsMsg('');
          setLdid(0);
        }
      } else {
        setMsg(message);
      }
    }
    if (message != '') {
      setMsg(message);
    }
  }, [nodeData, tabVal, treeNodeInfo, prefStore, refresh, mainTabVal]);

  const filteredDashData = useMemo(()=>{
    if (tabVal == 0 && activeOnly) {
      // we want to show 'idle in transaction', 'active', 'active in transaction', and future non-blank, non-"idle" status values
      return dashData.filter((r)=>(r.state && r.state != '' && r.state != 'idle'));
    }
    return dashData;
  }, [dashData, activeOnly, tabVal]);

  const showDefaultContents = () => {
    return (
      sid && !serverConnected ? (
        <Box className={classes.dashboardPanel}>
          <div className={classes.emptyPanel}>
            <EmptyPanelMessage text={msg}/>
          </div>
        </Box>
      ) : (
        <WelcomeDashboard
          pgBrowser={pgAdmin.Browser}
          node={node}
          itemData={nodeData}
          item={nodeItem}
          sid={sid}
          did={did}
        />
      )
    );
  };

  const CustomActiveOnlyHeaderLabel =
    {
      label: gettext('Active sessions only'),
    };
  const CustomActiveOnlyHeader = () => {
    return (
      <InputCheckbox
        label={gettext('Active sessions only')}
        labelPlacement="end"
        className={classes.searchInput}
        onChange={(e) => {
          e.preventDefault();
          setActiveOnly(e.target.checked);
        }}
        value={activeOnly}
        controlProps={CustomActiveOnlyHeaderLabel}
      ></InputCheckbox>);
  };

  return (
    <>
      {sid && serverConnected ? (
        <Box className={classes.dashboardPanel}>
          <Box className={classes.panelContent}>
            <Box className={classes.mainTabs}>
              <Box>
                <Tabs
                  value={mainTabVal}
                  onChange={mainTabChanged}
                >
                  {mainTabs.map((tabValue) => {
                    return <Tab key={tabValue} label={tabValue} />;
                  })}
                </Tabs>
              </Box>
              {/* General Statistics */}
              <TabPanel value={mainTabVal} index={0} classNameRoot={classes.tabPanel}>
                {!_.isUndefined(preferences) && preferences.show_graphs && (
                  <Graphs
                    key={sid + did}
                    preferences={preferences}
                    sid={sid}
                    did={did}
                    pageVisible={props.isActive}
                  ></Graphs>
                )}
                {!_.isUndefined(preferences) && preferences.show_activity && (
                  <SectionContainer title={dbConnected ?  gettext('Database activity') : gettext('Server activity')}>
                    <Box>
                      <Tabs
                        value={tabVal}
                        onChange={tabChanged}
                      >
                        {tabs.map((tabValue) => {
                          return <Tab key={tabValue} label={tabValue} />;
                        })}
                        <RefreshButton onClick={(e) => {
                          e.preventDefault();
                          setRefresh(!refresh);
                        }}/>
                      </Tabs>
                    </Box>
                    <TabPanel value={tabVal} index={0} classNameRoot={classes.tabPanel}>
                      <PgTable
                        caveTable={false}
                        CustomHeader={CustomActiveOnlyHeader}
                        columns={activityColumns}
                        data={filteredDashData}
                        schema={schemaDict}
                      ></PgTable>
                    </TabPanel>
                    <TabPanel value={tabVal} index={1} classNameRoot={classes.tabPanel}>
                      <PgTable
                        caveTable={false}
                        columns={databaseLocksColumns}
                        data={dashData}
                      ></PgTable>
                    </TabPanel>
                    <TabPanel value={tabVal} index={2} classNameRoot={classes.tabPanel}>
                      <PgTable
                        caveTable={false}
                        columns={databasePreparedColumns}
                        data={dashData}
                      ></PgTable>
                    </TabPanel>
                    <TabPanel value={tabVal} index={3} classNameRoot={classes.tabPanel}>
                      <PgTable
                        caveTable={false}
                        columns={serverConfigColumns}
                        data={dashData}
                      ></PgTable>
                    </TabPanel>
                  </SectionContainer>
                )}
              </TabPanel>
              {/* System Statistics */}
              <TabPanel value={mainTabVal} index={1} classNameRoot={classes.tabPanel}>
                <Box height="100%" display="flex" flexDirection="column">
                  {ssMsg === 'installed' && did === ldid ?
                    <ErrorBoundary>
                      <Box>
                        <Tabs
                          value={systemStatsTabVal}
                          onChange={systemStatsTabChanged}
                        >
                          {systemStatsTabs.map((tabValue) => {
                            return <Tab key={tabValue} label={tabValue} />;
                          })}
                        </Tabs>
                      </Box>
                      <TabPanel value={systemStatsTabVal} index={0} classNameRoot={classes.tabPanel}>
                        <Summary
                          key={sid + did}
                          preferences={preferences}
                          sid={sid}
                          did={did}
                          pageVisible={props.isActive}
                          serverConnected={serverConnected}
                        />
                      </TabPanel>
                      <TabPanel value={systemStatsTabVal} index={1} classNameRoot={classes.tabPanel}>
                        <CPU
                          key={sid + did}
                          preferences={preferences}
                          sid={sid}
                          did={did}
                          pageVisible={props.isActive}
                          serverConnected={serverConnected}
                        />
                      </TabPanel>
                      <TabPanel value={systemStatsTabVal} index={2} classNameRoot={classes.tabPanel}>
                        <Memory
                          key={sid + did}
                          preferences={preferences}
                          sid={sid}
                          did={did}
                          pageVisible={props.isActive}
                          serverConnected={serverConnected}
                        />
                      </TabPanel>
                      <TabPanel value={systemStatsTabVal} index={3} classNameRoot={classes.tabPanel}>
                        <Storage
                          key={sid + did}
                          preferences={preferences}
                          sid={sid}
                          did={did}
                          pageVisible={props.isActive}
                          serverConnected={serverConnected}
                          systemStatsTabVal={systemStatsTabVal}
                        />
                      </TabPanel>
                    </ErrorBoundary> :
                    <div className={classes.emptyPanel}>
                      <EmptyPanelMessage text={ssMsg}/>
                    </div>
                  }
                </Box>
              </TabPanel>
              {/* Replication */}
              <TabPanel value={mainTabVal} index={2} classNameRoot={classes.tabPanel}>
                <Replication key={mainTabVal} sid={sid} node={node} treeNodeInfo={treeNodeInfo} nodeData={nodeData} pageVisible={props.isActive} />
              </TabPanel>
            </Box>
          </Box>
        </Box>
      ) : showDefaultContents() }
    </>
  );
}

Dashboard.propTypes = {
  node: PropTypes.func,
  itemData: PropTypes.object,
  nodeData: PropTypes.object,
  treeNodeInfo: PropTypes.object,
  nodeItem: PropTypes.object,
  preferences: PropTypes.object,
  sid: PropTypes.string,
  did: PropTypes.oneOfType([PropTypes.bool, PropTypes.number]),
  row: PropTypes.object,
  serverConnected: PropTypes.bool,
  dbConnected: PropTypes.bool,
  isActive: PropTypes.bool,
};

export default withStandardTabInfo(Dashboard, BROWSER_PANELS.DASHBOARD);
