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 +@blueprint.route('/system_statistics', + endpoint='system_statistics', methods=['GET']) +@blueprint.route('/system_statistics/', + endpoint='system_statistics_sid', methods=['GET']) +@blueprint.route('/system_statistics//', + 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({ {/* System Statistics */} - - + + ; })} - - - Summary - - - CPU - - + + + + + + + + Memory - - + + Storage - - + + 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, };