public inbox for [email protected]  
help / color / mirror / Atom feed
From: Sahil Harpal <[email protected]>
To: Dave Page <[email protected]>
Cc: Aditya Toshniwal <[email protected]>
Cc: Akshay Joshi <[email protected]>
Cc: Khushboo Vashi <[email protected]>
Cc: [email protected]
Subject: Re: Pgadmin4 System Stats Extension Design
Date: Tue, 11 Jul 2023 11:58:29 +0530
Message-ID: <CAKi=nnfj2OcTBkUoWwMZ5YifExgrxs9Pbt42-2W1+n32LEmgvQ@mail.gmail.com> (raw)
In-Reply-To: <CAKi=nncko8TQVyGtEn_89DtZoztdhOA_e2-wSe8wROjZADgbXg@mail.gmail.com>
References: <CAKi=nneJvdbFyeDKnuQTVEnhNK0Zjdx5TWSwGUUSZO9YTC5E7Q@mail.gmail.com>
	<CANxoLDfO4BE0xvGLA3EBYyAzt3hCmuRcMY_pR3Zci9nPbL7P1Q@mail.gmail.com>
	<CAKi=nndnvAwgXVC=i=x3sSxNS9UCfks+EQWEjx8n5=u9CCP8og@mail.gmail.com>
	<CANxoLDeNzZkxYEnLdkFMkugvk7_k+BDSt6AoH83aaMkP+VZirQ@mail.gmail.com>
	<CAM9w-_mC2JKvxKKRwF7xCzoggoo0_XqBgUyqWDxXqSRQs_a0eg@mail.gmail.com>
	<CAKi=nncQ+OqkJ2PfvNNs40h5PfkO57YKTMEXdYeOpxUXhTzj5A@mail.gmail.com>
	<CA+OCxowriuEED8BC7DRZKwCM3dOfNaDWhf+vhJsH2PWq88yc7w@mail.gmail.com>
	<CAKi=nncY7wdMyqT2tKRAVWDaFSsgUS_qnOz0aifd-BorScUNSw@mail.gmail.com>
	<CA+OCxoyog3cqhZcEQ1xenmHUFMLM+VS8j91GM_RnU3VK8bGjaQ@mail.gmail.com>
	<CAKi=nncGiLTK36jQWnGL-0DToo4qTqojf+iLbDvRTfk2z_48Uw@mail.gmail.com>
	<CA+OCxowEmnWJHRa=QnuZpn42Cn594XZVduMPJuOg5MbdeQx0aw@mail.gmail.com>
	<CAKi=nnfMHZSGP3G+gS9JSLNp2C=BHF2ztsz6W0mpBREc4y=hiQ@mail.gmail.com>
	<CA+OCxowt2XSCEOxZ+Mz1CzMGQv5MCNV+GZO2b3E5PtZj1YgYOA@mail.gmail.com>
	<CAKi=nndoS4g8MmOBD6wZKCtGotpmxDa17rq8-obv3B9MaSbYjg@mail.gmail.com>
	<CA+OCxozjkCkVOFabHbMP+1sZ+hKftXA6Z8q00c+A2=mYHKbcuQ@mail.gmail.com>
	<CAKi=nncko8TQVyGtEn_89DtZoztdhOA_e2-wSe8wROjZADgbXg@mail.gmail.com>

Hi,

I have written code for the Summary and CPU tabs and would like to post it
here for review.

I'm currently displaying the static values in the process info pie chart
because of a minor bug. The pg_sys_process_info() query takes much longer
(around 2 mins) to execute and prevents the updation of other graphs and
tables. I tried adding it in separate useInterval with larger pollDelay,
but it didn't work. In the patch, I commented out that snippet (In
Summary.jsx).

I'm attaching the *WIP.patch* file which contains the latest changes and
also the SS of the Summary and CPU tabs.


Attachments:

  [image/png] CPU.png (132.8K, 3-CPU.png)
  download | view image

  [image/png] Summary.png (163.1K, 4-Summary.png)
  download | view image

  [application/x-patch] WIP.patch (9.6K, 5-WIP.patch)
  download | inline diff:
diff --git a/web/pgadmin/dashboard/__init__.py b/web/pgadmin/dashboard/__init__.py
index 1dac54e74..12f491ea6 100644
--- a/web/pgadmin/dashboard/__init__.py
+++ b/web/pgadmin/dashboard/__init__.py
@@ -197,6 +197,9 @@ class DashboardModule(PgAdminModule):
             'dashboard.get_prepared_by_database_id',
             'dashboard.config',
             'dashboard.get_config_by_server_id',
+            'dashboard.system_statistics',
+            'dashboard.system_statistics_sid',
+            'dashboard.system_statistics_did',
         ]
 
 
@@ -536,3 +539,38 @@ def terminate_session(sid=None, did=None, pid=None):
         response=gettext("Success") if res else gettext("Failed"),
         status=200
     )
+
+
+# System Statistics Backend
[email protected]('/system_statistics',
+                 endpoint='system_statistics', methods=['GET'])
[email protected]('/system_statistics/<int:sid>',
+                 endpoint='system_statistics_sid', methods=['GET'])
[email protected]('/system_statistics/<int:sid>/<int:did>',
+                 endpoint='system_statistics_did', methods=['GET'])
+
+@login_required
+@check_precondition
+def system_statistics(sid=None, did=None):
+    resp_data = {}
+
+    if request.args['chart_names'] != '':
+        chart_names = request.args['chart_names'].split(',')
+
+        if not sid:
+            return internal_server_error(errormsg='Server ID not specified.')
+
+        sql = render_template(
+            "/".join([g.template_path, 'system_statistics.sql']), did=did,
+            chart_names=chart_names,
+        )
+        status, res = g.conn.execute_dict(sql)
+
+        for chart_row in res['rows']:
+            resp_data[chart_row['chart_name']] = json.loads(
+                chart_row['chart_data'])
+
+    return ajax_response(
+        response=resp_data,
+        status=200
+    )
diff --git a/web/pgadmin/dashboard/static/js/Dashboard.jsx b/web/pgadmin/dashboard/static/js/Dashboard.jsx
index 588583eb3..d65c375ca 100644
--- a/web/pgadmin/dashboard/static/js/Dashboard.jsx
+++ b/web/pgadmin/dashboard/static/js/Dashboard.jsx
@@ -29,6 +29,8 @@ import _ from 'lodash';
 import CachedOutlinedIcon from '@material-ui/icons/CachedOutlined';
 import EmptyPanelMessage from '../../../static/js/components/EmptyPanelMessage';
 import TabPanel from '../../../static/js/components/TabPanel';
+import Summary from './Summary';
+import CPU from './CPU';
 
 function parseData(data) {
   let res = [];
@@ -154,10 +156,14 @@ export default function Dashboard({
   const [msg, setMsg] = useState('');
   const [tabVal, setTabVal] = useState(0);
   const [mainTabVal, setmainTabVal] = useState(0);
-  const [systemStatsTabVal, setSystemStatsTabVal] = useState(0);
   const [refresh, setRefresh] = useState(false);
   const [activeOnly, setActiveOnly] = useState(false);
   const [schemaDict, setSchemaDict] = React.useState({});
+  const [systemStatsTabVal, setSystemStatsTabVal] = useState(0);
+      
+  const systemStatsTabChanged = (e, tabVal) => {
+      setSystemStatsTabVal(tabVal);
+  };
 
   if (!did) {
     tabs.push(gettext('Configuration'));
@@ -171,10 +177,6 @@ export default function Dashboard({
     setmainTabVal(tabVal);
   };
 
-  const systemStatsTabChanged = (e, tabVal) => {
-    setSystemStatsTabVal(tabVal);
-  };
-
   const serverConfigColumns = [
     {
       accessor: 'name',
@@ -959,8 +961,8 @@ export default function Dashboard({
                 </TabPanel>
                 {/* System Statistics */}
                 <TabPanel value={mainTabVal} index={1} classNameRoot={classes.tabPanel}>
-                  <Box height="100%" display="flex" flexDirection="column">
-                    <Box>
+                <Box height="100%" display="flex" flexDirection="column">
+                  <Box>
                       <Tabs
                         value={systemStatsTabVal}
                         onChange={systemStatsTabChanged}
@@ -969,20 +971,32 @@ export default function Dashboard({
                           return <Tab key={tabValue} label={tabValue} />;
                         })}
                       </Tabs>
-                    </Box>
-                    <TabPanel value={systemStatsTabVal} index={0} classNameRoot={classes.tabPanel}>
-                      Summary
-                    </TabPanel>
-                    <TabPanel value={systemStatsTabVal} index={1} classNameRoot={classes.tabPanel}>
-                      CPU
-                    </TabPanel>
-                    <TabPanel value={systemStatsTabVal} index={2} classNameRoot={classes.tabPanel}>
+                  </Box>
+                  <TabPanel value={systemStatsTabVal} index={0} classNameRoot={classes.tabPanel}>
+                    <Summary
+                      key={sid + did}
+                      sid={sid} 
+                      did={did}
+                      pageVisible={props.panelVisible}
+                      serverConnected={props.serverConnected}
+                    />
+                  </TabPanel>
+                  <TabPanel value={systemStatsTabVal} index={1} classNameRoot={classes.tabPanel}>
+                    <CPU
+                      key={sid + did}
+                      sid={sid} 
+                      did={did}
+                      pageVisible={props.panelVisible}
+                      serverConnected={props.serverConnected}
+                    />
+                  </TabPanel>
+                  <TabPanel value={systemStatsTabVal} index={2} classNameRoot={classes.tabPanel}>
                       Memory
-                    </TabPanel>
-                    <TabPanel value={systemStatsTabVal} index={3} classNameRoot={classes.tabPanel}>
+                  </TabPanel>
+                  <TabPanel value={systemStatsTabVal} index={3} classNameRoot={classes.tabPanel}>
                       Storage
-                    </TabPanel>
-                  </Box>
+                  </TabPanel>
+              </Box>
                 </TabPanel>
               </Box>
             </Box>
diff --git a/web/pgadmin/static/js/components/PgChart/StreamingChart.jsx b/web/pgadmin/static/js/components/PgChart/StreamingChart.jsx
index bd465e3da..1e03cd21b 100644
--- a/web/pgadmin/static/js/components/PgChart/StreamingChart.jsx
+++ b/web/pgadmin/static/js/components/PgChart/StreamingChart.jsx
@@ -58,44 +58,32 @@ function tooltipPlugin(refreshRate) {
   };
 }
 
-export default function StreamingChart({xRange=75, data, options}) {
+export default function StreamingChart({xRange=75, data, options, showSecondAxis=false}) {
   const chartRef = useRef();
   const theme = useTheme();
   const { width, height, ref:containerRef } = useResizeDetector();
-  const defaultOptions = useMemo(()=>({
-    title: '',
-    width: width,
-    height: height,
-    padding: [10, 0, 10, 0],
-    focus: {
-      alpha: 0.3,
-    },
-    cursor: {
-      y: false,
-      drag: {
-        setScale: false,
-      }
-    },
-    series: [
+  const defaultOptions = useMemo(()=> {
+    const series = [
       {},
-      ...(data.datasets?.map((datum)=>({
+      ...(data.datasets?.map((datum, index) => ({
         label: datum.label,
         stroke: datum.borderColor,
         width: options.lineBorderWidth ?? 1,
-        points: { show: options.showDataPoints ?? false, size: datum.pointHitRadius*2 }
-      }))??{})
-    ],
-    scales: {
-      x: {
-        time: false,
-      }
-    },
-    axes: [
+        scale: showSecondAxis && (index === 1) ? 'y1' : 'y',
+        points: { show: options.showDataPoints ?? false, size: datum.pointHitRadius * 2 },
+      })) ?? []),
+    ];
+
+    const axes = [
       {
         show: false,
         stroke: theme.palette.text.primary,
       },
-      {
+    ];
+
+    if(showSecondAxis){
+      axes.push({
+        scale: 'y',
         grid: {
           stroke: theme.otherVars.borderColor,
           width: 0.5,
@@ -109,10 +97,64 @@ export default function StreamingChart({xRange=75, data, options}) {
           }
           return size;
         }
-      }
-    ],
-    plugins: options.showTooltip ? [tooltipPlugin(data.refreshRate)] : [],
-  }), [data.refreshRate, data?.datasets?.length, width, height, options]);
+      });
+      axes.push({
+        scale: 'y1',
+        side: 1,
+        stroke: theme.palette.text.primary,
+        grid: {show: false},
+        size: function(_obj, values) {
+          let size = 40;
+          if(values?.length > 0) {
+            size = values[values.length-1].length*12;
+            if(size < 40) size = 40;
+          }
+          return size;
+        }
+      });
+    } else{
+      axes.push({
+        scale: 'y',
+        grid: {
+          stroke: theme.otherVars.borderColor,
+          width: 0.5,
+        },
+        stroke: theme.palette.text.primary,
+        size: function(_obj, values) {
+          let size = 40;
+          if(values?.length > 0) {
+            size = values[values.length-1].length*12;
+            if(size < 40) size = 40;
+          }
+          return size;
+        }
+      });
+    }
+  
+    return {
+      title: '',
+      width: width,
+      height: height,
+      padding: [10, 0, 10, 0],
+      focus: {
+        alpha: 0.3,
+      },
+      cursor: {
+        y: false,
+        drag: {
+          setScale: false,
+        }
+      },
+      series: series,
+      scales: {
+        x: {
+          time: false,
+        }
+      },
+      axes: axes,
+      plugins: options.showTooltip ? [tooltipPlugin(data.refreshRate)] : [],
+    };
+  }, [data.refreshRate, data?.datasets?.length, width, height, options]);
 
   const initialState = [
     Array.from(new Array(xRange).keys()),
@@ -140,4 +182,5 @@ StreamingChart.propTypes = {
   xRange: PropTypes.number.isRequired,
   data: propTypeData.isRequired,
   options: PropTypes.object,
+  showSecondAxis: PropTypes.bool,
 };


view thread (106+ messages)  latest in thread

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: [email protected]
  Cc: [email protected], [email protected], [email protected], [email protected], [email protected]
  Subject: Re: Pgadmin4 System Stats Extension Design
  In-Reply-To: <CAKi=nnfj2OcTBkUoWwMZ5YifExgrxs9Pbt42-2W1+n32LEmgvQ@mail.gmail.com>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox