diff --git a/docs/en_US/release_notes_3_2.rst b/docs/en_US/release_notes_3_2.rst index 09f0364dc..762c4613c 100644 --- a/docs/en_US/release_notes_3_2.rst +++ b/docs/en_US/release_notes_3_2.rst @@ -21,7 +21,7 @@ Bug fixes | `Bug #3185 `_ - Fix the upgrade check on macOS. | `Bug #3191 `_ - Fix a number of debugger execution issues. -| `Bug #3294 `_ - Infrastructure (and changes to the Query Tool) for realtime preference handling. +| `Bug #3294 `_ - Infrastructure (and changes to the Query Tool, Dashboards and Debugger) for realtime preference handling. | `Bug #3309 `_ - Fix Directory format support for backups. | `Bug #3316 `_ - Support running on systems without a system tray. | `Bug #3319 `_ - Cleanup and fix handling of Query Tool Cancel button status. diff --git a/web/pgadmin/browser/static/js/panel.js b/web/pgadmin/browser/static/js/panel.js index ab0681a96..5238dcee0 100644 --- a/web/pgadmin/browser/static/js/panel.js +++ b/web/pgadmin/browser/static/js/panel.js @@ -170,10 +170,9 @@ define( if (pgBrowser.tree) { pgBrowser.save_current_layout(pgBrowser); var selectedNode = pgBrowser.tree.selected(); - // Discontinue this event after first time visible - this.off(wcDocker.EVENT.VISIBILITY_CHANGED); - if (!_.isUndefined(pgAdmin.Dashboard)) - pgAdmin.Dashboard.toggleVisibility(true); + if (!_.isUndefined(pgAdmin.Dashboard)) { + pgAdmin.Dashboard.toggleVisibility(pgBrowser.panels.dashboard.panel.isVisible()); + } // Explicitly trigger tree selected event when we add the tab. pgBrowser.Events.trigger('pgadmin-browser:tree:selected', selectedNode, pgBrowser.tree.itemData(selectedNode), pgBrowser.Node); diff --git a/web/pgadmin/dashboard/__init__.py b/web/pgadmin/dashboard/__init__.py index 91162f76b..ffd4a7bc5 100644 --- a/web/pgadmin/dashboard/__init__.py +++ b/web/pgadmin/dashboard/__init__.py @@ -280,8 +280,6 @@ def index(sid=None, did=None): rates = {} settings = {} - prefs = Preferences.module('dashboards') - # Get the server version if sid is not None: g.manager = get_driver( @@ -293,22 +291,6 @@ def index(sid=None, did=None): if not g.conn.connected(): g.version = 0 - session_stats_refresh_pref = prefs.preference('session_stats_refresh') - rates['session_stats_refresh'] = session_stats_refresh_pref.get() - tps_stats_refresh_pref = prefs.preference('tps_stats_refresh') - rates['tps_stats_refresh'] = tps_stats_refresh_pref.get() - ti_stats_refresh_pref = prefs.preference('ti_stats_refresh') - rates['ti_stats_refresh'] = ti_stats_refresh_pref.get() - to_stats_refresh_pref = prefs.preference('to_stats_refresh') - 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: return render_template('/dashboard/welcome_dashboard.html') @@ -317,8 +299,7 @@ def index(sid=None, did=None): '/dashboard/server_dashboard.html', sid=sid, rates=rates, - version=g.version, - settings=settings + version=g.version ) else: return render_template( @@ -326,8 +307,7 @@ def index(sid=None, did=None): sid=sid, did=did, rates=rates, - version=g.version, - settings=settings + version=g.version ) diff --git a/web/pgadmin/dashboard/static/css/dashboard.css b/web/pgadmin/dashboard/static/css/dashboard.css index 2fc7897cb..61174f336 100644 --- a/web/pgadmin/dashboard/static/css/dashboard.css +++ b/web/pgadmin/dashboard/static/css/dashboard.css @@ -2,8 +2,8 @@ padding: 15px; } -.dashboard-header-spacer { - padding-top: 15px; +.dashboard-row { + margin-bottom: 15px; } .dashboard-link { @@ -175,4 +175,6 @@ margin-bottom: 0%; } -/* CSS to make subnode control look preety in backgrid - END */ +.dashboard-hidden { + display: none; +} diff --git a/web/pgadmin/dashboard/static/js/dashboard.js b/web/pgadmin/dashboard/static/js/dashboard.js index 02c7d439d..c411a84a2 100644 --- a/web/pgadmin/dashboard/static/js/dashboard.js +++ b/web/pgadmin/dashboard/static/js/dashboard.js @@ -192,6 +192,10 @@ define('pgadmin.dashboard', [ this.initialized = true; + this.sid = this.did = -1; + this.version = -1; + + // Bind the Dashboard object with the 'object_selected' function var selected = this.object_selected.bind(this); var disconnected = this.object_disconnected.bind(this); @@ -205,6 +209,11 @@ define('pgadmin.dashboard', [ // Load the default welcome dashboard var url = url_for('dashboard.index'); + /* Store the interval ids of the graph interval functions so that we can clear + * them when graphs are disabled + */ + this.intervalIds = {}; + var dashboardPanel = pgBrowser.panels['dashboard'].panel; if (dashboardPanel) { var div = dashboardPanel.layout().scene().find('.pg-panel-content'); @@ -238,14 +247,17 @@ define('pgadmin.dashboard', [ // Handle treeview clicks object_selected: function(item, itemData, node) { + let self = this; + /* Clear all the interval functions of previous dashboards */ + self.clearIntervalId(); if (itemData && itemData._type && dashboardVisible) { var treeHierarchy = node.getTreeNodeHierarchy(item), url = url_for('dashboard.index'), - sid = -1, - did = -1, b = pgAdmin.Browser, m = b && b.Nodes[itemData._type]; + self.sid = self.did = -1; + self.version = itemData.version; cancel_query_url = url_for('dashboard.index') + 'cancel_query/'; terminate_session_url = url_for('dashboard.index') + 'terminate_session/'; @@ -271,20 +283,21 @@ define('pgadmin.dashboard', [ } } else { if ('database' in treeHierarchy) { - sid = treeHierarchy.server._id; - did = treeHierarchy.database._id; + self.sid = treeHierarchy.server._id; + self.did = treeHierarchy.database._id; is_server_dashboard = false; is_database_dashboard = true; - url += sid + '/' + did; - cancel_query_url += sid + '/' + did + '/'; - terminate_session_url += sid + '/' + did + '/'; + url += self.sid + '/' + self.did; + cancel_query_url += self.sid + '/' + self.did + '/'; + terminate_session_url += self.sid + '/' + self.did + '/'; } else if ('server' in treeHierarchy) { - sid = treeHierarchy.server._id; + self.sid = treeHierarchy.server._id; + self.did = -1; is_server_dashboard = true; is_database_dashboard = false; - url += sid; - cancel_query_url += sid + '/'; - terminate_session_url += sid + '/'; + url += self.sid; + cancel_query_url += self.sid + '/'; + terminate_session_url += self.sid + '/'; } } @@ -299,7 +312,6 @@ define('pgadmin.dashboard', [ // Avoid unnecessary reloads if (url != $(dashboardPanel).data('dashboard_url') || (url == $(dashboardPanel).data('dashboard_url') && $(dashboardPanel).data('server_status') == false)) { - // Clear out everything so any existing timers die off $(div).empty(); $.ajax({ @@ -309,6 +321,7 @@ define('pgadmin.dashboard', [ }) .done(function(data) { $(div).html(data); + self.init_dashboard(); }) .fail(function() { $(div).html( @@ -317,7 +330,9 @@ define('pgadmin.dashboard', [ }); $(dashboardPanel).data('server_status', true); } - + else { + self.init_dashboard(); + } } else { $(div).empty(); $(div).html( @@ -327,102 +342,16 @@ define('pgadmin.dashboard', [ } // Cache the current IDs for next time $(dashboardPanel).data('dashboard_url', url); - } } } }, - // Render a chart - render_chart: function( - container, data, dataset, sid, did, url, options, counter, refresh - ) { + renderChartLoop: function(container, sid, did, url, options, counter, refresh) { + var data = [], + dataset = []; - // Data 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] } - // ] - - if (!dashboardVisible) - return; - - var y = 0, - x; - if (dataset.length == 0) { - if (counter == true) { - // Have we stashed initial values? - if (_.isUndefined($(container).data('counter_previous_vals'))) { - $(container).data('counter_previous_vals', data[0]); - } else { - // Create the initial data structure - for (x in data[0]) { - dataset.push({ - 'data': [ - [0, data[0][x] - $(container).data('counter_previous_vals')[x]], - ], - 'label': x, - }); - } - } - } else { - // Create the initial data structure - for (x in data[0]) { - dataset.push({ - 'data': [ - [0, data[0][x]], - ], - 'label': x, - }); - } - } - } else { - for (x in data[0]) { - // Push new values onto the existing data structure - // If this is a counter stat, we need to subtract the previous value - if (counter == false) { - dataset[y]['data'].unshift([0, data[0][x]]); - } 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($(container).data('counter_previous_vals'))) - return; - - dataset[y]['data'].unshift([0, data[0][x] - $(container).data('counter_previous_vals')[x]]); - } - - // Reset the time index to get a proper scrolling display - for (var z = 0; z < dataset[y]['data'].length; z++) { - dataset[y]['data'][z][0] = z; - } - - y++; - } - $(container).data('counter_previous_vals', data[0]); - } - - // Remove uneeded elements - for (x = 0; x < dataset.length; x++) { - // Remove old data points - if (dataset[x]['data'].length > 101) { - dataset[x]['data'].pop(); - } - } - - // Draw Graph, if the container still exists and has a size - var dashboardPanel = pgBrowser.panels['dashboard'].panel; - var div = dashboardPanel.layout().scene().find('.pg-panel-content'); - if ($(div).find(container).length) { // Exists? - if (container.clientHeight > 0 && container.clientWidth > 0) { // Not hidden? - Flotr.draw(container, dataset, options); - } - } else { - return; - } - - // Animate - var setTimeoutFunc = function() { + var theIntervalFunc = function() { var path = url + sid; if (did != -1) { path += '/' + did; @@ -435,7 +364,82 @@ define('pgadmin.dashboard', [ .done(function(resp) { $(container).removeClass('graph-error'); data = JSON.parse(resp); - pgAdmin.Dashboard.render_chart(container, data, dataset, sid, did, url, options, counter, refresh); + if (!dashboardVisible) + return; + + var y = 0, + x; + if (dataset.length == 0) { + if (counter == true) { + // Have we stashed initial values? + if (_.isUndefined($(container).data('counter_previous_vals'))) { + $(container).data('counter_previous_vals', data[0]); + } else { + // Create the initial data structure + for (x in data[0]) { + dataset.push({ + 'data': [ + [0, data[0][x] - $(container).data('counter_previous_vals')[x]], + ], + 'label': x, + }); + } + } + } else { + // Create the initial data structure + for (x in data[0]) { + dataset.push({ + 'data': [ + [0, data[0][x]], + ], + 'label': x, + }); + } + } + } else { + for (x in data[0]) { + // Push new values onto the existing data structure + // If this is a counter stat, we need to subtract the previous value + if (counter == false) { + dataset[y]['data'].unshift([0, data[0][x]]); + } 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($(container).data('counter_previous_vals'))) + return; + + dataset[y]['data'].unshift([0, data[0][x] - $(container).data('counter_previous_vals')[x]]); + } + + // Reset the time index to get a proper scrolling display + for (var z = 0; z < dataset[y]['data'].length; z++) { + dataset[y]['data'][z][0] = z; + } + + y++; + } + $(container).data('counter_previous_vals', data[0]); + } + + // Remove uneeded elements + for (x = 0; x < dataset.length; x++) { + // Remove old data points + if (dataset[x]['data'].length > 101) { + dataset[x]['data'].pop(); + } + } + + // Draw Graph, if the container still exists and has a size + var dashboardPanel = pgBrowser.panels['dashboard'].panel; + var div = dashboardPanel.layout().scene().find('.pg-panel-content'); + if ($(div).find(container).length) { // Exists? + if (container.clientHeight > 0 && container.clientWidth > 0) { // Not hidden? + Flotr.draw(container, dataset, options); + } + } else { + return; + } + }) .fail(function(xhr) { let err = ''; @@ -463,15 +467,36 @@ define('pgadmin.dashboard', [ $(container).html( '' ); - - // Try again... - if (container.clientHeight > 0 && container.clientWidth > 0) { - setTimeout(setTimeoutFunc, refresh * 1000); - } }); }; + /* Execute once for the first time as setInterval will not do */ + theIntervalFunc(); + return setInterval(theIntervalFunc, refresh * 1000); + }, - setTimeout(setTimeoutFunc, refresh * 1000); + // Render a chart + render_chart: function( + container, url, options, counter, chartName, prefName + ) { + + // Data 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 self = this; + if(self.intervalIds[chartName] + && self.old_preferences[prefName] != self.preferences[prefName]) { + self.clearIntervalId(chartName); + } + if(!self.intervalIds[chartName]) { + self.intervalIds[chartName] = self.renderChartLoop( + container, self.sid, self.did, url, + options, counter, self.preferences[prefName] + ); + } }, // Handler function to support the "Add Server" link @@ -503,12 +528,13 @@ define('pgadmin.dashboard', [ }, // Render a grid - render_grid: function(container, sid, did, url, columns) { - var Datum = Backbone.Model.extend({}); + render_grid: function(container, url, columns) { + var Datum = Backbone.Model.extend({}), + self = this; - var path = url + sid; - if (did != -1) { - path += '/' + did; + var path = url + self.sid; + if (self.did != -1) { + path += '/' + self.did; } var Data = Backbone.Collection.extend({ @@ -527,6 +553,7 @@ define('pgadmin.dashboard', [ }); // Render the grid + $(container).empty(); $(container).append(grid.render().el); // Initialize a client-side filter to filter on the client @@ -615,41 +642,59 @@ 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, - show_graphs, - show_server_activity - ) { + clearIntervalId: function(intervalId) { + var self = this; + if(!intervalId){ + _.each(self.intervalIds, function(id, key) { + clearInterval(id); + delete self.intervalIds[key]; + }); + } + else { + clearInterval(self.intervalIds[intervalId]); + delete self.intervalIds[intervalId]; + } + }, + + // Rock n' roll on the dashboard + init_dashboard: function() { + let self = this; + + if(self.sid === -1 && self.did === -1) { + return; + } + + /* Cache may take time to load for the first time + * Keep trying till available + */ + let cacheIntervalId = setInterval(function() { + try { + if(window.top.pgAdmin.Browser.preference_version() > 0) { + clearInterval(cacheIntervalId); + self.reflectPreferences(); + } + } + catch(err) { + clearInterval(cacheIntervalId); + throw err; + } + },0); + + /* Register for preference changed event broadcasted */ + pgBrowser.onPreferencesChange('dashboards', function() { + self.reflectPreferences(); + }); + + }, + + reflectPreferences: function() { + /* Common things can come here */ + var self = this; 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 div_server_activity = $('.dashboard-container').find('#server_activity'); - var div_server_locks = $('.dashboard-container').find('#server_locks'); - var div_server_prepared = $('.dashboard-container').find('#server_prepared'); - var div_server_config = $('.dashboard-container').find('#server_config'); - var dataset_sessions = []; - var data_sessions = []; - var dataset_tps = []; - var data_tps = []; - var dataset_ti = []; - var data_ti = []; - var dataset_to = []; - var data_to = []; - var dataset_bio = []; - var data_bio = []; - - // Fake DB ID - var did = -1; - var options_line = { parseFloat: false, xaxis: { @@ -664,40 +709,85 @@ define('pgadmin.dashboard', [ position: 'nw', backgroundColor: '#D2E8FF', }, + shadowSize: 0, + resolution : 5, }; - // Display graphs - if(show_graphs) { + /* We will use old preferences for selective graph updates on preference change */ + if(self.preferences) { + self.old_preferences = self.preferences; + self.preferences = window.top.pgAdmin.Browser.get_preferences_for_module('dashboards'); + } + else { + self.preferences = window.top.pgAdmin.Browser.get_preferences_for_module('dashboards'); + self.old_preferences = self.preferences; + } + + 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.clearIntervalId(); + } + + if (self.preferences.show_activity && $('#dashboard-activity').hasClass('dashboard-hidden')) { + $('#dashboard-activity').removeClass('dashboard-hidden'); + } + else if(!self.preferences.show_activity) { + $('#dashboard-activity').addClass('dashboard-hidden'); + } + + if(self.preferences.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 + div_sessions, url_for('dashboard.session_stats'), options_line, false, + 'session_stats', '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 + div_tps, url_for('dashboard.tps_stats'), options_line, true, + 'tps_stats','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 + div_ti, url_for('dashboard.ti_stats'), options_line, true, + 'ti_stats', '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 + div_to, url_for('dashboard.to_stats'), options_line, true, + 'to_stats','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 + div_bio, url_for('dashboard.bio_stats'), options_line, true, + 'bio_stats','bio_stats_refresh' ); } + /* Dashboard specific preferences can be updated in the + * appropriate functions + */ + if(is_server_dashboard) { + self.reflectPreferencesServer(); + } + else if(is_database_dashboard) { + self.reflectPreferencesDatabase(); + } + + if(!self.preferences.show_graphs && !self.preferences.show_activity) { + $('#dashboard-none-show').removeClass('dashboard-hidden'); + } + else { + $('#dashboard-none-show').addClass('dashboard-hidden'); + } + }, + reflectPreferencesServer: function() { + var self = this; + var div_server_activity = $('.dashboard-container').find('#server_activity'); + var div_server_locks = $('.dashboard-container').find('#server_locks'); + var div_server_prepared = $('.dashboard-container').find('#server_prepared'); + var div_server_config = $('.dashboard-container').find('#server_config'); + // Display server activity - if (show_server_activity) { + if (self.preferences.show_activity) { var server_activity_columns = [{ name: 'pid', label: gettext('PID'), @@ -735,7 +825,7 @@ define('pgadmin.dashboard', [ cell: 'string', }]; - if (version < 90600) { + if (self.version < 90600) { server_activity_columns = server_activity_columns.concat( [{ name: 'waiting', @@ -766,7 +856,7 @@ define('pgadmin.dashboard', [ // Add version to each field _.each(subNodeFieldsModel[0].fields, function(obj) { - obj['version'] = version; + obj['version'] = self.version; }); // Add cancel active query button @@ -775,7 +865,7 @@ define('pgadmin.dashboard', [ label: '', cell: SessionDetailsCell, cell_priority: -1, - postgres_version: version, + postgres_version: self.version, schema: subNodeFieldsModel, }); @@ -788,7 +878,7 @@ define('pgadmin.dashboard', [ editable: false, cell_priority: -1, canDeleteRow: pgAdmin.Dashboard.can_take_action, - postgres_version: version, + postgres_version: self.version, }); server_activity_columns.unshift({ @@ -799,7 +889,7 @@ define('pgadmin.dashboard', [ editable: false, cell_priority: -1, canDeleteRow: pgAdmin.Dashboard.can_take_action, - postgres_version: version, + postgres_version: self.version, }); var server_locks_columns = [{ @@ -929,20 +1019,16 @@ define('pgadmin.dashboard', [ // 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 + div_server_activity, url_for('dashboard.activity'), server_activity_columns ); pgAdmin.Dashboard.render_grid( - div_server_locks, sid, did, url_for('dashboard.locks'), - server_locks_columns + div_server_locks, url_for('dashboard.locks'), server_locks_columns ); pgAdmin.Dashboard.render_grid( - div_server_prepared, sid, did, url_for('dashboard.prepared'), - server_prepared_columns + div_server_prepared, url_for('dashboard.prepared'), server_prepared_columns ); pgAdmin.Dashboard.render_grid( - div_server_config, sid, did, url_for('dashboard.config'), - server_config_columns + div_server_config, url_for('dashboard.config'), server_config_columns ); pgAdmin.Dashboard.render_grid_data(div_server_activity); @@ -969,7 +1055,7 @@ define('pgadmin.dashboard', [ }); // Handle button clicks - $('button').on('click',() => { + $('button').off('click').on('click',() => { switch (this.id) { case 'btn_server_activity_refresh': pgAdmin.Dashboard.render_grid_data(div_server_activity); @@ -990,87 +1076,14 @@ define('pgadmin.dashboard', [ }); } }, - - // 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, - 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'); - var div_to = document.getElementById('graph-to'); - var div_bio = document.getElementById('graph-bio'); + reflectPreferencesDatabase: function() { + var self = this; var div_database_activity = document.getElementById('database_activity'); var div_database_locks = document.getElementById('database_locks'); var div_database_prepared = document.getElementById('database_prepared'); - var dataset_sessions = []; - var data_sessions = []; - var dataset_tps = []; - var data_tps = []; - var dataset_ti = []; - var data_ti = []; - var dataset_to = []; - var data_to = []; - var dataset_bio = []; - var data_bio = []; - - var options_line = { - parseFloat: false, - xaxis: { - min: 100, - max: 0, - autoscale: 0, - }, - yaxis: { - autoscale: 1, - }, - legend: { - position: 'nw', - backgroundColor: '#D2E8FF', - }, - }; - - // 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 - ); - } // Display server activity - if (show_database_activity) { + if (self.preferences.show_activity) { var database_activity_columns = [{ name: 'pid', label: gettext('PID'), @@ -1103,7 +1116,7 @@ define('pgadmin.dashboard', [ cell: 'string', }]; - if (version < 90600) { + if (self.version < 90600) { database_activity_columns = database_activity_columns.concat( [{ name: 'waiting', @@ -1134,7 +1147,7 @@ define('pgadmin.dashboard', [ // Add version to each field _.each(subNodeFieldsModel[0].fields, function(obj) { - obj['version'] = version; + obj['version'] = self.version; }); // Add cancel active query button @@ -1143,7 +1156,7 @@ define('pgadmin.dashboard', [ label: '', cell: SessionDetailsCell, cell_priority: -1, - postgres_version: version, + postgres_version: self.version, schema: subNodeFieldsModel, }); @@ -1155,7 +1168,7 @@ define('pgadmin.dashboard', [ editable: false, cell_priority: -1, canDeleteRow: pgAdmin.Dashboard.can_take_action, - postgres_version: version, + postgres_version: self.version, }); database_activity_columns.unshift({ name: 'pg-backform-delete', @@ -1165,7 +1178,7 @@ define('pgadmin.dashboard', [ editable: false, cell_priority: -1, canDeleteRow: pgAdmin.Dashboard.can_take_action, - postgres_version: version, + postgres_version: self.version, }); var database_locks_columns = [{ @@ -1258,22 +1271,19 @@ define('pgadmin.dashboard', [ // 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 + div_database_activity, url_for('dashboard.activity'), database_activity_columns ); pgAdmin.Dashboard.render_grid( - div_database_locks, sid, did, url_for('dashboard.locks'), - database_locks_columns + div_database_locks, url_for('dashboard.locks'), database_locks_columns ); pgAdmin.Dashboard.render_grid( - div_database_prepared, sid, did, url_for('dashboard.prepared'), - database_prepared_columns + div_database_prepared, 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) { + $('a[data-toggle="tab"]').off('shown.bs.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); @@ -1290,7 +1300,7 @@ define('pgadmin.dashboard', [ }); // Handle button clicks - $('button').on('click',() => { + $('button').off('click').on('click',() => { switch (this.id) { case 'btn_database_activity_refresh': pgAdmin.Dashboard.render_grid_data(div_database_activity); @@ -1308,7 +1318,12 @@ define('pgadmin.dashboard', [ } }, toggleVisibility: function(flag) { +// let self = this; dashboardVisible = flag; + +// if(dashboardVisible) { +// self.init_dashboard(); +// } }, can_take_action: function(m) { // We will validate if user is allowed to cancel the active query diff --git a/web/pgadmin/dashboard/templates/dashboard/database_dashboard.html b/web/pgadmin/dashboard/templates/dashboard/database_dashboard.html index 37ff5b97a..26cde01aa 100644 --- a/web/pgadmin/dashboard/templates/dashboard/database_dashboard.html +++ b/web/pgadmin/dashboard/templates/dashboard/database_dashboard.html @@ -1,135 +1,110 @@
-{% if settings.show_graphs %} -
-
-
- {{ _('Database sessions') }} +
+
+
+
+ {{ _('Database sessions') }} +
+
+
+
+ {{ _('Transactions per second') }} +
-
-
- {{ _('Transactions per second') }} +
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
- {{ _('Tuples in') }} +
+
+
+ {{ _('Tuples in') }} +
+
+
+
+ {{ _('Tuples out') }} +
+
+
+
+ {{ _('Block I/O') }} +
-
-
- {{ _('Tuples out') }} -
-
-
-
- {{ _('Block I/O') }} -
-
-
-
-
-
-
-
-
-
-
-
-
-
-{% 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') }} +
+
+
+
+
+
+
+
+
-
-
-
- - +
+
+
+
+ {{ _('Database activity') }} +
+
+
+
+
+
+ + - -
-
-
- -
+ +
+
+
+ +
+
+
-
-
-
-
- -
+
+
+ +
+
+
-
-
-
-
- -
+
+
+ +
+
+
-
-{% endif %} - -{% if not settings.show_graphs and not settings.show_activity %} - - - diff --git a/web/pgadmin/dashboard/templates/dashboard/server_dashboard.html b/web/pgadmin/dashboard/templates/dashboard/server_dashboard.html index b3578253d..5a4df66aa 100644 --- a/web/pgadmin/dashboard/templates/dashboard/server_dashboard.html +++ b/web/pgadmin/dashboard/templates/dashboard/server_dashboard.html @@ -1,144 +1,120 @@
-{% if settings.show_graphs %} -
-
-
- {{ _('Server sessions') }} +
+
+
+
+ {{ _('Server sessions') }} +
+
+
+
+ {{ _('Transactions per second') }} +
-
-
- {{ _('Transactions per second') }} +
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
- {{ _('Tuples in') }} +
+
+
+ {{ _('Tuples in') }} +
+
+
+
+ {{ _('Tuples out') }} +
+
+
+
+ {{ _('Block I/O') }} +
-
-
- {{ _('Tuples out') }} -
-
-
-
- {{ _('Block I/O') }} -
-
-
-
-
-
-
-
-
-
-
-
-
-
-{% 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') }} +
+
+
+
+
+
+
+
+
-
-
-
- - +
+
+
+
+ {{ _('Server activity') }} +
+
+
+
+
+
+ + - -
-
-
- -
+ +
+
+
+ +
+
+
-
-
-
-
- -
+
+
+ +
+
+
-
-
-
-
- -
+
+
+ +
+
+
-
-
-
-
- -
+
+
+ +
+
+
-
-{% endif %} - -{% if not settings.show_graphs and not settings.show_activity %} - - - diff --git a/web/pgadmin/dashboard/tests/test_dashboard_templates.py b/web/pgadmin/dashboard/tests/test_dashboard_templates.py deleted file mode 100644 index dd24bddc9..000000000 --- a/web/pgadmin/dashboard/tests/test_dashboard_templates.py +++ /dev/null @@ -1,263 +0,0 @@ -########################################################################## -# -# 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 TestDashboardTemplates(BaseTestGenerator): - scenarios = [ - # Server dashboard - ( - 'Dashboard, when returning the html page with graphs and ' - 'server activity related html elements for server dashboard', - dict( - template_path='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='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='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='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='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='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='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='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" - ) diff --git a/web/pgadmin/static/js/keyboard_shortcuts.js b/web/pgadmin/static/js/keyboard_shortcuts.js index 232f67fd6..667129dd8 100644 --- a/web/pgadmin/static/js/keyboard_shortcuts.js +++ b/web/pgadmin/static/js/keyboard_shortcuts.js @@ -117,13 +117,10 @@ function validateShortcutKeys(user_defined_shortcut, event) { } /* Debugger: Keyboard Shortcuts handling */ -function keyboardShortcutsDebugger($el, event, user_defined_shortcuts) { +function keyboardShortcutsDebugger($el, event, preferences) { let panel_id, panel_content, $input; - let edit_grid_keys = user_defined_shortcuts.edit_grid_keys, - next_panel_keys = user_defined_shortcuts.next_panel_keys, - previous_panel_keys = user_defined_shortcuts.previous_panel_keys; - if(this.validateShortcutKeys(edit_grid_keys, event)) { + if(this.validateShortcutKeys(preferences.edit_grid_values, event)) { this._stopEventPropagation(event); panel_content = $el.find( 'div.wcPanelTabContent:not(".wcPanelTabContentHidden")' @@ -133,10 +130,10 @@ function keyboardShortcutsDebugger($el, event, user_defined_shortcuts) { if($input.length) $input.trigger('click'); } - } else if(this.validateShortcutKeys(next_panel_keys, event)) { + } else if(this.validateShortcutKeys(preferences.move_next, event)) { this._stopEventPropagation(event); panel_id = this.getInnerPanel($el, 'right'); - } else if(this.validateShortcutKeys(previous_panel_keys, event)) { + } else if(this.validateShortcutKeys(preferences.move_previous, event)) { this._stopEventPropagation(event); panel_id = this.getInnerPanel($el, 'left'); } diff --git a/web/pgadmin/tools/debugger/__init__.py b/web/pgadmin/tools/debugger/__init__.py index f24942d72..4479f85cb 100644 --- a/web/pgadmin/tools/debugger/__init__.py +++ b/web/pgadmin/tools/debugger/__init__.py @@ -293,33 +293,6 @@ def update_session_function_transaction(trans_id, data): session['functionData'] = function_data -def get_shortcuts_for_accesskey(): - """ - This function will fetch and return accesskey shortcuts for debugger - toolbar buttons - - Returns: - Dict of shortcut keys - """ - # Fetch debugger preferences - dp = Preferences.module('debugger') - btn_start = dp.preference('btn_start').get() - btn_stop = dp.preference('btn_stop').get() - btn_step_into = dp.preference('btn_step_into').get() - btn_step_over = dp.preference('btn_step_over').get() - btn_toggle_breakpoint = dp.preference('btn_toggle_breakpoint').get() - btn_clear_breakpoints = dp.preference('btn_clear_breakpoints').get() - - return { - 'start': btn_start.get('key').get('char'), - 'stop': btn_stop.get('key').get('char'), - 'step_into': btn_step_into.get('key').get('char'), - 'step_over': btn_step_over.get('key').get('char'), - 'toggle_breakpoint': btn_toggle_breakpoint.get('key').get('char'), - 'clear_breakpoints': btn_clear_breakpoints.get('key').get('char') - } - - @blueprint.route( '/init/////', methods=['GET'], endpoint='init_for_function' @@ -589,7 +562,6 @@ def direct_new(trans_id): is_linux=is_linux_platform, client_platform=user_agent.platform, stylesheets=[url_for('debugger.static', filename='css/debugger.css')], - accesskey=get_shortcuts_for_accesskey() ) @@ -811,12 +783,8 @@ def initialize_target(debug_type, sid, did, scid, func_id, tri_id=None): # is initialized del session['funcData'] - pref = Preferences.module('debugger') - new_browser_tab = pref.preference('debugger_new_browser_tab').get() - return make_json_response(data={'status': status, - 'debuggerTransId': trans_id, - 'newBrowserTab': new_browser_tab}) + 'debuggerTransId': trans_id}) @blueprint.route( diff --git a/web/pgadmin/tools/debugger/static/js/debugger.js b/web/pgadmin/tools/debugger/static/js/debugger.js index d632343e8..39caca716 100644 --- a/web/pgadmin/tools/debugger/static/js/debugger.js +++ b/web/pgadmin/tools/debugger/static/js/debugger.js @@ -184,6 +184,18 @@ define([ }); this.frame.load(pgBrowser.docker); + + let self = this; + let cacheIntervalId = setInterval(function() { + try { + self.preferences = window.top.pgAdmin.Browser; + clearInterval(cacheIntervalId); + } + catch(err) { + clearInterval(cacheIntervalId); + throw err; + } + }); }, // It will check weather the function is actually debuggable or not with pre-required condition. can_debug: function(itemData, item, data) { @@ -313,7 +325,8 @@ define([ var t = pgBrowser.tree, i = item || t.selected(), d = i && i.length == 1 ? t.itemData(i) : undefined, - node = d && pgBrowser.Nodes[d._type]; + node = d && pgBrowser.Nodes[d._type], + self = this; if (!d) return; @@ -384,7 +397,7 @@ define([ 'trans_id': res.data.debuggerTransId, }); - if (res.data.newBrowserTab) { + if (self.preferences.debugger_new_browser_tab) { window.open(url, '_blank'); } else { pgBrowser.Events.once( @@ -435,7 +448,8 @@ define([ var t = pgBrowser.tree, i = item || t.selected(), d = i && i.length == 1 ? t.itemData(i) : undefined, - node = d && pgBrowser.Nodes[d._type]; + node = d && pgBrowser.Nodes[d._type], + self = this; if (!d) return; @@ -499,7 +513,7 @@ define([ 'trans_id': res.data.debuggerTransId, }); - if (res.data.newBrowserTab) { + if (self.preferences.debugger_new_browser_tab) { window.open(url, '_blank'); } else { pgBrowser.Events.once( diff --git a/web/pgadmin/tools/debugger/static/js/direct.js b/web/pgadmin/tools/debugger/static/js/direct.js index bc1aff11f..35a6970e3 100644 --- a/web/pgadmin/tools/debugger/static/js/direct.js +++ b/web/pgadmin/tools/debugger/static/js/direct.js @@ -1393,7 +1393,7 @@ define([ controller about the click and controller will take the action for the specified button click. */ var DebuggerToolbarView = Backbone.View.extend({ - el: '.dubugger_main_container', + el: '.debugger_main_container', initialize: function() { controller.on('pgDebugger:button:state:stop', this.enable_stop, this); controller.on('pgDebugger:button:state:step_over', this.enable_step_over, this); @@ -1496,44 +1496,11 @@ define([ controller.Step_into(pgTools.DirectDebug.trans_id); }, keyAction: function (event) { - var $el = this.$el, panel_id, actual_panel; - - // If already fetched earlier then don't do it again - if(_.size(pgTools.DirectDebug.debugger_keyboard_shortcuts) == 0) { - // Fetch keyboard shortcut keys - var edit_grid_shortcut_perf, next_panel_perf, previous_panel_perf; - edit_grid_shortcut_perf = window.top.pgAdmin.Browser.get_preference( - 'debugger', 'edit_grid_values' - ); - next_panel_perf = window.top.pgAdmin.Browser.get_preference( - 'debugger', 'move_next' - ); - previous_panel_perf = window.top.pgAdmin.Browser.get_preference( - 'debugger', 'move_previous' - ); - - // If debugger opened in new Tab then window.top won't be available - if(!edit_grid_shortcut_perf || !next_panel_perf || !previous_panel_perf) { - edit_grid_shortcut_perf = window.opener.pgAdmin.Browser.get_preference( - 'debugger', 'edit_grid_values' - ); - next_panel_perf = window.opener.pgAdmin.Browser.get_preference( - 'debugger', 'move_next' - ); - previous_panel_perf = window.opener.pgAdmin.Browser.get_preference( - 'debugger', 'move_previous' - ); - } - - pgTools.DirectDebug.debugger_keyboard_shortcuts = { - 'edit_grid_keys': edit_grid_shortcut_perf.value, - 'next_panel_keys': next_panel_perf.value, - 'previous_panel_keys': previous_panel_perf.value, - }; - } + var $el = this.$el, panel_id, actual_panel, + self = this; panel_id = keyboardShortcuts.processEventDebugger( - $el, event, pgTools.DirectDebug.debugger_keyboard_shortcuts + $el, event, self.preferences ); // Panel navigation @@ -1572,7 +1539,10 @@ define([ this.debug_restarted = false; this.is_user_aborted_debugging = false; this.is_polling_required = true; // Flag to stop unwanted ajax calls - this.debugger_keyboard_shortcuts = {}; + + let browser = window.opener ? + window.opener.pgAdmin.Browser : window.top.pgAdmin.Browser; + this.preferences = browser.get_preferences_for_module('sqleditor'); this.docker = new wcDocker( '#container', { @@ -1856,6 +1826,35 @@ define([ if(self.docker.$container){ self.docker.$container.parent().focus(); } + + let cacheIntervalId = setInterval(function() { + try { + let browser = window.opener ? window.opener.pgAdmin.Browser : window.top.pgAdmin.Browser; + if(browser.preference_version() > 0) { + clearInterval(cacheIntervalId); + self.reflectPreferences(); + + /* If debugger is in a new tab, event fired is not available + * instead, a poller is set up who will check + */ + if(self.preferences.debugger_new_browser_tab) { + let pollIntervalId = setInterval(()=>{ + if(window.opener && window.opener.pgAdmin) { + self.reflectPreferences(); + } + else { + clearInterval(pollIntervalId); + } + }, 1000); + } + } + } + catch(err) { + clearInterval(cacheIntervalId); + throw err; + } + },0); + }; self.docker.startLoading(gettext('Loading...')); @@ -1863,8 +1862,50 @@ define([ // Create the toolbar view for debugging the function this.toolbarView = new DebuggerToolbarView(); - }, + /* Cache may take time to load for the first time + * Keep trying till available + */ + + + /* Register for preference changed event broadcasted in parent + * to reload the shorcuts. + */ + pgBrowser.onPreferencesChange('debugger', function() { + self.reflectPreferences(); + }); + }, + reflectPreferences: function() { + let self = this, + browser = window.opener ? window.opener.pgAdmin.Browser : window.top.pgAdmin.Browser; + self.preferences = browser.get_preferences_for_module('debugger'); + self.toolbarView.preferences = self.preferences; + + /* Update the shortcuts of the buttons */ + self.toolbarView.$el.find('#btn-step-into') + .attr('title', keyboardShortcuts.shortcut_accesskey_title('Step into',self.preferences.btn_step_into)) + .attr('accesskey', keyboardShortcuts.shortcut_key(self.preferences.btn_step_into)); + + self.toolbarView.$el.find('#btn-step-over') + .attr('title', keyboardShortcuts.shortcut_accesskey_title('Step over',self.preferences.btn_step_over)) + .attr('accesskey', keyboardShortcuts.shortcut_key(self.preferences.btn_step_over)); + + self.toolbarView.$el.find('#btn-continue') + .attr('title', keyboardShortcuts.shortcut_accesskey_title('Continue/Start',self.preferences.btn_start)) + .attr('accesskey', keyboardShortcuts.shortcut_key(self.preferences.btn_start)); + + self.toolbarView.$el.find('#btn-toggle-breakpoint') + .attr('title', keyboardShortcuts.shortcut_accesskey_title('Toggle breakpoint',self.preferences.btn_toggle_breakpoint)) + .attr('accesskey', keyboardShortcuts.shortcut_key(self.preferences.btn_toggle_breakpoint)); + + self.toolbarView.$el.find('#btn-clear-breakpoint') + .attr('title', keyboardShortcuts.shortcut_accesskey_title('Clear all breakpoints',self.preferences.btn_clear_breakpoints)) + .attr('accesskey', keyboardShortcuts.shortcut_key(self.preferences.btn_clear_breakpoints)); + + self.toolbarView.$el.find('#btn-stop') + .attr('title', keyboardShortcuts.shortcut_accesskey_title('Stop',self.preferences.btn_stop)) + .attr('accesskey', keyboardShortcuts.shortcut_key(self.preferences.btn_stop)); + }, // Register the panel with new debugger docker instance. registerPanel: function(name, title, width, height, onInit) { var self = this; diff --git a/web/pgadmin/tools/debugger/templates/debugger/direct.html b/web/pgadmin/tools/debugger/templates/debugger/direct.html index 58d97a068..084126983 100644 --- a/web/pgadmin/tools/debugger/templates/debugger/direct.html +++ b/web/pgadmin/tools/debugger/templates/debugger/direct.html @@ -35,47 +35,47 @@ try { .debugger-container .wcLoadingIcon.fa-pulse{-webkit-animation: none;} {% endif %} -
+