diff --git a/docs/en_US/images/preferences_dashboard_display.png b/docs/en_US/images/preferences_dashboard_display.png new file mode 100644 index 000000000..50c045771 Binary files /dev/null and b/docs/en_US/images/preferences_dashboard_display.png differ diff --git a/docs/en_US/preferences.rst b/docs/en_US/preferences.rst index 2492628b9..9a44a557a 100644 --- a/docs/en_US/preferences.rst +++ b/docs/en_US/preferences.rst @@ -60,6 +60,14 @@ Use the fields on the *Graphs* panel to specify your display preferences for the * Use the *Tuples out refresh rate* field to specify the number of seconds between tuples-out samples displayed in graphs. +.. image:: images/preferences_dashboard_display.png + :alt: Preferences dialog dashboard display options + +* When the *Show graphs?* switch is set to *True*, graphs will be displayed on dashboards. + +* When the *Show activity?* switch is set to *True*, activity tables will be displayed on dashboards. + + **The Debugger Node** Expand the *Debugger* node to specify your debugger display preferences. diff --git a/web/pgadmin/dashboard/__init__.py b/web/pgadmin/dashboard/__init__.py index 0259a8f39..7666cb50c 100644 --- a/web/pgadmin/dashboard/__init__.py +++ b/web/pgadmin/dashboard/__init__.py @@ -115,6 +115,22 @@ class DashboardModule(PgAdminModule): help_str=gettext('The number of seconds between graph samples.') ) + self.display_graphs = self.dashboard_preference.register( + 'display', 'show_graphs', + gettext("Show graphs?"), 'boolean', True, + category_label=gettext('Display'), + help_str=gettext('If set to True, graphs ' + 'will be displayed on dashboards.') + ) + + self.display_server_activity = self.dashboard_preference.register( + 'display', 'show_activity', + gettext("Show activity?"), 'boolean', True, + category_label=gettext('Display'), + help_str=gettext('If set to True, activity tables ' + 'will be displayed on dashboards.') + ) + def get_exposed_url_endpoints(self): """ Returns: @@ -262,6 +278,7 @@ def index(sid=None, did=None): """ rates = {} + settings = {} prefs = Preferences.module('dashboards') @@ -286,6 +303,11 @@ def index(sid=None, did=None): rates['to_stats_refresh'] = to_stats_refresh_pref.get() bio_stats_refresh_pref = prefs.preference('bio_stats_refresh') rates['bio_stats_refresh'] = bio_stats_refresh_pref.get() + # Whether to display graphs and server activity preferences + show_graphs_pref = prefs.preference('show_graphs') + settings['show_graphs'] = show_graphs_pref.get() + show_activity_pref = prefs.preference('show_activity') + settings['show_activity'] = show_activity_pref.get() # Show the appropriate dashboard based on the identifiers passed to us if sid is None and did is None: @@ -295,7 +317,8 @@ def index(sid=None, did=None): '/dashboard/server_dashboard.html', sid=sid, rates=rates, - version=g.version + version=g.version, + settings=settings ) else: return render_template( @@ -303,7 +326,8 @@ def index(sid=None, did=None): sid=sid, did=did, rates=rates, - version=g.version + version=g.version, + settings=settings ) diff --git a/web/pgadmin/dashboard/static/js/dashboard.js b/web/pgadmin/dashboard/static/js/dashboard.js index 6fcef0fbe..dd6ecf962 100644 --- a/web/pgadmin/dashboard/static/js/dashboard.js +++ b/web/pgadmin/dashboard/static/js/dashboard.js @@ -609,7 +609,17 @@ define('pgadmin.dashboard', [ }, // Rock n' roll on the server dashboard - init_server_dashboard: function(sid, version, session_stats_refresh, tps_stats_refresh, ti_stats_refresh, to_stats_refresh, bio_stats_refresh) { + init_server_dashboard: function( + sid, + version, + session_stats_refresh, + tps_stats_refresh, + ti_stats_refresh, + to_stats_refresh, + bio_stats_refresh, + show_graphs, + show_server_activity + ) { 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]; @@ -649,328 +659,344 @@ define('pgadmin.dashboard', [ }, }; - var server_activity_columns = [{ - name: 'pid', - label: gettext('PID'), - editable: false, - cell: 'string', - }, { - name: 'datname', - label: gettext('Database'), - editable: false, - cell: 'string', - }, { - name: 'usename', - label: gettext('User'), - editable: false, - cell: 'string', - }, { - name: 'application_name', - label: gettext('Application'), - editable: false, - cell: 'string', - }, { - name: 'client_addr', - label: gettext('Client'), - editable: false, - cell: 'string', - }, { - name: 'backend_start', - label: gettext('Backend start'), - editable: false, - cell: 'string', - }, { - name: 'state', - label: gettext('State'), - editable: false, - cell: 'string', - }]; - - if (version < 90600) { - server_activity_columns = server_activity_columns.concat( - [{ - name: 'waiting', - label: gettext('Waiting?'), - editable: false, - cell: 'string', - }]); - } else { - server_activity_columns = server_activity_columns.concat( - [{ - name: 'wait_event', - label: gettext('Wait Event'), - editable: false, - cell: 'string', - }, { - name: 'blocking_pids', - label: gettext('Blocking PIDs'), - editable: false, - cell: 'string', - }]); + // Display graphs + if(show_graphs) { + // Render the graphs + pgAdmin.Dashboard.render_chart( + div_sessions, data_sessions, dataset_sessions, sid, did, + url_for('dashboard.session_stats'), options_line, false, + session_stats_refresh + ); + pgAdmin.Dashboard.render_chart( + div_tps, data_tps, dataset_tps, sid, did, + url_for('dashboard.tps_stats'), options_line, true, + tps_stats_refresh + ); + pgAdmin.Dashboard.render_chart( + div_ti, data_ti, dataset_ti, sid, did, + url_for('dashboard.ti_stats'), options_line, true, + ti_stats_refresh + ); + pgAdmin.Dashboard.render_chart( + div_to, data_to, dataset_to, sid, did, + url_for('dashboard.to_stats'), options_line, true, + to_stats_refresh + ); + pgAdmin.Dashboard.render_chart( + div_bio, data_bio, dataset_bio, sid, did, + url_for('dashboard.bio_stats'), options_line, true, + bio_stats_refresh + ); } - var newActiveQueryDetailsModel = new ActiveQueryDetailsModel(); + // Display server activity + if (show_server_activity) { + var server_activity_columns = [{ + name: 'pid', + label: gettext('PID'), + editable: false, + cell: 'string', + }, { + name: 'datname', + label: gettext('Database'), + editable: false, + cell: 'string', + }, { + name: 'usename', + label: gettext('User'), + editable: false, + cell: 'string', + }, { + name: 'application_name', + label: gettext('Application'), + editable: false, + cell: 'string', + }, { + name: 'client_addr', + label: gettext('Client'), + editable: false, + cell: 'string', + }, { + name: 'backend_start', + label: gettext('Backend start'), + editable: false, + cell: 'string', + }, { + name: 'state', + label: gettext('State'), + editable: false, + cell: 'string', + }]; - var subNodeFieldsModel = Backform.generateViewSchema( - null, newActiveQueryDetailsModel, 'create', null, null, true - ); - - // Add version to each field - _.each(subNodeFieldsModel[0].fields, function(obj) { - obj['version'] = version; - }); - - // Add cancel active query button - server_activity_columns.unshift({ - name: 'pg-backform-expand', - label: '', - cell: SessionDetailsCell, - cell_priority: -1, - postgres_version: version, - schema: subNodeFieldsModel, - }); - - // Add cancel active query button - server_activity_columns.unshift({ - name: 'pg-backform-delete', - label: '', - cell: customDashboardActionCell, - cell_action: 'cancel', - editable: false, - cell_priority: -1, - canDeleteRow: pgAdmin.Dashboard.can_take_action, - postgres_version: version, - }); - - server_activity_columns.unshift({ - name: 'pg-backform-delete', - label: '', - cell: customDashboardActionCell, - cell_action: 'terminate', - editable: false, - cell_priority: -1, - canDeleteRow: pgAdmin.Dashboard.can_take_action, - postgres_version: version, - }); - - var server_locks_columns = [{ - name: 'pid', - label: gettext('PID'), - editable: false, - cell: 'string', - }, { - name: 'datname', - label: gettext('Database'), - editable: false, - cell: 'string', - }, { - name: 'locktype', - label: gettext('Lock type'), - editable: false, - cell: 'string', - }, { - name: 'relation', - label: gettext('Target relation'), - editable: false, - cell: 'string', - }, { - name: 'page', - label: gettext('Page'), - editable: false, - cell: 'string', - }, { - name: 'tuple', - label: gettext('Tuple'), - editable: false, - cell: 'string', - }, { - name: 'virtualxid', - label: gettext('vXID (target)'), - editable: false, - cell: 'string', - }, { - name: 'transactionid', - label: gettext('XID (target)'), - editable: false, - cell: 'string', - }, { - name: 'classid', - label: gettext('Class'), - editable: false, - cell: 'string', - }, { - name: 'objid', - label: gettext('Object ID'), - editable: false, - cell: 'string', - }, { - name: 'virtualtransaction', - label: gettext('vXID (owner)'), - editable: false, - cell: 'string', - }, { - name: 'mode', - label: gettext('Mode'), - editable: false, - cell: 'string', - }, { - name: 'granted', - label: gettext('Granted?'), - editable: false, - cell: 'string', - }]; - - var server_prepared_columns = [{ - name: 'git', - label: gettext('Name'), - editable: false, - cell: 'string', - }, { - name: 'database', - label: gettext('Database'), - editable: false, - cell: 'string', - }, { - name: 'Owner', - label: gettext('Owner'), - editable: false, - cell: 'string', - }, { - name: 'transaction', - label: gettext('XID'), - editable: false, - cell: 'string', - }, { - name: 'prepared', - label: gettext('Prepared at'), - editable: false, - cell: 'string', - }]; - - var server_config_columns = [{ - name: 'name', - label: gettext('Name'), - editable: false, - cell: 'string', - }, { - name: 'category', - label: gettext('Category'), - editable: false, - cell: 'string', - }, { - name: 'setting', - label: gettext('Setting'), - editable: false, - cell: 'string', - }, { - name: 'unit', - label: gettext('Unit'), - editable: false, - cell: 'string', - }, { - name: 'short_desc', - label: gettext('Description'), - editable: false, - cell: 'string', - }]; - - // Render the graphs - pgAdmin.Dashboard.render_chart( - div_sessions, data_sessions, dataset_sessions, sid, did, - url_for('dashboard.session_stats'), options_line, false, - session_stats_refresh - ); - pgAdmin.Dashboard.render_chart( - div_tps, data_tps, dataset_tps, sid, did, - url_for('dashboard.tps_stats'), options_line, true, - tps_stats_refresh - ); - pgAdmin.Dashboard.render_chart( - div_ti, data_ti, dataset_ti, sid, did, - url_for('dashboard.ti_stats'), options_line, true, - ti_stats_refresh - ); - pgAdmin.Dashboard.render_chart( - div_to, data_to, dataset_to, sid, did, - url_for('dashboard.to_stats'), options_line, true, - to_stats_refresh - ); - pgAdmin.Dashboard.render_chart( - div_bio, data_bio, dataset_bio, sid, did, - url_for('dashboard.bio_stats'), options_line, true, - bio_stats_refresh - ); - - // To align subnode controls properly - $(div_server_activity).addClass('pg-el-container'); - $(div_server_activity).attr('el', 'sm'); - - // Render the tabs, but only get data for the activity tab for now - pgAdmin.Dashboard.render_grid( - div_server_activity, sid, did, - url_for('dashboard.activity'), server_activity_columns - ); - pgAdmin.Dashboard.render_grid( - div_server_locks, sid, did, url_for('dashboard.locks'), - server_locks_columns - ); - pgAdmin.Dashboard.render_grid( - div_server_prepared, sid, did, url_for('dashboard.prepared'), - server_prepared_columns - ); - pgAdmin.Dashboard.render_grid( - div_server_config, sid, did, url_for('dashboard.config'), - server_config_columns - ); - - pgAdmin.Dashboard.render_grid_data(div_server_activity); - - // (Re)render the appropriate tab - $('a[data-toggle="tab"]').on('shown.bs.tab', function(e) { - switch ($(e.target).attr('aria-controls')) { - case 'tab_server_activity': - pgAdmin.Dashboard.render_grid_data(div_server_activity); - break; - - case 'tab_server_locks': - pgAdmin.Dashboard.render_grid_data(div_server_locks); - break; - - case 'tab_server_prepared': - pgAdmin.Dashboard.render_grid_data(div_server_prepared); - break; - - case 'tab_server_config': - pgAdmin.Dashboard.render_grid_data(div_server_config); - break; + if (version < 90600) { + server_activity_columns = server_activity_columns.concat( + [{ + name: 'waiting', + label: gettext('Waiting?'), + editable: false, + cell: 'string', + }]); + } else { + server_activity_columns = server_activity_columns.concat( + [{ + name: 'wait_event', + label: gettext('Wait Event'), + editable: false, + cell: 'string', + }, { + name: 'blocking_pids', + label: gettext('Blocking PIDs'), + editable: false, + cell: 'string', + }]); } - }); - // Handle button clicks - $('button').click(function() { - switch (this.id) { - case 'btn_server_activity_refresh': - pgAdmin.Dashboard.render_grid_data(div_server_activity); - break; + var newActiveQueryDetailsModel = new ActiveQueryDetailsModel(); - case 'btn_server_locks_refresh': - pgAdmin.Dashboard.render_grid_data(div_server_locks); - break; + var subNodeFieldsModel = Backform.generateViewSchema( + null, newActiveQueryDetailsModel, 'create', null, null, true + ); - case 'btn_server_prepared_refresh': - pgAdmin.Dashboard.render_grid_data(div_server_prepared); - break; + // Add version to each field + _.each(subNodeFieldsModel[0].fields, function(obj) { + obj['version'] = version; + }); - case 'btn_server_config_refresh': - pgAdmin.Dashboard.render_grid_data(div_server_config); - break; - } - }); + // Add cancel active query button + server_activity_columns.unshift({ + name: 'pg-backform-expand', + label: '', + cell: SessionDetailsCell, + cell_priority: -1, + postgres_version: version, + schema: subNodeFieldsModel, + }); + // Add cancel active query button + server_activity_columns.unshift({ + name: 'pg-backform-delete', + label: '', + cell: customDashboardActionCell, + cell_action: 'cancel', + editable: false, + cell_priority: -1, + canDeleteRow: pgAdmin.Dashboard.can_take_action, + postgres_version: version, + }); + + server_activity_columns.unshift({ + name: 'pg-backform-delete', + label: '', + cell: customDashboardActionCell, + cell_action: 'terminate', + editable: false, + cell_priority: -1, + canDeleteRow: pgAdmin.Dashboard.can_take_action, + postgres_version: version, + }); + + var server_locks_columns = [{ + name: 'pid', + label: gettext('PID'), + editable: false, + cell: 'string', + }, { + name: 'datname', + label: gettext('Database'), + editable: false, + cell: 'string', + }, { + name: 'locktype', + label: gettext('Lock type'), + editable: false, + cell: 'string', + }, { + name: 'relation', + label: gettext('Target relation'), + editable: false, + cell: 'string', + }, { + name: 'page', + label: gettext('Page'), + editable: false, + cell: 'string', + }, { + name: 'tuple', + label: gettext('Tuple'), + editable: false, + cell: 'string', + }, { + name: 'virtualxid', + label: gettext('vXID (target)'), + editable: false, + cell: 'string', + }, { + name: 'transactionid', + label: gettext('XID (target)'), + editable: false, + cell: 'string', + }, { + name: 'classid', + label: gettext('Class'), + editable: false, + cell: 'string', + }, { + name: 'objid', + label: gettext('Object ID'), + editable: false, + cell: 'string', + }, { + name: 'virtualtransaction', + label: gettext('vXID (owner)'), + editable: false, + cell: 'string', + }, { + name: 'mode', + label: gettext('Mode'), + editable: false, + cell: 'string', + }, { + name: 'granted', + label: gettext('Granted?'), + editable: false, + cell: 'string', + }]; + + var server_prepared_columns = [{ + name: 'git', + label: gettext('Name'), + editable: false, + cell: 'string', + }, { + name: 'database', + label: gettext('Database'), + editable: false, + cell: 'string', + }, { + name: 'Owner', + label: gettext('Owner'), + editable: false, + cell: 'string', + }, { + name: 'transaction', + label: gettext('XID'), + editable: false, + cell: 'string', + }, { + name: 'prepared', + label: gettext('Prepared at'), + editable: false, + cell: 'string', + }]; + + var server_config_columns = [{ + name: 'name', + label: gettext('Name'), + editable: false, + cell: 'string', + }, { + name: 'category', + label: gettext('Category'), + editable: false, + cell: 'string', + }, { + name: 'setting', + label: gettext('Setting'), + editable: false, + cell: 'string', + }, { + name: 'unit', + label: gettext('Unit'), + editable: false, + cell: 'string', + }, { + name: 'short_desc', + label: gettext('Description'), + editable: false, + cell: 'string', + }]; + + // To align subnode controls properly + $(div_server_activity).addClass('pg-el-container'); + $(div_server_activity).attr('el', 'sm'); + + // Render the tabs, but only get data for the activity tab for now + pgAdmin.Dashboard.render_grid( + div_server_activity, sid, did, + url_for('dashboard.activity'), server_activity_columns + ); + pgAdmin.Dashboard.render_grid( + div_server_locks, sid, did, url_for('dashboard.locks'), + server_locks_columns + ); + pgAdmin.Dashboard.render_grid( + div_server_prepared, sid, did, url_for('dashboard.prepared'), + server_prepared_columns + ); + pgAdmin.Dashboard.render_grid( + div_server_config, sid, did, url_for('dashboard.config'), + server_config_columns + ); + + pgAdmin.Dashboard.render_grid_data(div_server_activity); + + // (Re)render the appropriate tab + $('a[data-toggle="tab"]').on('shown.bs.tab', function(e) { + switch ($(e.target).attr('aria-controls')) { + case 'tab_server_activity': + pgAdmin.Dashboard.render_grid_data(div_server_activity); + break; + + case 'tab_server_locks': + pgAdmin.Dashboard.render_grid_data(div_server_locks); + break; + + case 'tab_server_prepared': + pgAdmin.Dashboard.render_grid_data(div_server_prepared); + break; + + case 'tab_server_config': + pgAdmin.Dashboard.render_grid_data(div_server_config); + break; + } + }); + + // Handle button clicks + $('button').click(function() { + switch (this.id) { + case 'btn_server_activity_refresh': + pgAdmin.Dashboard.render_grid_data(div_server_activity); + break; + + case 'btn_server_locks_refresh': + pgAdmin.Dashboard.render_grid_data(div_server_locks); + break; + + case 'btn_server_prepared_refresh': + pgAdmin.Dashboard.render_grid_data(div_server_prepared); + break; + + case 'btn_server_config_refresh': + pgAdmin.Dashboard.render_grid_data(div_server_config); + break; + } + }); + } }, // Rock n' roll on the database dashboard - init_database_dashboard: function(sid, did, version, session_stats_refresh, tps_stats_refresh, ti_stats_refresh, to_stats_refresh, bio_stats_refresh) { + init_database_dashboard: function( + sid, + did, + version, + session_stats_refresh, + tps_stats_refresh, + ti_stats_refresh, + to_stats_refresh, + bio_stats_refresh, + show_graphs, + show_database_activity + ) { var div_sessions = document.getElementById('graph-sessions'); var div_tps = document.getElementById('graph-tps'); var div_ti = document.getElementById('graph-ti'); @@ -1006,269 +1032,273 @@ define('pgadmin.dashboard', [ }, }; - var database_activity_columns = [{ - name: 'pid', - label: gettext('PID'), - editable: false, - cell: 'string', - }, { - name: 'usename', - label: gettext('User'), - editable: false, - cell: 'string', - }, { - name: 'application_name', - label: gettext('Application'), - editable: false, - cell: 'string', - }, { - name: 'client_addr', - label: gettext('Client'), - editable: false, - cell: 'string', - }, { - name: 'backend_start', - label: gettext('Backend start'), - editable: false, - cell: 'string', - }, { - name: 'state', - label: gettext('State'), - editable: false, - cell: 'string', - }]; - - if (version < 90600) { - database_activity_columns = database_activity_columns.concat( - [{ - name: 'waiting', - label: gettext('Waiting?'), - editable: false, - cell: 'string', - }]); - } else { - database_activity_columns = database_activity_columns.concat( - [{ - name: 'wait_event', - label: gettext('Wait Event'), - editable: false, - cell: 'string', - }, { - name: 'blocking_pids', - label: gettext('Blocking PIDs'), - editable: false, - cell: 'string', - }]); + // Display graphs + if(show_graphs) { + // Render the graphs + pgAdmin.Dashboard.render_chart( + div_sessions, data_sessions, dataset_sessions, sid, did, + url_for('dashboard.session_stats'), options_line, false, + session_stats_refresh + ); + pgAdmin.Dashboard.render_chart( + div_tps, data_tps, dataset_tps, sid, did, + url_for('dashboard.tps_stats'), options_line, true, + tps_stats_refresh + ); + pgAdmin.Dashboard.render_chart( + div_ti, data_ti, dataset_ti, sid, did, + url_for('dashboard.ti_stats'), options_line, true, + ti_stats_refresh + ); + pgAdmin.Dashboard.render_chart( + div_to, data_to, dataset_to, sid, did, + url_for('dashboard.to_stats'), options_line, true, + to_stats_refresh + ); + pgAdmin.Dashboard.render_chart( + div_bio, data_bio, dataset_bio, sid, did, + url_for('dashboard.bio_stats'), options_line, true, + bio_stats_refresh + ); } - var newActiveQueryDetailsModel = new ActiveQueryDetailsModel(); + // Display server activity + if (show_database_activity) { + var database_activity_columns = [{ + name: 'pid', + label: gettext('PID'), + editable: false, + cell: 'string', + }, { + name: 'usename', + label: gettext('User'), + editable: false, + cell: 'string', + }, { + name: 'application_name', + label: gettext('Application'), + editable: false, + cell: 'string', + }, { + name: 'client_addr', + label: gettext('Client'), + editable: false, + cell: 'string', + }, { + name: 'backend_start', + label: gettext('Backend start'), + editable: false, + cell: 'string', + }, { + name: 'state', + label: gettext('State'), + editable: false, + cell: 'string', + }]; - var subNodeFieldsModel = Backform.generateViewSchema( - null, newActiveQueryDetailsModel, 'create', null, null, true - ); - - // Add version to each field - _.each(subNodeFieldsModel[0].fields, function(obj) { - obj['version'] = version; - }); - - - // Add cancel active query button - database_activity_columns.unshift({ - name: 'pg-backform-expand', - label: '', - cell: SessionDetailsCell, - cell_priority: -1, - postgres_version: version, - schema: subNodeFieldsModel, - }); - - database_activity_columns.unshift({ - name: 'pg-backform-delete', - label: '', - cell: customDashboardActionCell, - cell_action: 'cancel', - editable: false, - cell_priority: -1, - canDeleteRow: pgAdmin.Dashboard.can_take_action, - postgres_version: version, - }); - database_activity_columns.unshift({ - name: 'pg-backform-delete', - label: '', - cell: customDashboardActionCell, - cell_action: 'terminate', - editable: false, - cell_priority: -1, - canDeleteRow: pgAdmin.Dashboard.can_take_action, - postgres_version: version, - }); - - var database_locks_columns = [{ - name: 'pid', - label: gettext('PID'), - editable: false, - cell: 'string', - }, { - name: 'locktype', - label: gettext('Lock type'), - editable: false, - cell: 'string', - }, { - name: 'relation', - label: gettext('Target relation'), - editable: false, - cell: 'string', - }, { - name: 'page', - label: gettext('Page'), - editable: false, - cell: 'string', - }, { - name: 'tuple', - label: gettext('Tuple'), - editable: false, - cell: 'string', - }, { - name: 'virtualxid', - label: gettext('vXID (target)'), - editable: false, - cell: 'string', - }, { - name: 'transactionid', - label: gettext('XID (target)'), - editable: false, - cell: 'string', - }, { - name: 'classid', - label: gettext('Class'), - editable: false, - cell: 'string', - }, { - name: 'objid', - label: gettext('Object ID'), - editable: false, - cell: 'string', - }, { - name: 'virtualtransaction', - label: gettext('vXID (owner)'), - editable: false, - cell: 'string', - }, { - name: 'mode', - label: gettext('Mode'), - editable: false, - cell: 'string', - }, { - name: 'granted', - label: gettext('Granted?'), - editable: false, - cell: 'string', - }]; - - var database_prepared_columns = [{ - name: 'git', - label: gettext('Name'), - editable: false, - cell: 'string', - }, { - name: 'Owner', - label: gettext('Owner'), - editable: false, - cell: 'string', - }, { - name: 'transaction', - label: gettext('XID'), - editable: false, - cell: 'string', - }, { - name: 'prepared', - label: gettext('Prepared at'), - editable: false, - cell: 'string', - }]; - - // Render the graphs - pgAdmin.Dashboard.render_chart( - div_sessions, data_sessions, dataset_sessions, sid, did, - url_for('dashboard.session_stats'), options_line, false, - session_stats_refresh - ); - pgAdmin.Dashboard.render_chart( - div_tps, data_tps, dataset_tps, sid, did, - url_for('dashboard.tps_stats'), options_line, true, - tps_stats_refresh - ); - pgAdmin.Dashboard.render_chart( - div_ti, data_ti, dataset_ti, sid, did, - url_for('dashboard.ti_stats'), options_line, true, - ti_stats_refresh - ); - pgAdmin.Dashboard.render_chart( - div_to, data_to, dataset_to, sid, did, - url_for('dashboard.to_stats'), options_line, true, - to_stats_refresh - ); - pgAdmin.Dashboard.render_chart( - div_bio, data_bio, dataset_bio, sid, did, - url_for('dashboard.bio_stats'), options_line, true, - bio_stats_refresh - ); - - // To align subnode controls properly - $(div_database_activity).addClass('pg-el-container'); - $(div_database_activity).attr('el', 'sm'); - - // Render the tabs, but only get data for the activity tab for now - pgAdmin.Dashboard.render_grid( - div_database_activity, sid, did, url_for('dashboard.activity'), - database_activity_columns - ); - pgAdmin.Dashboard.render_grid( - div_database_locks, sid, did, url_for('dashboard.locks'), - database_locks_columns - ); - pgAdmin.Dashboard.render_grid( - div_database_prepared, sid, did, url_for('dashboard.prepared'), - database_prepared_columns - ); - - pgAdmin.Dashboard.render_grid_data(div_database_activity); - - // (Re)render the appropriate tab - $('a[data-toggle="tab"]').on('shown.bs.tab', function(e) { - switch ($(e.target).attr('aria-controls')) { - case 'tab_database_activity': - pgAdmin.Dashboard.render_grid_data(div_database_activity); - break; - - case 'tab_database_locks': - pgAdmin.Dashboard.render_grid_data(div_database_locks); - break; - - case 'tab_database_prepared': - pgAdmin.Dashboard.render_grid_data(div_database_prepared); - break; + if (version < 90600) { + database_activity_columns = database_activity_columns.concat( + [{ + name: 'waiting', + label: gettext('Waiting?'), + editable: false, + cell: 'string', + }]); + } else { + database_activity_columns = database_activity_columns.concat( + [{ + name: 'wait_event', + label: gettext('Wait Event'), + editable: false, + cell: 'string', + }, { + name: 'blocking_pids', + label: gettext('Blocking PIDs'), + editable: false, + cell: 'string', + }]); } - }); - // Handle button clicks - $('button').click(function() { - switch (this.id) { - case 'btn_database_activity_refresh': - pgAdmin.Dashboard.render_grid_data(div_database_activity); - break; + var newActiveQueryDetailsModel = new ActiveQueryDetailsModel(); - case 'btn_database_locks_refresh': - pgAdmin.Dashboard.render_grid_data(div_database_locks); - break; + var subNodeFieldsModel = Backform.generateViewSchema( + null, newActiveQueryDetailsModel, 'create', null, null, true + ); - case 'btn_database_prepared_refresh': - pgAdmin.Dashboard.render_grid_data(div_database_prepared); - break; - } - }); + // Add version to each field + _.each(subNodeFieldsModel[0].fields, function(obj) { + obj['version'] = version; + }); + // Add cancel active query button + database_activity_columns.unshift({ + name: 'pg-backform-expand', + label: '', + cell: SessionDetailsCell, + cell_priority: -1, + postgres_version: version, + schema: subNodeFieldsModel, + }); + + database_activity_columns.unshift({ + name: 'pg-backform-delete', + label: '', + cell: customDashboardActionCell, + cell_action: 'cancel', + editable: false, + cell_priority: -1, + canDeleteRow: pgAdmin.Dashboard.can_take_action, + postgres_version: version, + }); + database_activity_columns.unshift({ + name: 'pg-backform-delete', + label: '', + cell: customDashboardActionCell, + cell_action: 'terminate', + editable: false, + cell_priority: -1, + canDeleteRow: pgAdmin.Dashboard.can_take_action, + postgres_version: version, + }); + + var database_locks_columns = [{ + name: 'pid', + label: gettext('PID'), + editable: false, + cell: 'string', + }, { + name: 'locktype', + label: gettext('Lock type'), + editable: false, + cell: 'string', + }, { + name: 'relation', + label: gettext('Target relation'), + editable: false, + cell: 'string', + }, { + name: 'page', + label: gettext('Page'), + editable: false, + cell: 'string', + }, { + name: 'tuple', + label: gettext('Tuple'), + editable: false, + cell: 'string', + }, { + name: 'virtualxid', + label: gettext('vXID (target)'), + editable: false, + cell: 'string', + }, { + name: 'transactionid', + label: gettext('XID (target)'), + editable: false, + cell: 'string', + }, { + name: 'classid', + label: gettext('Class'), + editable: false, + cell: 'string', + }, { + name: 'objid', + label: gettext('Object ID'), + editable: false, + cell: 'string', + }, { + name: 'virtualtransaction', + label: gettext('vXID (owner)'), + editable: false, + cell: 'string', + }, { + name: 'mode', + label: gettext('Mode'), + editable: false, + cell: 'string', + }, { + name: 'granted', + label: gettext('Granted?'), + editable: false, + cell: 'string', + }]; + + var database_prepared_columns = [{ + name: 'git', + label: gettext('Name'), + editable: false, + cell: 'string', + }, { + name: 'Owner', + label: gettext('Owner'), + editable: false, + cell: 'string', + }, { + name: 'transaction', + label: gettext('XID'), + editable: false, + cell: 'string', + }, { + name: 'prepared', + label: gettext('Prepared at'), + editable: false, + cell: 'string', + }]; + + // To align subnode controls properly + $(div_database_activity).addClass('pg-el-container'); + $(div_database_activity).attr('el', 'sm'); + + // Render the tabs, but only get data for the activity tab for now + pgAdmin.Dashboard.render_grid( + div_database_activity, sid, did, url_for('dashboard.activity'), + database_activity_columns + ); + pgAdmin.Dashboard.render_grid( + div_database_locks, sid, did, url_for('dashboard.locks'), + database_locks_columns + ); + pgAdmin.Dashboard.render_grid( + div_database_prepared, sid, did, url_for('dashboard.prepared'), + database_prepared_columns + ); + + pgAdmin.Dashboard.render_grid_data(div_database_activity); + + // (Re)render the appropriate tab + $('a[data-toggle="tab"]').on('shown.bs.tab', function(e) { + switch ($(e.target).attr('aria-controls')) { + case 'tab_database_activity': + pgAdmin.Dashboard.render_grid_data(div_database_activity); + break; + + case 'tab_database_locks': + pgAdmin.Dashboard.render_grid_data(div_database_locks); + break; + + case 'tab_database_prepared': + pgAdmin.Dashboard.render_grid_data(div_database_prepared); + break; + } + }); + + // Handle button clicks + $('button').click(function() { + switch (this.id) { + case 'btn_database_activity_refresh': + pgAdmin.Dashboard.render_grid_data(div_database_activity); + break; + + case 'btn_database_locks_refresh': + pgAdmin.Dashboard.render_grid_data(div_database_locks); + break; + + case 'btn_database_prepared_refresh': + pgAdmin.Dashboard.render_grid_data(div_database_prepared); + break; + } + }); + } }, toggleVisibility: function(flag) { dashboardVisible = flag; diff --git a/web/pgadmin/dashboard/templates/dashboard/database_dashboard.html b/web/pgadmin/dashboard/templates/dashboard/database_dashboard.html index 6c3c8c278..37ff5b97a 100644 --- a/web/pgadmin/dashboard/templates/dashboard/database_dashboard.html +++ b/web/pgadmin/dashboard/templates/dashboard/database_dashboard.html @@ -1,4 +1,5 @@
+{% if settings.show_graphs %}
@@ -49,8 +50,14 @@
- +{% endif %} +{% if settings.show_activity %} + {# If we are displaying graphs then only we need space on top #} + {% if settings.show_graphs %}
+ {% else %} +
+ {% endif %}
{{ _('Database activity') }} @@ -101,9 +108,28 @@
+{% endif %} + +{% if not settings.show_graphs and not settings.show_activity %} + +{% endif %} +
diff --git a/web/pgadmin/dashboard/templates/dashboard/server_dashboard.html b/web/pgadmin/dashboard/templates/dashboard/server_dashboard.html index 5b217d4fc..b3578253d 100644 --- a/web/pgadmin/dashboard/templates/dashboard/server_dashboard.html +++ b/web/pgadmin/dashboard/templates/dashboard/server_dashboard.html @@ -1,4 +1,5 @@
+{% if settings.show_graphs %}
@@ -49,8 +50,14 @@
- +{% endif %} +{% if settings.show_activity %} + {# If we are displaying graphs then only we need space on top #} + {% if settings.show_graphs %}
+ {% else %} +
+ {% endif %}
{{ _('Server activity') }} @@ -111,9 +118,27 @@
+{% endif %} + +{% if not settings.show_graphs and not settings.show_activity %} + +{% endif %} +
diff --git a/web/pgadmin/dashboard/tests/__init__.py b/web/pgadmin/dashboard/tests/__init__.py new file mode 100644 index 000000000..590026ad4 --- /dev/null +++ b/web/pgadmin/dashboard/tests/__init__.py @@ -0,0 +1,8 @@ +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2018, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## diff --git a/web/pgadmin/dashboard/tests/test_dashboard_templates.py b/web/pgadmin/dashboard/tests/test_dashboard_templates.py new file mode 100644 index 000000000..205e50b62 --- /dev/null +++ b/web/pgadmin/dashboard/tests/test_dashboard_templates.py @@ -0,0 +1,279 @@ +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2018, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## + +import os +import sys +from flask import Flask, render_template +from jinja2 import FileSystemLoader +from pgadmin import VersionedTemplateLoader +from pgadmin.utils.route import BaseTestGenerator + +if sys.version_info < (3, 3): + from mock import MagicMock +else: + from unittest.mock import MagicMock + +# Hard coded dummy input parameters for the templates +RATES = { + 'session_stats_refresh': 1, + 'tps_stats_refresh': 1, + 'ti_stats_refresh': 1, + 'to_stats_refresh': 1, + 'bio_stats_refresh': 1 +} + +DISPLAY_DASHBOARD = { + 'both': { + 'show_graphs': True, + 'show_activity': True + }, + + 'only_graphs': { + 'show_graphs': True, + 'show_activity': False + }, + + 'only_server_activity': { + 'show_graphs': False, + 'show_activity': True + }, + + 'none': { + 'show_graphs': False, + 'show_activity': False + } +} + +VERSION = 95000 + +SERVER_ID = 1 + +DATABASE_ID = 123 + + +# To moke gettext function used in the template +_ = MagicMock(side_effect=lambda x: x) + + +class TestExplainPlanTemplates(BaseTestGenerator): + scenarios = [ + # Server dashboard + ( + 'Dashboard, when returning the html page with graphs and ' + 'server activity related html elements for server dashboard', + dict( + template_path=os.path.join( + 'dashboard', 'server_dashboard.html' + ), + input_parameters=dict( + sid=SERVER_ID, + did=None, + rates=RATES, + version=VERSION, + settings=DISPLAY_DASHBOARD['both'], + _=_ + ), + expected_return_value=[ + 'Server sessions', + 'Server activity' + ], + not_expected_return_value=[] + ) + ), + ( + 'Dashboard, when returning the html page with only graphs ' + 'related html elements for server dashboard', + dict( + template_path=os.path.join( + 'dashboard', 'server_dashboard.html' + ), + input_parameters=dict( + sid=SERVER_ID, + did=None, + rates=RATES, + version=VERSION, + settings=DISPLAY_DASHBOARD['only_graphs'], + _=_ + ), + expected_return_value=[ + 'Server sessions' + ], + not_expected_return_value=[ + 'Server activity' + ] + ) + ), + ( + 'Dashboard, when returning the html page with only server ' + 'activity related html elements for server dashboard', + dict( + template_path=os.path.join( + 'dashboard', 'server_dashboard.html' + ), + input_parameters=dict( + sid=SERVER_ID, + did=None, + rates=RATES, + version=VERSION, + settings=DISPLAY_DASHBOARD['only_server_activity'], + _=_ + ), + expected_return_value=[ + 'Server activity' + ], + not_expected_return_value=[ + 'Server sessions' + ] + ) + ), + ( + 'Dashboard, when returning the html page with neither ' + 'graphs nor server activity related html elements for server ' + 'dashboard', + dict( + template_path=os.path.join( + 'dashboard', 'server_dashboard.html' + ), + input_parameters=dict( + sid=SERVER_ID, + did=None, + rates=RATES, + version=VERSION, + settings=DISPLAY_DASHBOARD['none'], + _=_ + ), + expected_return_value=[], + not_expected_return_value=[ + 'Server activity', + 'Server sessions' + ] + ) + ), + # Database dashboard + ( + 'Dashboard, when returning the html page with graphs and ' + 'database activity related html elements for database dashboard', + dict( + template_path=os.path.join( + 'dashboard', 'database_dashboard.html' + ), + input_parameters=dict( + sid=SERVER_ID, + did=DATABASE_ID, + rates=RATES, + version=VERSION, + settings=DISPLAY_DASHBOARD['both'], + _=_ + ), + expected_return_value=[ + 'Database sessions', + 'Database activity' + ], + not_expected_return_value=[] + ) + ), + ( + 'Dashboard, when returning the html page with only ' + 'graphs related html elements for database dashboard', + dict( + template_path=os.path.join( + 'dashboard', 'database_dashboard.html' + ), + input_parameters=dict( + sid=SERVER_ID, + did=DATABASE_ID, + rates=RATES, + version=VERSION, + settings=DISPLAY_DASHBOARD['only_graphs'], + _=_ + ), + expected_return_value=[ + 'Database sessions' + ], + not_expected_return_value=[ + 'Database activity' + ] + ) + ), + ( + 'Dashboard, when returning the html page with only ' + 'database activity related html elements for database dashboard', + dict( + template_path=os.path.join( + 'dashboard', 'database_dashboard.html' + ), + input_parameters=dict( + sid=SERVER_ID, + did=DATABASE_ID, + rates=RATES, + version=VERSION, + settings=DISPLAY_DASHBOARD['only_server_activity'], + _=_ + ), + expected_return_value=[ + 'Database activity' + ], + not_expected_return_value=[ + 'Database sessions' + ] + ) + ), + ( + 'Dashboard, when returning the html page with neither ' + 'graphs nor database activity related html elements for database ' + 'dashboard', + dict( + template_path=os.path.join( + 'dashboard', 'database_dashboard.html' + ), + input_parameters=dict( + sid=SERVER_ID, + did=DATABASE_ID, + rates=RATES, + version=VERSION, + settings=DISPLAY_DASHBOARD['none'], + _=_ + ), + expected_return_value=[], + not_expected_return_value=[ + 'Database sessions', + 'Database activity' + ] + ) + ), + + ] + + def setUp(self): + self.loader = VersionedTemplateLoader(FakeApp()) + + def runTest(self): + with FakeApp().app_context(): + result = render_template( + self.template_path, **self.input_parameters + ) + # checks for expected html elements + for expected_string in self.expected_return_value: + self.assertIn( + expected_string, result + ) + + # checks for not expected html elements + for not_expected_string in self.not_expected_return_value: + self.assertNotIn( + not_expected_string, result + ) + + +class FakeApp(Flask): + def __init__(self): + super(FakeApp, self).__init__("") + self.jinja_loader = FileSystemLoader( + os.path.dirname(os.path.realpath(__file__)) + "/../templates" + )