public inbox for [email protected]help / color / mirror / Atom feed
[pgAdmin4][RM3294] User need to reset the layout to see the changed preferences parameters 14+ messages / 3 participants [nested] [flat]
* [pgAdmin4][RM3294] User need to reset the layout to see the changed preferences parameters @ 2018-06-28 14:34 Aditya Toshniwal <[email protected]> 0 siblings, 1 reply; 14+ messages in thread From: Aditya Toshniwal @ 2018-06-28 14:34 UTC (permalink / raw) To: pgadmin-hackers Hi Hackers, Attached is the patch for making preferences realtime and applying without reseting the layout. Please note, the patch is only for one module - SQL Editor and is the first part for the RM. There are lot of changes to be done to cover all and hence sending in parts. This will not affect/break existing code. Further patches will cover other modules. Highlights of this patch include: - Changes will affect SQL Editors in Create dialog boxes, SQL tab of the main screen, Query tool, History entries in the query tool, Query tool opened in New Tab/Window - All the components of SQL editor will refer to single source of preferences which is cached in the Browser object. All other redundant ajax get preference calls are removed. - SQL editor will not refer template JS variables anymore, once all the references are removed the template variables will also be removed. - Code refactoring wherever possible. - Covered JS test cases wherever possible. Request you to kindly review. -- Thanks and Regards, Aditya Toshniwal Software Engineer | EnterpriseDB Software Solutions | Pune "Don't Complain about Heat, Plant a tree" Attachments: [application/octet-stream] 0001-RM3294.patch (106.6K, 3-0001-RM3294.patch) download | inline diff: diff --git a/web/pgadmin/browser/__init__.py b/web/pgadmin/browser/__init__.py index 3741d9d3..fb1eb7db 100644 --- a/web/pgadmin/browser/__init__.py +++ b/web/pgadmin/browser/__init__.py @@ -680,17 +680,6 @@ def browser_css(): """Render and return CSS snippets from the nodes and modules.""" snippets = [] - # Get configurable options - prefs = Preferences.module('sqleditor') - - sql_font_size_pref = prefs.preference('sql_font_size') - sql_font_size = round(float(sql_font_size_pref.get()), 2) - - if sql_font_size != 0: - snippets.append( - '.CodeMirror { font-size: %sem; }' % str(sql_font_size) - ) - for submodule in blueprint.submodules: snippets.extend(submodule.csssnippets) return make_response( diff --git a/web/pgadmin/browser/static/css/browser.css b/web/pgadmin/browser/static/css/browser.css index 3ba330d3..1b2e06e7 100644 --- a/web/pgadmin/browser/static/css/browser.css +++ b/web/pgadmin/browser/static/css/browser.css @@ -1,3 +1,6 @@ +:root { + --codemirror-font-size : 1em; +} /* Styles for the main browser */ .browser-pane-container { position: absolute; @@ -66,3 +69,8 @@ samp, .pg-login-icon { font-size: 16px; } + +.CodeMirror { + font-size: var(--codemirror-font-size, '1em'); +} + diff --git a/web/pgadmin/browser/static/js/browser.js b/web/pgadmin/browser/static/js/browser.js index b26738cf..c330a871 100644 --- a/web/pgadmin/browser/static/js/browser.js +++ b/web/pgadmin/browser/static/js/browser.js @@ -2,8 +2,8 @@ define('pgadmin.browser', [ 'sources/tree/tree', 'sources/gettext', 'sources/url_for', 'require', 'jquery', 'underscore', 'underscore.string', 'bootstrap', 'sources/pgadmin', 'pgadmin.alertifyjs', 'bundled_codemirror', - 'sources/check_node_visibility', 'sources/modify_animation', 'pgadmin.browser.utils', 'wcdocker', - 'jquery.contextmenu', 'jquery.aciplugin', 'jquery.acitree', + 'sources/check_node_visibility', 'pgadmin.browser.utils', 'wcdocker', + 'jquery.contextmenu', 'jquery.aciplugin', 'jquery.acitree', 'pgadmin.browser.preferences', 'pgadmin.browser.messages', 'pgadmin.browser.menu', 'pgadmin.browser.panel', 'pgadmin.browser.error', 'pgadmin.browser.frame', @@ -13,7 +13,7 @@ define('pgadmin.browser', [ ], function( tree, gettext, url_for, require, $, _, S, Bootstrap, pgAdmin, Alertify, - codemirror, checkNodeVisibility, modifyAnimation + codemirror, checkNodeVisibility ) { window.jQuery = window.$ = $; // Some scripts do export their object in the window only. @@ -342,7 +342,7 @@ define('pgadmin.browser', [ // Cache preferences obj.cache_preferences(); - this.add_panels(); + obj.add_panels(); // Initialize the Docker obj.docker = new wcDocker( '#dockerContainer', { @@ -400,11 +400,22 @@ define('pgadmin.browser', [ mode: 'text/x-pgsql', readOnly: true, extraKeys: pgAdmin.Browser.editor_shortcut_keys, - tabSize: pgAdmin.Browser.editor_options.tabSize, - lineWrapping: pgAdmin.Browser.editor_options.wrapCode, - autoCloseBrackets: pgAdmin.Browser.editor_options.insert_pair_brackets, - matchBrackets: pgAdmin.Browser.editor_options.brace_matching, }); + /* Cache may take time to load for the first time + * Reflect the changes once cache is available + */ + let cacheIntervalId = setInterval(()=> { + let sqlEditPreferences = obj.get_preferences_for_module('sqleditor'); + if(sqlEditPreferences) { + clearInterval(cacheIntervalId); + obj.reflectPreferences('sqleditor'); + } + }, 500); + + /* Check for sql editor preference changes */ + obj.onPreferencesChange('sqleditor', function() { + obj.reflectPreferences('sqleditor'); + }); setTimeout(function() { obj.editor.setValue('-- ' + select_object_msg); @@ -514,10 +525,6 @@ define('pgadmin.browser', [ }; }, - // This will hold preference data (Works as a cache object) - // Here node will be a key and it's preference data will be value - preferences_cache: {}, - // Add menus of module/extension at appropriate menu add_menus: function(menus) { var self = this, @@ -661,46 +668,6 @@ define('pgadmin.browser', [ } } }, - - // Get preference value from cache - get_preference: function(module, preference) { - var self = this; - // If cache is not yet loaded then keep checking - if(_.size(self.preferences_cache) == 0) { - var check_preference = function() { - if(_.size(self.preferences_cache) > 0) { - clearInterval(preferenceTimeout); - return _.findWhere( - self.preferences_cache, {'module': module, 'name': preference} - ); - } - }, - preferenceTimeout = setInterval(check_preference, 1000); - } - else { - return _.findWhere( - self.preferences_cache, {'module': module, 'name': preference} - ); - } - }, - - // Get and cache the preferences - cache_preferences: function () { - var self = this; - $.ajax({ - url: url_for('preferences.get_all'), - success: function(res) { - self.preferences_cache = res; - pgBrowser.keyboardNavigation.init(); - modifyAnimation.modifyAcitreeAnimation(self); - modifyAnimation.modifyAlertifyAnimation(self); - }, - error: function(xhr, status, error) { - Alertify.pgRespErrorNotify(xhr, error); - }, - }); - }, - _findTreeChildNode: function(_i, _d, _o) { var loaded = _o.t.wasLoad(_i), onLoad = function() { diff --git a/web/pgadmin/browser/static/js/preferences.js b/web/pgadmin/browser/static/js/preferences.js new file mode 100644 index 00000000..73caa10d --- /dev/null +++ b/web/pgadmin/browser/static/js/preferences.js @@ -0,0 +1,126 @@ +import pgAdmin from 'sources/pgadmin'; +import url_for from 'sources/url_for'; +import * as modifyAnimation from 'sources/modify_animation'; +import $ from 'jquery'; +import * as Alertify from 'pgadmin.alertifyjs'; +import * as SqlEditorUtils from 'sources/sqleditor_utils'; + +const pgBrowser = pgAdmin.Browser = pgAdmin.Browser || {}; + +/* Add cache related methods and properties */ +_.extend(pgBrowser, { + /* This will hold preference data (Works as a cache object) + * Here node will be a key and it's preference data will be value + */ + preferences_cache: [], + + /* This will be used by poller of new tabs/windows to check + * if preference cache is updated in parent/window.opener. + */ + prefcache_version: 0, + + /* Get cached preference */ + get_preference: function(module, preference){ + const self = this; + // If cache is not yet loaded then keep checking + if(_.size(self.preferences_cache) == 0) { + var check_preference = function() { + if(self.preferences_cache.length > 0) { + clearInterval(preferenceTimeout); + return _.findWhere( + self.preferences_cache, {'module': module, 'name': preference} + ); + } + }, + preferenceTimeout = setInterval(check_preference, 1000); + } + else { + return _.findWhere( + self.preferences_cache, {'module': module, 'name': preference} + ); + } + }, + + /* Get all the preferences of a module */ + get_preferences_for_module: function(module) { + var self = this; + let preferences = {}; + _.each( + _.where(self.preferences_cache, {'module': module}), + (preference) => { + preferences[preference.name] = preference.value; + } + ); + return preferences; + }, + + /* Get preference of an id, id is numeric */ + get_preference_for_id : function(id) { + var self = this; + return _.findWhere(self.preferences_cache, {'id': id}); + }, + + // Get and cache the preferences + cache_preferences: function (modulesChanged) { + var self = this; + return $.ajax({ + url: url_for('preferences.get_all'), + success: function(res) { + self.preferences_cache = res; + self.prefcache_version = (new Date()).getTime(); + + pgBrowser.keyboardNavigation.init(); + if(pgBrowser.tree) { + modifyAnimation.modifyAcitreeAnimation(self); + modifyAnimation.modifyAlertifyAnimation(self); + } + + /* Once the cache is loaded after changing the preferences, + * notify the modules of the change + */ + if(modulesChanged) { + _.each(modulesChanged, (val, key)=> { + $.event.trigger('prefchange:'+key); + }); + } + }, + error: function(xhr, status, error) { + Alertify.pgRespErrorNotify(xhr, error); + }, + }); + }, + + reflectPreferences: function(module) { + let obj = this; + + if(module === 'sqleditor' || module === null || typeof module === 'undefined') { + let sqlEditPreferences = obj.get_preferences_for_module('sqleditor'); + + $(obj.editor.getWrapperElement()).css( + 'font-size',SqlEditorUtils.calcFontSize(sqlEditPreferences.sql_font_size) + ); + obj.editor.setOption('tabSize', sqlEditPreferences.tab_size); + obj.editor.setOption('lineWrapping', sqlEditPreferences.wrap_code); + obj.editor.setOption('autoCloseBrackets', sqlEditPreferences.insert_pair_brackets); + obj.editor.setOption('matchBrackets', sqlEditPreferences.brace_matching); + obj.editor.refresh(); + } + }, + + onPreferencesChange: function(module, eventHandler) { + window.parent.$(parent.document).on('prefchange:'+module, function(event) { + /* If a sqleditor is closed, event handler will be called + * but the window.top will be null. Unbind the event handler + */ + if(window.top === null) { + window.$(document).off(event); + } + else { + eventHandler(event); + } + }); + }, + +}); + +export {pgBrowser}; diff --git a/web/pgadmin/preferences/static/js/preferences.js b/web/pgadmin/preferences/static/js/preferences.js index cdbda0cd..7f21f80c 100644 --- a/web/pgadmin/preferences/static/js/preferences.js +++ b/web/pgadmin/preferences/static/js/preferences.js @@ -439,8 +439,20 @@ define('pgadmin.preferences', [ if (e.button.text == gettext('OK')) { preferences.updateAll(); + + /* Find the modules changed */ + let modulesChanged = {}; + _.each(changed, (val, key)=> { + let pref = pgBrowser.get_preference_for_id(Number(key)); + if(!modulesChanged[pref.module]) { + modulesChanged[pref.module] = true; + } + }); + // Refresh preferences cache - setTimeout(pgBrowser.cache_preferences(), 2000); + setTimeout(()=> { + pgBrowser.cache_preferences(modulesChanged); + }, 500); } }, build: function() { diff --git a/web/pgadmin/static/js/backform.pgadmin.js b/web/pgadmin/static/js/backform.pgadmin.js index c7b98496..7096ee7b 100644 --- a/web/pgadmin/static/js/backform.pgadmin.js +++ b/web/pgadmin/static/js/backform.pgadmin.js @@ -1,10 +1,11 @@ define([ 'sources/gettext', 'underscore', 'underscore.string', 'jquery', - 'backbone', 'backform', 'backgrid', 'codemirror', 'spectrum', - 'pgadmin.backgrid', 'select2', -], function(gettext, _, S, $, Backbone, Backform, Backgrid, CodeMirror) { + 'backbone', 'backform', 'backgrid', 'codemirror', 'sources/sqleditor_utils', + 'spectrum', 'pgadmin.backgrid', 'select2', +], function(gettext, _, S, $, Backbone, Backform, Backgrid, CodeMirror, SqlEditorUtils) { - var pgAdmin = (window.pgAdmin = window.pgAdmin || {}); + var pgAdmin = (window.pgAdmin = window.pgAdmin || {}), + pgBrowser = pgAdmin.Browser; pgAdmin.editableCell = function() { if (this.attributes && !_.isUndefined(this.attributes.disabled) && @@ -1259,8 +1260,7 @@ define([ var subnode = data.subnode.schema ? data.subnode : data.subnode.prototype, gridSchema = Backform.generateGridColumnsFromModel( data.node_info, subnode, this.field.get('mode'), data.columns, data.schema_node - ), - pgBrowser = window.pgAdmin.Browser; + ); // Clean up existing grid if any (in case of re-render) if (self.grid) { @@ -1428,6 +1428,23 @@ define([ getValueFromDOM: function() { return this.formatter.toRaw(this.$el.find('textarea').val(), this.model); }, + + reflectPreferences: function() { + var self = this; + /* self.sqlCtrl is null when SQL tab is not active */ + if(self.sqlCtrl) { + let sqlEditPreferences = pgAdmin.Browser.get_preferences_for_module('sqleditor'); + + $(self.sqlCtrl.getWrapperElement()).css( + 'font-size',SqlEditorUtils.calcFontSize(sqlEditPreferences.sql_font_size) + ); + self.sqlCtrl.setOption('tabSize', sqlEditPreferences.tab_size); + self.sqlCtrl.setOption('lineWrapping', sqlEditPreferences.wrap_code); + self.sqlCtrl.setOption('autoCloseBrackets', sqlEditPreferences.insert_pair_brackets); + self.sqlCtrl.setOption('matchBrackets', sqlEditPreferences.brace_matching); + self.sqlCtrl.refresh(); + } + }, render: function() { if (this.sqlCtrl) { this.sqlCtrl.toTextArea(); @@ -1446,12 +1463,16 @@ define([ mode: 'text/x-pgsql', readOnly: true, extraKeys: pgAdmin.Browser.editor_shortcut_keys, - tabSize: pgAdmin.Browser.editor_options.tabSize, - lineWrapping: pgAdmin.Browser.editor_options.wrapCode, - autoCloseBrackets: pgAdmin.Browser.editor_options.insert_pair_brackets, - matchBrackets: pgAdmin.Browser.editor_options.brace_matching, }); + this.reflectPreferences(); + + /* Check for sql editor preference changes */ + let self = this; + pgBrowser.onPreferencesChange('sqleditor', function() { + self.reflectPreferences(); + }); + /* * We will listen to the tab change event to check, if the SQL tab has * been clicked or, not. @@ -1571,7 +1592,6 @@ define([ ) { var proto = (Model && Model.prototype) || Model, schema = subschema || (proto && proto.schema), - pgBrowser = window.pgAdmin.Browser, fields = [], groupInfo = {}; @@ -2051,6 +2071,25 @@ define([ return this.sqlCtrl.getValue(); }, + reflectPreferences: function() { + var self = this; + /* self.sqlCtrl is null when Definition tab is not active */ + if(self.sqlCtrl) { + let sqlEditPreferences = pgAdmin.Browser.get_preferences_for_module('sqleditor'); + + $(self.sqlCtrl.getWrapperElement()).css( + 'font-size',SqlEditorUtils.calcFontSize(sqlEditPreferences.sql_font_size) + ); + self.sqlCtrl.setOption('indentWithTabs', !sqlEditPreferences.use_spaces); + self.sqlCtrl.setOption('indentUnit', sqlEditPreferences.tab_size); + self.sqlCtrl.setOption('tabSize', sqlEditPreferences.tab_size); + self.sqlCtrl.setOption('lineWrapping', sqlEditPreferences.wrap_code); + self.sqlCtrl.setOption('autoCloseBrackets', sqlEditPreferences.insert_pair_brackets); + self.sqlCtrl.setOption('matchBrackets', sqlEditPreferences.brace_matching); + self.sqlCtrl.refresh(); + } + }, + render: function() { // Clean up the existing sql control if (this.sqlCtrl) { @@ -2093,14 +2132,14 @@ define([ lineNumbers: true, mode: 'text/x-pgsql', extraKeys: pgAdmin.Browser.editor_shortcut_keys, - indentWithTabs: pgAdmin.Browser.editor_options.indent_with_tabs, - indentUnit: pgAdmin.Browser.editor_options.tabSize, - tabSize: pgAdmin.Browser.editor_options.tabSize, - lineWrapping: pgAdmin.Browser.editor_options.wrapCode, - autoCloseBrackets: pgAdmin.Browser.editor_options.insert_pair_brackets, - matchBrackets: pgAdmin.Browser.editor_options.brace_matching, }); + self.reflectPreferences(); + /* Check for sql editor preference changes */ + pgBrowser.onPreferencesChange('sqleditor', function() { + self.reflectPreferences(); + }); + // Disable editor if (isDisabled) { // set read only mode to true instead of 'nocursor', and hide cursor using a class so that copying is enabled diff --git a/web/pgadmin/static/js/keyboard_shortcuts.js b/web/pgadmin/static/js/keyboard_shortcuts.js index 1fe07e9b..57d8a303 100644 --- a/web/pgadmin/static/js/keyboard_shortcuts.js +++ b/web/pgadmin/static/js/keyboard_shortcuts.js @@ -8,6 +8,7 @@ ////////////////////////////////////////////////////////////////////////// import $ from 'jquery'; +import gettext from 'sources/gettext'; const PERIOD_KEY = 190, FWD_SLASH_KEY = 191, @@ -49,6 +50,52 @@ function isCtrlAltBoth(event) { return event.ctrlKey && event.altKey && !event.shiftKey; } +/* Returns the key of shortcut */ +function shortcut_key(shortcut) { + let key = ''; + if(shortcut['key'] && shortcut['key']['char']) { + key = shortcut['key']['char'].toUpperCase(); + } + return key; +} + +/* Converts shortcut object to title representation + * Shortcut object is browser.get_preference().value + */ +function shortcut_title(title, shortcut) { + let text_representation = ''; + + if (typeof shortcut === 'undefined' || shortcut === null) { + return text_representation; + } + if(shortcut['alt']) { + text_representation = gettext('Alt') + '+'; + } + if(shortcut['shift']) { + text_representation += gettext('Shift') + '+'; + } + if(shortcut['control']) { + text_representation += gettext('Ctrl') + '+'; + } + text_representation += shortcut_key(shortcut); + + return gettext('%(title)s (%(text_representation)s)',{ + 'title': title, + 'text_representation': text_representation, + }); +} + +/* Returns the key char of shortcut + * shortcut object is browser.get_preference().value + */ +function shortcut_accesskey_title(title, shortcut) { + return gettext('%(title)s (accesskey + %(key)s)',{ + 'title': title, + 'key': shortcut_key(shortcut), + }); +} + + function _stopEventPropagation(event) { event.cancelBubble = true; event.preventDefault(); @@ -124,19 +171,19 @@ function getInnerPanel($el, direction) { /* Query tool: Keyboard Shortcuts handling */ function keyboardShortcutsQueryTool( - sqlEditorController, keyboardShortcutConfig, queryToolActions, event + sqlEditorController, queryToolActions, event ) { if (sqlEditorController.isQueryRunning()) { return; } let keyCode = event.which || event.keyCode, panel_id; - let executeKeys = keyboardShortcutConfig['execute']; - let explainKeys = keyboardShortcutConfig['explain']; - let explainAnalyzeKeys = keyboardShortcutConfig['explain_analyze']; - let downloadCsvKeys = keyboardShortcutConfig['download_csv']; - let nextPanelKeys = keyboardShortcutConfig['move_next']; - let previousPanelKeys = keyboardShortcutConfig['move_previous']; - let toggleCaseKeys = keyboardShortcutConfig['toggle_case']; + let executeKeys = sqlEditorController.preferences.execute_query; + let explainKeys = sqlEditorController.preferences.explain_query; + let explainAnalyzeKeys = sqlEditorController.preferences.explain_analyze_query; + let downloadCsvKeys = sqlEditorController.preferences.download_csv; + let nextPanelKeys = sqlEditorController.preferences.move_next; + let previousPanelKeys = sqlEditorController.preferences.move_previous; + let toggleCaseKeys = sqlEditorController.preferences.toggle_case; if (this.validateShortcutKeys(executeKeys, event)) { this._stopEventPropagation(event); @@ -245,4 +292,7 @@ module.exports = { isAltShiftBoth: isAltShiftBoth, isCtrlShiftBoth: isCtrlShiftBoth, isCtrlAltBoth: isCtrlAltBoth, + shortcut_key : shortcut_key, + shortcut_title : shortcut_title, + shortcut_accesskey_title : shortcut_accesskey_title, }; diff --git a/web/pgadmin/static/js/sqleditor/query_tool_actions.js b/web/pgadmin/static/js/sqleditor/query_tool_actions.js index 411c6ed5..6cbbce0f 100644 --- a/web/pgadmin/static/js/sqleditor/query_tool_actions.js +++ b/web/pgadmin/static/js/sqleditor/query_tool_actions.js @@ -119,58 +119,6 @@ let queryToolActions = { window.top.document.activeElement.blur(); }, - getKeyboardShortcuts: function (sqlEditorController) { - let executeQueryPref = window.top.pgAdmin.Browser.get_preference( - 'sqleditor', 'execute_query'); - let explainQueryPref = window.top.pgAdmin.Browser.get_preference( - 'sqleditor', 'explain_query'); - let explainAnalyzeQueryPref = window.top.pgAdmin.Browser.get_preference( - 'sqleditor', 'explain_analyze_query'); - let downloadCsvPref = window.top.pgAdmin.Browser.get_preference( - 'sqleditor', 'download_csv'); - let nextPanelPerf = window.top.pgAdmin.Browser.get_preference( - 'sqleditor', 'move_next'); - let previousPanelPerf = window.top.pgAdmin.Browser.get_preference( - 'sqleditor', 'move_previous'); - let toggleCasePerf = window.top.pgAdmin.Browser.get_preference( - 'sqleditor', 'toggle_case'); - - if(!executeQueryPref && sqlEditorController.handler.is_new_browser_tab) { - executeQueryPref = window.opener.pgAdmin.Browser.get_preference( - 'sqleditor', 'execute_query' - ), - explainQueryPref = window.opener.pgAdmin.Browser.get_preference( - 'sqleditor', 'explain_query' - ), - explainAnalyzeQueryPref = window.opener.pgAdmin.Browser.get_preference( - 'sqleditor', 'explain_analyze_query' - ), - downloadCsvPref = window.opener.pgAdmin.Browser.get_preference( - 'sqleditor', 'download_csv' - ), - nextPanelPerf = window.opener.pgAdmin.Browser.get_preference( - 'sqleditor', 'move_next' - ), - previousPanelPerf = window.opener.pgAdmin.Browser.get_preference( - 'sqleditor', 'move_previous' - ), - toggleCasePerf = window.opener.pgAdmin.Browser.get_preference( - 'sqleditor', 'toggle_case' - ); - } - - return { - 'execute': executeQueryPref.value, - 'explain': explainQueryPref.value, - 'explain_analyze': explainAnalyzeQueryPref.value, - 'download_csv': downloadCsvPref.value, - 'move_next': nextPanelPerf.value, - 'move_previous': previousPanelPerf.value, - 'toggle_case': toggleCasePerf.value, - }; - - }, - toggleCaseOfSelectedText: function (sqlEditorController) { let codeMirrorObj = sqlEditorController.gridView.query_tool_obj; let selectedText = codeMirrorObj.getSelection(); diff --git a/web/pgadmin/static/js/sqleditor/query_tool_preferences.js b/web/pgadmin/static/js/sqleditor/query_tool_preferences.js new file mode 100644 index 00000000..3ee2f0bc --- /dev/null +++ b/web/pgadmin/static/js/sqleditor/query_tool_preferences.js @@ -0,0 +1,179 @@ +import {shortcut_key, shortcut_accesskey_title, shortcut_title} + from 'sources/keyboard_shortcuts'; +import * as SqlEditorUtils from 'sources/sqleditor_utils'; +import $ from 'jquery'; + +function reflectPreferences(sqlEditor) { + let $el = sqlEditor.$el, + preferences = sqlEditor.preferences; + + if(sqlEditor.handler.slickgrid) { + sqlEditor.handler.slickgrid.CSVOptions = { + quoting: sqlEditor.preferences.results_grid_quoting, + quote_char: sqlEditor.preferences.results_grid_quote_char, + field_separator: sqlEditor.preferences.results_grid_field_separator, + }; + } + + /* Accessed using accesskey direct w/o ctrl,atl,shift */ + $el.find('#btn-load-file') + .attr('title', shortcut_accesskey_title('Open File',preferences.btn_open_file)) + .attr('accesskey', shortcut_key(preferences.btn_open_file)); + + $el.find('#btn-save') + .attr('title', shortcut_accesskey_title('Save File',preferences.btn_save_file)) + .attr('accesskey', shortcut_key(preferences.btn_save_file)); + + $el.find('#btn-find-menu-dropdown') + .attr('title', shortcut_accesskey_title('Find',preferences.btn_find_options)) + .attr('accesskey', shortcut_key(preferences.btn_find_options)); + + $el.find('#btn-copy-row') + .attr('title', shortcut_accesskey_title('Copy',preferences.btn_copy_row)) + .attr('accesskey', shortcut_key(preferences.btn_copy_row)); + + $el.find('#btn-paste-row') + .attr('title', shortcut_accesskey_title('Paste',preferences.btn_paste_row)) + .attr('accesskey', shortcut_key(preferences.btn_paste_row)); + + $el.find('#btn-delete-row') + .attr('title', shortcut_accesskey_title('Delete',preferences.btn_delete_row)) + .attr('accesskey', shortcut_key(preferences.btn_delete_row)); + + $el.find('#btn-filter') + .attr('title', shortcut_accesskey_title('Filter',preferences.btn_filter_dialog)) + .attr('accesskey', shortcut_key(preferences.btn_filter_dialog)); + + $el.find('#btn-filter-dropdown') + .attr('title', shortcut_accesskey_title('Filter options',preferences.btn_filter_options)) + .attr('accesskey', shortcut_key(preferences.btn_filter_options)); + + $el.find('#btn-rows-limit') + .attr('title', shortcut_accesskey_title('Rows limit',preferences.btn_rows_limit)) + .attr('accesskey', shortcut_key(preferences.btn_rows_limit)); + + $el.find('#btn-query-dropdown') + .attr('title', shortcut_accesskey_title('Execute options',preferences.btn_execute_options)) + .attr('accesskey', shortcut_key(preferences.btn_execute_options)); + + $el.find('#btn-cancel-query') + .attr('title', shortcut_accesskey_title('Cancel query',preferences.btn_cancel_query)) + .attr('accesskey', shortcut_key(preferences.btn_cancel_query)); + + $el.find('#btn-clear-dropdown') + .attr('title', shortcut_accesskey_title('Clear',preferences.btn_clear_options)) + .attr('accesskey', shortcut_key(preferences.btn_clear_options)); + + $el.find('#btn-conn-status') + .attr('accesskey', shortcut_key(preferences.btn_conn_status)) + .find('i') + .attr('title', + shortcut_accesskey_title('Connection status (click for details)', + preferences.btn_conn_status)); + + /* Accessed using ctrl,atl,shift and key */ + $el.find('#btn-flash') + .attr('title', + shortcut_title('Execute/Refresh',preferences.execute_query)); + + $el.find('#btn-flash-menu span') + .text(shortcut_title('Execute/Refresh',preferences.execute_query)); + + $el.find('#btn-explain span') + .text(shortcut_title('Explain',preferences.explain_query)); + + $el.find('#btn-explain-analyze span') + .text(shortcut_title('Explain Analyze',preferences.explain_analyze_query)); + + $el.find('#btn-download') + .attr('title', + shortcut_title('Download as CSV',preferences.download_csv)); + + /* Set Auto-commit and auto-rollback on query editor */ + if (preferences.auto_commit) { + $el.find('.auto-commit').removeClass('visibility-hidden'); + } + else { + $el.find('.auto-commit').addClass('visibility-hidden'); + } + if (preferences.auto_rollback) { + $el.find('.auto-rollback').removeClass('visibility-hidden'); + } + else { + $el.find('.auto-rollback').addClass('visibility-hidden'); + } + + /* Set explain options on query editor */ + if (preferences.explain_verbose){ + $el.find('.explain-verbose').removeClass('visibility-hidden'); + } + else { + $el.find('.explain-verbose').addClass('visibility-hidden'); + } + + if (preferences.explain_costs){ + $el.find('.explain-costs').removeClass('visibility-hidden'); + } + else { + $el.find('.explain-costs').addClass('visibility-hidden'); + } + + if (preferences.explain_buffers){ + $el.find('.explain-buffers').removeClass('visibility-hidden'); + } + else { + $el.find('.explain-buffers').addClass('visibility-hidden'); + } + + if (preferences.explain_timing) { + $el.find('.explain-timing').removeClass('visibility-hidden'); + } + else { + $el.find('.explain-timing').addClass('visibility-hidden'); + } + + /* Connection status check */ + /* remove the status checker if present */ + if(sqlEditor.connIntervalId != null) { + clearInterval(sqlEditor.connIntervalId); + sqlEditor.connIntervalId = null; + } + if (preferences.connection_status) { + let $conn_status = $el.find('#btn-conn-status'), + $status_el = $conn_status.find('i'); + $conn_status.popover(); + + $conn_status.removeClass('connection-status-hide'); + $el.find('.editor-title').addClass('editor-title-connection'); + + // To set initial connection + SqlEditorUtils.fetchConnectionStatus(sqlEditor.handler, $conn_status, $status_el); + + // Calling it again in specified interval + sqlEditor.connIntervalId = setInterval( + SqlEditorUtils.fetchConnectionStatus.bind(null, sqlEditor.handler, $conn_status, $status_el), + preferences.connection_status_fetch_time * 1000 + ); + } + else { + $el.find('#btn-conn-status').addClass('connection-status-hide'); + $el.find('.editor-title').removeClass('editor-title-connection'); + } + + /* Code Mirror Preferences */ + let sql_font_size = SqlEditorUtils.calcFontSize(preferences.sql_font_size); + $(sqlEditor.query_tool_obj.getWrapperElement()).css('font-size', sql_font_size); + + sqlEditor.query_tool_obj.setOption('indentWithTabs', !preferences.use_spaces); + sqlEditor.query_tool_obj.setOption('indentUnit', preferences.tab_size); + sqlEditor.query_tool_obj.setOption('tabSize', preferences.tab_size); + sqlEditor.query_tool_obj.setOption('lineWrapping', preferences.wrap_code); + sqlEditor.query_tool_obj.setOption('autoCloseBrackets', preferences.insert_pair_brackets); + sqlEditor.query_tool_obj.setOption('matchBrackets', preferences.brace_matching); + sqlEditor.query_tool_obj.refresh(); + + /* Render history to reflect Font size change */ + sqlEditor.render_history_grid(); +} + +export {reflectPreferences}; diff --git a/web/pgadmin/static/js/sqleditor_utils.js b/web/pgadmin/static/js/sqleditor_utils.js index be41566f..0fff1d95 100644 --- a/web/pgadmin/static/js/sqleditor_utils.js +++ b/web/pgadmin/static/js/sqleditor_utils.js @@ -178,24 +178,6 @@ define(['jquery', 'sources/gettext', 'sources/url_for'], }); }, - // This function will update the connection status - updateConnectionStatus: function(target, poll_time) { - var $el = $(target.gridView.$el.find('.connection_status')), - $status_el = $($el.find('.fa-custom')); - - // Apply popover on element - $el.popover(); - - // To set initial connection statussource$el.popover() - sqlEditorUtils.fetchConnectionStatus(target, $el, $status_el); - - // Calling it again in specified interval - setInterval( - sqlEditorUtils.fetchConnectionStatus.bind(null, target, $el, $status_el), - poll_time * 1000 - ); - }, - // Updates the flag for connection status poll updateConnectionStatusFlag: function(status) { var $el = $('.connection_status'); @@ -203,6 +185,15 @@ define(['jquery', 'sources/gettext', 'sources/url_for'], $el.data('panel-visible', status); } }, + + calcFontSize: function(fontSize) { + if(fontSize) { + return Number((Math.round(fontSize + 'e+2') + 'e-2')) + 'em'; + } + else { + return '0em'; + } + }, }; return sqlEditorUtils; }); diff --git a/web/pgadmin/static/jsx/history/detail/code_mirror.jsx b/web/pgadmin/static/jsx/history/detail/code_mirror.jsx index 6e982128..038cc200 100644 --- a/web/pgadmin/static/jsx/history/detail/code_mirror.jsx +++ b/web/pgadmin/static/jsx/history/detail/code_mirror.jsx @@ -50,6 +50,11 @@ export default class CodeMirror extends React.Component { Object.keys(props.options || {}).forEach(key => this.editor.setOption(key, props.options[key])); this.editor.setValue(props.value || ''); + + if(props.sqlFontSize) { + $(this.editor.getWrapperElement()).css('font-size', props.sqlFontSize); + } + this.editor.refresh(); } diff --git a/web/pgadmin/static/jsx/history/detail/history_detail_query.jsx b/web/pgadmin/static/jsx/history/detail/history_detail_query.jsx index dce34607..eae55dee 100644 --- a/web/pgadmin/static/jsx/history/detail/history_detail_query.jsx +++ b/web/pgadmin/static/jsx/history/detail/history_detail_query.jsx @@ -64,6 +64,7 @@ export default class HistoryDetailQuery extends React.Component { mode: 'text/x-pgsql', readOnly: true, }} + sqlFontSize= {this.props.sqlEditorPref.sql_font_size} /> </div>); } @@ -71,4 +72,5 @@ export default class HistoryDetailQuery extends React.Component { HistoryDetailQuery.propTypes = { historyEntry: Shapes.historyDetail, + sqlEditorPref: Shapes.sqlEditorPrefObj, }; diff --git a/web/pgadmin/static/jsx/history/query_history.jsx b/web/pgadmin/static/jsx/history/query_history.jsx index 3c07b5bd..8b5ffd2a 100644 --- a/web/pgadmin/static/jsx/history/query_history.jsx +++ b/web/pgadmin/static/jsx/history/query_history.jsx @@ -97,13 +97,16 @@ export default class QueryHistory extends React.Component { selectedEntry={this.state.selectedEntry} onSelectEntry={this.selectHistoryEntry} /> - <QueryHistoryDetail historyEntry={this.state.currentHistoryDetail}/> + <QueryHistoryDetail historyEntry={this.state.currentHistoryDetail} + sqlEditorPref={this.props.sqlEditorPref} + /> </SplitPane>); } } QueryHistory.propTypes = { historyCollection: Shapes.historyCollectionClass.isRequired, + sqlEditorPref: Shapes.sqlEditorPrefObj, }; export { diff --git a/web/pgadmin/static/jsx/react_shapes.jsx b/web/pgadmin/static/jsx/react_shapes.jsx index 454ab446..f8948b5f 100644 --- a/web/pgadmin/static/jsx/react_shapes.jsx +++ b/web/pgadmin/static/jsx/react_shapes.jsx @@ -25,7 +25,13 @@ let historyCollectionClass = onChange: PropTypes.func.isRequired, }); +let sqlEditorPrefObj = + PropTypes.shape({ + sql_font_size: PropTypes.string.isRequired, + }); + export default { historyDetail, historyCollectionClass, + sqlEditorPrefObj, }; diff --git a/web/pgadmin/tools/datagrid/__init__.py b/web/pgadmin/tools/datagrid/__init__.py index d3c3bf9c..04e2a683 100644 --- a/web/pgadmin/tools/datagrid/__init__.py +++ b/web/pgadmin/tools/datagrid/__init__.py @@ -24,12 +24,9 @@ from pgadmin.utils.ajax import make_json_response, bad_request, \ internal_server_error from config import PG_DEFAULT_DRIVER -from pgadmin.utils.preferences import Preferences from pgadmin.model import Server from pgadmin.utils.driver import get_driver from pgadmin.utils.exception import ConnectionLost, SSHTunnelConnectionLost -from pgadmin.tools.sqleditor.utils.query_tool_preferences import \ - get_query_tool_keyboard_shortcuts, get_text_representation_of_shortcut class DataGridModule(PgAdminModule): @@ -184,13 +181,9 @@ def initialize_datagrid(cmd_type, obj_type, sgid, sid, did, obj_id): # Store the grid dictionary into the session variable session['gridData'] = sql_grid_data - pref = Preferences.module('sqleditor') - new_browser_tab = pref.preference('new_browser_tab').get() - return make_json_response( data={ - 'gridTransId': trans_id, - 'newBrowserTab': new_browser_tab + 'gridTransId': trans_id } ) @@ -246,12 +239,6 @@ def panel(trans_id, is_query_tool, editor_title): if "linux" in _platform: is_linux_platform = True - pref = Preferences.module('sqleditor') - if pref.preference('new_browser_tab').get(): - new_browser_tab = 'true' - else: - new_browser_tab = 'false' - # Fetch the server details bgcolor = None fgcolor = None @@ -271,16 +258,10 @@ def panel(trans_id, is_query_tool, editor_title): url_params = dict() if is_query_tool == 'true': - prompt_save_changes = pref.preference( - 'prompt_save_query_changes' - ).get() url_params['sgid'] = trans_obj.sgid url_params['sid'] = trans_obj.sid url_params['did'] = trans_obj.did else: - prompt_save_changes = pref.preference( - 'prompt_save_data_changes' - ).get() url_params['cmd_type'] = trans_obj.cmd_type url_params['obj_type'] = trans_obj.object_type url_params['sgid'] = trans_obj.sgid @@ -288,9 +269,6 @@ def panel(trans_id, is_query_tool, editor_title): url_params['did'] = trans_obj.did url_params['obj_id'] = trans_obj.obj_id - display_connection_status = pref.preference('connection_status').get() - queryToolShortcuts = get_query_tool_keyboard_shortcuts() - return render_template( "datagrid/index.html", _=gettext, @@ -300,19 +278,11 @@ def panel(trans_id, is_query_tool, editor_title): script_type_url=sURL, is_desktop_mode=app.PGADMIN_RUNTIME, is_linux=is_linux_platform, - is_new_browser_tab=new_browser_tab, server_type=server_type, client_platform=user_agent.platform, bgcolor=bgcolor, fgcolor=fgcolor, - # convert python boolean value to equivalent js boolean literal - # before passing it to html template. - prompt_save_changes='true' if prompt_save_changes else 'false', - display_connection_status=display_connection_status, - url_params=json.dumps(url_params), - key=queryToolShortcuts.get('keys'), - shortcuts=queryToolShortcuts.get('shortcuts'), - get_shortcut_text=get_text_representation_of_shortcut + url_params=json.dumps(url_params) ) @@ -387,13 +357,9 @@ def initialize_query_tool(sgid, sid, did=None): # Store the grid dictionary into the session variable session['gridData'] = sql_grid_data - pref = Preferences.module('sqleditor') - new_browser_tab = pref.preference('new_browser_tab').get() - return make_json_response( data={ - 'gridTransId': trans_id, - 'newBrowserTab': new_browser_tab + 'gridTransId': trans_id } ) diff --git a/web/pgadmin/tools/datagrid/static/js/datagrid.js b/web/pgadmin/tools/datagrid/static/js/datagrid.js index c730b180..bc66ba6d 100644 --- a/web/pgadmin/tools/datagrid/static/js/datagrid.js +++ b/web/pgadmin/tools/datagrid/static/js/datagrid.js @@ -29,6 +29,23 @@ define('pgadmin.datagrid', [ this.initialized = true; this.title_index = 1; + /* Cache may take time to load for the first time + * Keep trying till available + */ + let cacheIntervalId = setInterval(()=> { + this.preferences = pgBrowser.get_preferences_for_module('sqleditor'); + if(this.preferences) { + clearInterval(cacheIntervalId); + } + }); + + + let self = this; + pgBrowser.onPreferencesChange('sqleditor', function() { + self.preferences = pgBrowser.get_preferences_for_module('sqleditor'); + }); + + this.spinner_el = '<div class="wcLoadingContainer">'+ '<div class="wcLoadingBackground"></div>'+ '<div class="wcLoadingIconContainer">'+ @@ -279,12 +296,12 @@ define('pgadmin.datagrid', [ lineNumbers: true, mode: 'text/x-pgsql', extraKeys: pgBrowser.editor_shortcut_keys, - indentWithTabs: pgAdmin.Browser.editor_options.indent_with_tabs, - indentUnit: pgAdmin.Browser.editor_options.tabSize, - tabSize: pgBrowser.editor_options.tabSize, - lineWrapping: pgAdmin.Browser.editor_options.wrapCode, - autoCloseBrackets: pgAdmin.Browser.editor_options.insert_pair_brackets, - matchBrackets: pgAdmin.Browser.editor_options.brace_matching, + indentWithTabs: !this.preferences.use_spaces, + indentUnit: this.preferences.tab_size, + tabSize: this.preferences.tab_size, + lineWrapping: this.preferences.wrap_code, + autoCloseBrackets: this.preferences.insert_pair_brackets, + matchBrackets: this.preferences.brace_matching, }); setTimeout(function() { @@ -415,13 +432,20 @@ define('pgadmin.datagrid', [ } } - if (trans_obj.newBrowserTab) { + if (this.preferences.new_browser_tab) { var newWin = window.open(baseUrl, '_blank'); // add a load listener to the window so that the title gets changed on page load newWin.addEventListener('load', function() { newWin.document.title = panel_title; + + /* Set the initial version of pref cache the new window is having + * This will be used by the poller to compare with window openers + * pref cache version + */ + newWin.pgAdmin.Browser.prefcache_version = pgBrowser.prefcache_version; }); + } else { /* On successfully initialization find the dashboard panel, * create new panel and add it to the dashboard panel. diff --git a/web/pgadmin/tools/datagrid/templates/datagrid/index.html b/web/pgadmin/tools/datagrid/templates/datagrid/index.html index ad090262..37187e45 100644 --- a/web/pgadmin/tools/datagrid/templates/datagrid/index.html +++ b/web/pgadmin/tools/datagrid/templates/datagrid/index.html @@ -10,13 +10,6 @@ .alertify .ajs-dialog.ajs-shake{-webkit-animation-name: none;} .sql-editor-busy-icon.fa-pulse{-webkit-animation: none;} {% endif %} - - {# Note: If we will display connection status then we have to provide some - space to display status icon else we can use all the space available #} - .editor-title { - width:{% if display_connection_status -%} calc(100% - 43px) - {% else %} 100% {%- endif %}; - } </style> <div id="main-editor_panel"> <div id="fetching_data" class="wcLoadingIconContainer sql-editor-busy-fetching hide"> @@ -28,14 +21,14 @@ <div id="btn-toolbar" class="pg-prop-btn-group bg-gray-2 border-gray-3" role="toolbar" aria-label=""> <div class="btn-group" role="group" aria-label=""> <button id="btn-load-file" type="button" class="btn btn-default btn-load-file" - title="{{ _('Open File') }}{{ _(' (accesskey+{0})'.format(key.open_file.upper())) }}" - accesskey="{{key.open_file}}" + title="" + accesskey="" tabindex="0"> <i class="fa fa-folder-open-o" aria-hidden="true"></i> </button> <button id="btn-save" type="button" class="btn btn-default" - title="{{ _('Save') }}{{ _(' (accesskey+{0})'.format(key.save_file.upper())) }}" - accesskey="{{key.save_file}}" + title="" + accesskey="" disabled> <i class="fa fa-floppy-o" aria-hidden="true" tabindex="0"></i> </button> @@ -63,8 +56,8 @@ </button> <button id="btn-find-menu-dropdown" type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" - title="{{ _('Find options') }}{{ _(' (accesskey+{0})'.format(key.find_options.upper())) }}" - accesskey="{{key.find_options}}" + title="" + accesskey="" tabindex="0"> <span class="caret"></span> <span class="sr-only">Toggle Dropdown</span> </button> @@ -122,22 +115,22 @@ </div> <div class="btn-group" role="group" aria-label=""> <button id="btn-copy-row" type="button" class="btn btn-default" - title="{{ _('Copy') }}{{ _(' (accesskey+{0})'.format(key.copy_row.upper())) }}" - accesskey="{{key.copy_row}}" + title="" + accesskey="" tabindex="0" disabled> <i class="fa fa-files-o" aria-hidden="true"></i> </button> <button id="btn-paste-row" type="button" class="btn btn-default" - title="{{ _('Paste') }}{{ _(' (accesskey+{0})'.format(key.paste_row.upper())) }}" - accesskey="{{key.paste_row}}" + title="" + accesskey="" tabindex="0" disabled> <i class="fa fa-clipboard" aria-hidden="true"></i> </button> </div> <div class="btn-group" role="group" aria-label=""> <button id="btn-delete-row" type="button" class="btn btn-default" - title="{{ _('Delete') }}{{ _(' (accesskey+{0})'.format(key.delete_row.upper())) }}" - accesskey="{{key.delete_row}}" + title="" + accesskey="" tabindex="0" disabled> <i class="fa fa-trash" aria-hidden="true"></i> </button> @@ -188,15 +181,15 @@ </div> <div class="btn-group" role="group" aria-label=""> <button id="btn-filter" type="button" class="btn btn-default" - title="{{ _('Filter') }}{{ _(' (accesskey+{0})'.format(key.filter_dialog.upper())) }}" - accesskey="{{key.filter_dialog}}" + title="" + accesskey="" tabindex="0" disabled> <i class="fa fa-filter" aria-hidden="true"></i> </button> <button id="btn-filter-dropdown" type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" - title="{{ _('Filter options') }}{{ _(' (accesskey+{0})'.format(key.filter_options.upper())) }}" - accesskey="{{key.filter_options}}" + title="" + accesskey="" disabled tabindex="0"> <span class="caret"></span> <span class="sr-only">{{ _('Toggle Dropdown') }}</span> </button> @@ -210,9 +203,9 @@ </ul> </div> <div class="btn-group" role="group" aria-label=""> - <select class="limit" style="height: 30px; width: 90px;" disabled - title="{{ _('Rows limit') }}{{ _(' (accesskey+{0})'.format(key.rows_limit.upper())) }}" - accesskey="{{key.rows_limit}}" + <select id="btn-rows-limit" class="limit" style="height: 30px; width: 90px;" disabled + title="" + accesskey="" tabindex="0"> <option value="-1">{{ _('No limit') }}</option> <option value="1000">{{ _('1000 rows') }}</option> @@ -223,31 +216,31 @@ <div class="btn-group" role="group" aria-label=""> <button id="btn-flash" data-test-selector="execute-refresh-button" type="button" class="btn btn-default" style="width: 40px;" - title="{{ _('Execute/Refresh') }}{{ _(' ({0})'.format(get_shortcut_text(shortcuts.execute_query))) }}" + title="" tabindex="0"> <i class="fa fa-bolt" aria-hidden="true"></i> </button> <button id="btn-query-dropdown" type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" - accesskey="{{key.execute_options}}" - title="{{ _('Execute options') }}{{ _(' (accesskey+{0})'.format(key.execute_options.upper())) }}" + accesskey="" + title="" tabindex="0"> <span class="caret"></span> <span class="sr-only">{{ _('Toggle Dropdown') }}</span> </button> <ul class="dropdown-menu" role="menu"> <li> <a id="btn-flash-menu" href="#" tabindex="0"> - <span>{{ _('Execute/Refresh') }}{{ _(' ({0})'.format(get_shortcut_text(shortcuts.execute_query))) }}</span> + <span></span> </a> </li> <li> <a id="btn-explain" href="#" tabindex="0"> - <span>{{ _('Explain') }}{{ _(' ({0})'.format(get_shortcut_text(shortcuts.explain_query))) }}</span> + <span></span> </a> </li> <li> <a id="btn-explain-analyze" href="#" tabindex="0"> - <span>{{ _('Explain Analyze') }}{{ _(' ({0})'.format(get_shortcut_text(shortcuts.explain_analyze_query))) }}</span> + <span></span> </a> </li> <li class="divider"></li> @@ -295,8 +288,8 @@ </li> </ul> <button id="btn-cancel-query" type="button" class="btn btn-default" - title="{{ _('Cancel query') }}{{ _(' (accesskey+{0})'.format(key.cancel_query.upper())) }}" - accesskey="{{key.cancel_query}}" + title="" + accesskey="" tabindex="0" disabled > <i class="fa fa-stop" aria-hidden="true"></i> </button> @@ -304,8 +297,8 @@ <div class="btn-group" role="group" aria-label=""> <button id="btn-clear-dropdown" type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" - title="{{ _('Clear') }}{{ _(' (accesskey+{0})'.format(key.clear_options.upper())) }}" - accesskey="{{key.clear_options}}" + title="" + accesskey="" tabindex="0"> <i class="fa fa-eraser" aria-hidden="true"></i> <span class="caret"></span> <span class="sr-only">{{ _('Toggle Dropdown') }}</span> @@ -325,7 +318,7 @@ </div> <div class="btn-group" role="group" aria-label=""> <button id="btn-download" type="button" class="btn btn-default" - title="{{ _('Download as CSV') }}{{ _(' ({0})'.format(get_shortcut_text(shortcuts.download_csv))) }}" + title="" tabindex="0"> <i class="fa fa-download" aria-hidden="true"></i> </button> @@ -333,21 +326,17 @@ </div> <div class="connection_status_wrapper"> - {% if display_connection_status %} - <div style="display: inline-block;" - title="{{ _('Connection status (click for details) (accesskey+{0})'.format(key.conn_status.upper())) }}"> - <div class="connection_status" data-container="body" - data-toggle="popover" data-placement="bottom" - data-content="" - data-panel-visible="visible" - accesskey="{{key.conn_status}}" - tabindex="0"> - <i class="fa-custom fa-query-tool-disconnected" aria-hidden="true" - title="{{ _('Connection status (click for details) (accesskey+{0})'.format(key.conn_status.upper())) }}"> - </i> - </div> + <div id="btn-conn-status" + class="connection_status connection-status-show" data-container="body" + data-toggle="popover" data-placement="bottom" + data-content="" + data-panel-visible="visible" + accesskey="" + tabindex="0"> + <i class="fa-custom fa-query-tool-disconnected" aria-hidden="true" + title=""> + </i> </div> - {% endif %} <div class="editor-title" style="background-color: {% if fgcolor %}{{ bgcolor or '#FFFFFF' }}{% else %}{{ bgcolor or '#2C76B4' }}{% endif %}; color: {{ fgcolor or 'white' }};"></div> </div> @@ -398,9 +387,7 @@ {{ is_query_tool }}, "{{ editor_title }}", script_type_url, - {{ is_new_browser_tab }}, "{{ server_type }}", - {{ prompt_save_changes }}, {{ url_params|safe}} ); }); diff --git a/web/pgadmin/tools/sqleditor/static/css/sqleditor.css b/web/pgadmin/tools/sqleditor/static/css/sqleditor.css index c54590d3..bd9b3091 100644 --- a/web/pgadmin/tools/sqleditor/static/css/sqleditor.css +++ b/web/pgadmin/tools/sqleditor/static/css/sqleditor.css @@ -625,3 +625,20 @@ input.editor-checkbox:focus { .data_sorting_dialog .data_sorting { padding: 10px 0px; } + +.editor-title { + width:100%; +} + +.editor-title-connection { + width:calc(100% - 43px); +} + +.connection-status-show { + display: inline-block; +} + +.connection-status-hide { + display: none; +} + diff --git a/web/pgadmin/tools/sqleditor/static/js/sqleditor.js b/web/pgadmin/tools/sqleditor/static/js/sqleditor.js index ce397692..6075de8b 100644 --- a/web/pgadmin/tools/sqleditor/static/js/sqleditor.js +++ b/web/pgadmin/tools/sqleditor/static/js/sqleditor.js @@ -16,7 +16,7 @@ define('tools.querytool', [ 'sources/sqleditor/query_tool_http_error_handler', 'sources/sqleditor/filter_dialog', 'sources/history/index.js', - 'sources/../jsx/history/query_history', + 'sourcesjsx/history/query_history', 'react', 'react-dom', 'sources/keyboard_shortcuts', 'sources/sqleditor/query_tool_actions', @@ -25,6 +25,7 @@ define('tools.querytool', [ 'sources/modify_animation', 'sources/sqleditor/calculate_query_run_time', 'sources/sqleditor/call_render_after_poll', + 'sources/sqleditor/query_tool_preferences', 'sources/../bundle/slickgrid', 'pgadmin.file_manager', 'backgrid.sizeable.columns', @@ -38,7 +39,7 @@ define('tools.querytool', [ XCellSelectionModel, setStagedRows, SqlEditorUtils, ExecuteQuery, httpErrorHandler, FilterHandler, HistoryBundle, queryHistory, React, ReactDOM, keyboardShortcuts, queryToolActions, queryToolNotifications, Datagrid, - modifyAnimation, calculateQueryRunTime, callRenderAfterPoll) { + modifyAnimation, calculateQueryRunTime, callRenderAfterPoll, queryToolPref) { /* Return back, this has been called more than once */ if (pgAdmin.SqlEditor) return pgAdmin.SqlEditor; @@ -58,6 +59,11 @@ define('tools.querytool', [ this.$el = opts.el; this.handler = opts.handler; this.handler['col_size'] = {}; + let browser = window.opener ? + window.opener.pgAdmin.Browser : window.top.pgAdmin.Browser; + this.preferences = browser.get_preferences_for_module('sqleditor'); + this.handler.preferences = this.preferences; + this.connIntervalId = null; }, // Bind all the events @@ -117,10 +123,6 @@ define('tools.querytool', [ var self = this; $('.editor-title').text(_.unescape(self.editor_title)); - self.checkConnectionStatus(); - - // Fetch and assign the shortcuts to current instance - self.keyboardShortcutConfig = queryToolActions.getKeyboardShortcuts(self); // Updates connection status flag self.gain_focus = function() { @@ -183,13 +185,7 @@ define('tools.querytool', [ }, gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'], extraKeys: pgBrowser.editor_shortcut_keys, - indentWithTabs: pgAdmin.Browser.editor_options.indent_with_tabs, - indentUnit: pgAdmin.Browser.editor_options.tabSize, - tabSize: pgAdmin.Browser.editor_options.tabSize, - lineWrapping: pgAdmin.Browser.editor_options.wrapCode, scrollbarStyle: 'simple', - autoCloseBrackets: pgAdmin.Browser.editor_options.insert_pair_brackets, - matchBrackets: pgAdmin.Browser.editor_options.brace_matching, }); // Refresh Code mirror on SQL panel resize to @@ -270,32 +266,32 @@ define('tools.querytool', [ self.render_history_grid(); queryToolNotifications.renderNotificationsGrid(self.notifications_panel); - if (!self.handler.is_new_browser_tab) { + if (!self.preferences.new_browser_tab) { // Listen on the panel closed event and notify user to save modifications. _.each(window.top.pgAdmin.Browser.docker.findPanels('frm_datagrid'), function(p) { if (p.isVisible()) { - if (self.handler.prompt_save_changes) { - p.on(wcDocker.EVENT.CLOSING, function() { - // Only if we can edit data then perform this check - var notify = false, - msg; - if (self.handler.can_edit) { - var data_store = self.handler.data_store; - if (data_store && (_.size(data_store.added) || - _.size(data_store.updated))) { - msg = gettext('The data has changed. Do you want to save changes?'); - notify = true; - } - } else if (self.handler.is_query_tool && self.handler.is_query_changed) { - msg = gettext('The text has changed. Do you want to save changes?'); + p.on(wcDocker.EVENT.CLOSING, function() { + // Only if we can edit data then perform this check + var notify = false, + msg; + if (self.handler.can_edit + && self.preferences.prompt_save_data_changes) { + var data_store = self.handler.data_store; + if (data_store && (_.size(data_store.added) || + _.size(data_store.updated))) { + msg = gettext('The data has changed. Do you want to save changes?'); notify = true; } - if (notify) { - return self.user_confirmation(p, msg); - } - return true; - }); - } + } else if (self.handler.is_query_tool && self.handler.is_query_changed + && self.preferences.prompt_save_query_changes) { + msg = gettext('The text has changed. Do you want to save changes?'); + notify = true; + } + if (notify) { + return self.user_confirmation(p, msg); + } + return true; + }); // Set focus on query tool of active panel p.on(wcDocker.EVENT.GAIN_FOCUS, function() { @@ -483,33 +479,35 @@ define('tools.querytool', [ }.bind(ctx), }; }); - }, - // This function will check the connection status at specific - // interval defined by the user in preference - checkConnectionStatus: function() { - var self = this, - preference = window.top.pgAdmin.Browser.get_preference( - 'sqleditor', 'connection_status_fetch_time' - ), - display_status = window.top.pgAdmin.Browser.get_preference( - 'sqleditor', 'connection_status' - ); - if(!preference && self.handler.is_new_browser_tab) { - preference = window.opener.pgAdmin.Browser.get_preference( - 'sqleditor', 'connection_status_fetch_time' - ); - display_status = window.opener.pgAdmin.Browser.get_preference( - 'sqleditor', 'connection_status' - ); - } - // Only enable pooling if it is enabled - if (display_status && display_status.value) { - SqlEditorUtils.updateConnectionStatus( - self.handler, - preference.value - ); + queryToolPref.reflectPreferences(self); + /* Register for preference changed event broadcasted in parent + * to reload the shorcuts. As sqleditor is in iFrame of wcDocker + * window parent is referred + */ + pgBrowser.onPreferencesChange('sqleditor', function() { + let browser = window.opener ? + window.opener.pgAdmin.Browser : window.top.pgAdmin.Browser; + self.preferences = browser.get_preferences_for_module('sqleditor'); + self.handler.preferences = self.preferences; + queryToolPref.reflectPreferences(self); + }); + + /* If sql editor is in a new tab, event fired is not available + * instead, a poller is set up who will check if the window.opener + * prefcache_version is updated. If updated, the new tab will update its + * preferences and reflect it + */ + if(self.preferences.new_browser_tab) { + setInterval(()=>{ + if(window.opener.pgAdmin && + pgBrowser.prefcache_version < window.opener.pgAdmin.Browser.prefcache_version) + { + pgBrowser.prefcache_version = window.opener.pgAdmin.Browser.prefcache_version; + self.reflectPreferences(); + } + }, 1000); } }, @@ -805,6 +803,11 @@ define('tools.querytool', [ }; self.handler.slickgrid = grid; + self.handler.slickgrid.CSVOptions = { + quoting: self.preferences.results_grid_quoting, + quote_char: self.preferences.results_grid_quote_char, + field_separator: self.preferences.results_grid_field_separator, + }; // Listener function to watch selected rows from grid if (editor_data.selection) { @@ -903,29 +906,6 @@ define('tools.querytool', [ handleQueryOutputKeyboardEvent(event, args); }); } else { - var pref_cache = undefined; - args.grid.CSVOptions = {}; - - if (self.handler.is_new_browser_tab) { - pref_cache = window.opener.pgAdmin.Browser.preferences_cache; - } else { - pref_cache = window.top.pgAdmin.Browser.preferences_cache; - } - - // Get CSV options from preferences cache - args.grid.CSVOptions.quoting = _.findWhere(pref_cache, { - 'module': 'sqleditor', - 'name': 'results_grid_quoting', - }).value; - args.grid.CSVOptions.quote_char = _.findWhere(pref_cache, { - 'module': 'sqleditor', - 'name': 'results_grid_quote_char', - }).value; - args.grid.CSVOptions.field_separator = _.findWhere(pref_cache, { - 'module': 'sqleditor', - 'name': 'results_grid_field_separator', - }).value; - handleQueryOutputKeyboardEvent(event, args); } }); @@ -1196,7 +1176,10 @@ define('tools.querytool', [ render_history_grid: function() { var self = this; - self.history_collection = new HistoryBundle.HistoryCollection([]); + /* Should not reset if function called again */ + if(!self.history_collection) { + self.history_collection = new HistoryBundle.HistoryCollection([]); + } var historyComponent; var historyCollectionReactElement = React.createElement( @@ -1205,9 +1188,13 @@ define('tools.querytool', [ ref: function(component) { historyComponent = component; }, + sqlEditorPref: { + sql_font_size: SqlEditorUtils.calcFontSize(this.preferences.sql_font_size), + }, }); ReactDOM.render(historyCollectionReactElement, $('#history_grid')[0]); + self.history_panel.off(wcDocker.EVENT.VISIBILITY_CHANGED); self.history_panel.on(wcDocker.EVENT.VISIBILITY_CHANGED, function() { historyComponent.refocus(); }); @@ -1416,29 +1403,7 @@ define('tools.querytool', [ // Callback function for copy button click. on_copy_row: function() { - var self = this, - pref_cache = undefined; - self.grid.CSVOptions = {}; - - if (self.handler.is_new_browser_tab) { - pref_cache = window.opener.pgAdmin.Browser.preferences_cache; - } else { - pref_cache = window.top.pgAdmin.Browser.preferences_cache; - } - - // Get CSV options from preferences cache - self.grid.CSVOptions.quoting = _.findWhere(pref_cache, { - 'module': 'sqleditor', - 'name': 'results_grid_quoting', - }).value; - self.grid.CSVOptions.quote_char = _.findWhere(pref_cache, { - 'module': 'sqleditor', - 'name': 'results_grid_quote_char', - }).value; - self.grid.CSVOptions.field_separator = _.findWhere(pref_cache, { - 'module': 'sqleditor', - 'name': 'results_grid_field_separator', - }).value; + var self = this; // Trigger the copy signal to the SqlEditorController class self.handler.trigger( @@ -1708,7 +1673,7 @@ define('tools.querytool', [ keyAction: function(event) { var panel_id, self = this; panel_id = keyboardShortcuts.processEventQueryTool( - this.handler, this.keyboardShortcutConfig, queryToolActions, event + this.handler, queryToolActions, event ); // If it return panel id then focus it @@ -1933,23 +1898,17 @@ define('tools.querytool', [ * header and loading icon and start execution of the sql query. */ start: function(transId, is_query_tool, editor_title, script_type_url, - is_new_browser_tab, server_type, prompt_save_changes, url_params + server_type, url_params ) { var self = this; self.is_query_tool = is_query_tool; self.rows_affected = 0; self.marked_line_no = 0; - self.explain_verbose = false; - self.explain_costs = false; - self.explain_buffers = false; - self.explain_timing = false; - self.is_new_browser_tab = is_new_browser_tab; self.has_more_rows = false; self.fetching_rows = false; self.close_on_save = false; self.server_type = server_type; - self.prompt_save_changes = prompt_save_changes; self.url_params = url_params; self.script_type_url = script_type_url; @@ -2022,7 +1981,6 @@ define('tools.querytool', [ // Listen to the codemirror on text change event // only in query editor tool if (self.is_query_tool) { - self.get_preferences(); self.gridView.query_tool_obj.on('change', self._on_query_change.bind(self)); } @@ -2830,7 +2788,7 @@ define('tools.querytool', [ setTitle: function(title, unsafe) { var self = this; - if (self.is_new_browser_tab) { + if (self.preferences.new_browser_tab) { window.document.title = title; } else { _.each(window.top.pgAdmin.Browser.docker.findPanels('frm_datagrid'), function(p) { @@ -2992,7 +2950,7 @@ define('tools.querytool', [ var title = self.gridView.current_file.replace(/^.*[\\\/]/g, '') + ' *'; self.setTitle(title, true); } else { - if (self.is_new_browser_tab) { + if (self.preferences.new_browser_tab) { title = window.document.title + ' *'; } else { // Find the title of the visible panel @@ -3570,22 +3528,8 @@ define('tools.querytool', [ }); }, - // This function will toggle "verbose" option in explain - _explain_verbose: function() { - var self = this; - if ($('.explain-verbose').hasClass('visibility-hidden') === true) { - $('.explain-verbose').removeClass('visibility-hidden'); - self.explain_verbose = true; - } else { - $('.explain-verbose').addClass('visibility-hidden'); - self.explain_verbose = false; - } - - // Set this option in preferences - var data = { - 'explain_verbose': self.explain_verbose, - }; - + explainPreferenceUpdate: function(subItem, data, caller) { + let self = this; $.ajax({ url: url_for('sqleditor.query_tool_preferences', { 'trans_id': self.transId, @@ -3596,133 +3540,94 @@ define('tools.querytool', [ success: function(res) { if (res.success == undefined || !res.success) { alertify.alert(gettext('Explain options error'), - gettext('Error occurred while setting verbose option in explain.') + gettext('Error occurred while setting %(subItem)s option in explain.', + {subItem : subItem}) ); } }, error: function(e) { let msg = httpErrorHandler.handleQueryToolAjaxError( - pgAdmin, self, e, '_explain_verbose', [], true + pgAdmin, self, e, caller, [], true ); alertify.alert(gettext('Explain options error'), msg); }, }); }, + // This function will toggle "verbose" option in explain + _explain_verbose: function() { + var self = this; + let explain_verbose = false; + if ($('.explain-verbose').hasClass('visibility-hidden') === true) { + $('.explain-verbose').removeClass('visibility-hidden'); + explain_verbose = true; + } else { + $('.explain-verbose').addClass('visibility-hidden'); + explain_verbose = false; + } + + self.explainPreferenceUpdate( + 'verbose', { + 'explain_verbose': explain_verbose, + }, '_explain_verbose' + ); + }, + // This function will toggle "costs" option in explain _explain_costs: function() { var self = this; + let explain_costs = false; if ($('.explain-costs').hasClass('visibility-hidden') === true) { $('.explain-costs').removeClass('visibility-hidden'); - self.explain_costs = true; + explain_costs = true; } else { $('.explain-costs').addClass('visibility-hidden'); - self.explain_costs = false; + explain_costs = false; } - // Set this option in preferences - var data = { - 'explain_costs': self.explain_costs, - }; - - $.ajax({ - url: url_for('sqleditor.query_tool_preferences', { - 'trans_id': self.transId, - }), - method: 'PUT', - contentType: 'application/json', - data: JSON.stringify(data), - success: function(res) { - if (res.success == undefined || !res.success) { - alertify.alert(gettext('Explain options error'), - gettext('Error occurred while setting costs option in explain.') - ); - } - }, - error: function(e) { - let msg = httpErrorHandler.handleQueryToolAjaxError( - pgAdmin, self, e, '_explain_costs', [], true - ); - alertify.alert(gettext('Explain options error'), msg); - }, - }); + self.explainPreferenceUpdate( + 'costs', { + 'explain_costs': explain_costs, + }, '_explain_costs' + ); }, // This function will toggle "buffers" option in explain _explain_buffers: function() { var self = this; + let explain_buffers = false; if ($('.explain-buffers').hasClass('visibility-hidden') === true) { $('.explain-buffers').removeClass('visibility-hidden'); - self.explain_buffers = true; + explain_buffers = true; } else { $('.explain-buffers').addClass('visibility-hidden'); - self.explain_buffers = false; + explain_buffers = false; } - // Set this option in preferences - var data = { - 'explain_buffers': self.explain_buffers, - }; - - $.ajax({ - url: url_for('sqleditor.query_tool_preferences', { - 'trans_id': self.transId, - }), - method: 'PUT', - contentType: 'application/json', - data: JSON.stringify(data), - success: function(res) { - if (res.success == undefined || !res.success) { - alertify.alert(gettext('Explain options error'), - gettext('Error occurred while setting buffers option in explain.') - ); - } - }, - error: function(e) { - let msg = httpErrorHandler.handleQueryToolAjaxError( - pgAdmin, self, e, '_explain_buffers', [], true - ); - alertify.alert(gettext('Explain options error'), msg); - }, - }); + self.explainPreferenceUpdate( + 'buffers', { + 'explain_buffers': explain_buffers, + }, '_explain_buffers' + ); }, // This function will toggle "timing" option in explain _explain_timing: function() { var self = this; + let explain_timing = false; if ($('.explain-timing').hasClass('visibility-hidden') === true) { $('.explain-timing').removeClass('visibility-hidden'); - self.explain_timing = true; + explain_timing = true; } else { $('.explain-timing').addClass('visibility-hidden'); - self.explain_timing = false; + explain_timing = false; } - // Set this option in preferences - var data = { - 'explain_timing': self.explain_timing, - }; - $.ajax({ - url: url_for('sqleditor.query_tool_preferences', { - 'trans_id': self.transId, - }), - method: 'PUT', - contentType: 'application/json', - data: JSON.stringify(data), - success: function(res) { - if (res.success == undefined || !res.success) { - alertify.alert(gettext('Explain options error'), - gettext('Error occurred while setting timing option in explain.') - ); - } - }, - error: function(e) { - let msg = httpErrorHandler.handleQueryToolAjaxError( - pgAdmin, self, e, '_explain_timing', [], true - ); - alertify.alert(gettext('Explain options error'), msg); - }, - }); + self.explainPreferenceUpdate( + 'timing', { + 'explain_timing': explain_timing, + }, '_explain_timing' + ); }, /* @@ -3751,85 +3656,6 @@ define('tools.querytool', [ is_query_running = value; }, - /* - * This function get explain options and auto rollback/auto commit - * values from preferences - */ - get_preferences: function() { - var self = this, - explain_verbose = false, - explain_costs = false, - explain_buffers = false, - explain_timing = false, - auto_commit = true, - auto_rollback = false, - updateUI = function() { - // Set Auto-commit and auto-rollback on query editor - if (auto_commit && - $('.auto-commit').hasClass('visibility-hidden') === true) - $('.auto-commit').removeClass('visibility-hidden'); - else { - $('.auto-commit').addClass('visibility-hidden'); - } - if (auto_rollback && - $('.auto-rollback').hasClass('visibility-hidden') === true) - $('.auto-rollback').removeClass('visibility-hidden'); - else { - $('.auto-rollback').addClass('visibility-hidden'); - } - - // Set explain options on query editor - if (explain_verbose && - $('.explain-verbose').hasClass('visibility-hidden') === true) - $('.explain-verbose').removeClass('visibility-hidden'); - else { - $('.explain-verbose').addClass('visibility-hidden'); - } - if (explain_costs && - $('.explain-costs').hasClass('visibility-hidden') === true) - $('.explain-costs').removeClass('visibility-hidden'); - else { - $('.explain-costs').addClass('visibility-hidden'); - } - if (explain_buffers && - $('.explain-buffers').hasClass('visibility-hidden') === true) - $('.explain-buffers').removeClass('visibility-hidden'); - else { - $('.explain-buffers').addClass('visibility-hidden'); - } - if (explain_timing && - $('.explain-timing').hasClass('visibility-hidden') === true) - $('.explain-timing').removeClass('visibility-hidden'); - else { - $('.explain-timing').addClass('visibility-hidden'); - } - }; - - $.ajax({ - url: url_for('sqleditor.query_tool_preferences', { - 'trans_id': self.transId, - }), - method: 'GET', - success: function(res) { - if (res.data) { - explain_verbose = res.data.explain_verbose; - explain_costs = res.data.explain_costs; - explain_buffers = res.data.explain_buffers; - explain_timing = res.data.explain_timing; - auto_commit = res.data.auto_commit; - auto_rollback = res.data.auto_rollback; - updateUI(); - } - }, - error: function(e) { - let msg = httpErrorHandler.handleQueryToolAjaxError( - pgAdmin, self, e, 'get_preferences', [], true - ); - updateUI(); - alertify.alert(gettext('Get Preferences error'), msg); - }, - }); - }, close: function() { var self = this; diff --git a/web/pgadmin/tools/sqleditor/tests/test_pref_utilities.py b/web/pgadmin/tools/sqleditor/tests/test_pref_utilities.py deleted file mode 100644 index cbd141b0..00000000 --- a/web/pgadmin/tools/sqleditor/tests/test_pref_utilities.py +++ /dev/null @@ -1,100 +0,0 @@ -########################################################################## -# -# pgAdmin 4 - PostgreSQL Tools -# -# Copyright (C) 2013 - 2018, The pgAdmin Development Team -# This software is released under the PostgreSQL Licence -# -########################################################################## -from pgadmin.utils.route import BaseTestGenerator -from pgadmin.tools.sqleditor.utils.query_tool_preferences import \ - get_text_representation_of_shortcut - - -class TestQueryToolPreference(BaseTestGenerator): - """ - Ensures that we are able to fetch preferences properly - """ - scenarios = [ - ('Check text representation of a valid shortcuts', dict( - fetch_pref=True, - sample_shortcut=dict( - alt=False, - shift=False, - control=False, - key=dict( - char='a', - keyCode=65 - ) - ), - expected_result='a' - )), - - ('Check text representation of a valid shortcuts', dict( - fetch_pref=True, - sample_shortcut=dict( - alt=True, - shift=False, - control=False, - key=dict( - char='a', - keyCode=65 - ) - ), - expected_result='Alt+a' - )), - - ('Check text representation of a valid shortcuts', dict( - fetch_pref=True, - sample_shortcut=dict( - alt=True, - shift=True, - control=True, - key=dict( - char='a', - keyCode=65 - ) - ), - expected_result='Alt+Shift+Ctrl+a' - )), - - ('Check text representation of a valid shortcuts', dict( - fetch_pref=True, - sample_shortcut=dict( - alt=False, - shift=True, - control=False, - key=dict( - char='a', - keyCode=65 - ) - ), - expected_result='Shift+a' - )), - - ('Check text representation of a valid shortcuts', dict( - fetch_pref=True, - sample_shortcut=dict( - alt=True, - shift=True, - control=False, - key=dict( - char='a', - keyCode=65 - ) - ), - expected_result='Alt+Shift+a' - )), - - ('Check text representation of a invalid shortcuts', dict( - fetch_pref=True, - sample_shortcut=None, - expected_result='' - )) - - ] - - def runTest(self): - """Check correct function is called to handle to run query.""" - result = get_text_representation_of_shortcut(self.sample_shortcut) - self.assertEquals(result, self.expected_result) diff --git a/web/pgadmin/tools/sqleditor/utils/query_tool_preferences.py b/web/pgadmin/tools/sqleditor/utils/query_tool_preferences.py index a5a7bcb8..5e2a8ef1 100644 --- a/web/pgadmin/tools/sqleditor/utils/query_tool_preferences.py +++ b/web/pgadmin/tools/sqleditor/utils/query_tool_preferences.py @@ -560,123 +560,3 @@ def RegisterQueryToolPreferences(self): help_str=gettext('If set to True, Keywords will be displayed ' 'in upper case for auto completion.') ) - - -def get_query_tool_keyboard_shortcuts(): - - """ - Fetch all the query tool shortcut preferences - - Returns: - List of query tool shortcut preferences - """ - qt_perf = Preferences.module('sqleditor') - conn_status = qt_perf.preference('btn_conn_status').get() - clear_options = qt_perf.preference('btn_clear_options').get() - cancel_query = qt_perf.preference('btn_cancel_query').get() - execute_options = qt_perf.preference('btn_execute_options').get() - filter_options = qt_perf.preference('btn_filter_options').get() - rows_limit = qt_perf.preference('btn_rows_limit').get() - filter_dialog = qt_perf.preference('btn_filter_dialog').get() - delete_row = qt_perf.preference('btn_delete_row').get() - paste_row = qt_perf.preference('btn_paste_row').get() - copy_row = qt_perf.preference('btn_copy_row').get() - save_file = qt_perf.preference('btn_save_file').get() - open_file = qt_perf.preference('btn_open_file').get() - move_next = qt_perf.preference('move_next').get() - move_previous = qt_perf.preference('move_previous').get() - download_csv = qt_perf.preference('download_csv').get() - execute_query = qt_perf.preference('execute_query').get() - explain_query = qt_perf.preference('explain_query').get() - explain_analyze_query = qt_perf.preference('explain_analyze_query').get() - find_options = qt_perf.preference('btn_find_options').get() - toggle_case = qt_perf.preference('toggle_case').get() - - return { - 'keys': { - 'conn_status': conn_status.get('key').get('char'), - 'clear_options': clear_options.get('key').get('char'), - 'cancel_query': cancel_query.get('key').get('char'), - 'execute_options': execute_options.get('key').get('char'), - 'filter_options': filter_options.get('key').get('char'), - 'rows_limit': rows_limit.get('key').get('char'), - 'filter_dialog': filter_dialog.get('key').get('char'), - 'delete_row': delete_row.get('key').get('char'), - 'paste_row': paste_row.get('key').get('char'), - 'copy_row': copy_row.get('key').get('char'), - 'save_file': save_file.get('key').get('char'), - 'open_file': open_file.get('key').get('char'), - 'move_next': move_next.get('key').get('char'), - 'move_previous': move_previous.get('key').get('char'), - 'download_csv': download_csv.get('key').get('char'), - 'execute_query': execute_query.get('key').get('char'), - 'explain_query': explain_query.get('key').get('char'), - 'explain_analyze_query': explain_analyze_query.get('key').get( - 'char' - ), - 'find_options': find_options.get('key').get('char'), - 'toggle_case': toggle_case.get('key').get('char') - }, - 'shortcuts': { - 'conn_status': conn_status, - 'clear_options': clear_options, - 'cancel_query': cancel_query, - 'execute_options': execute_options, - 'filter_options': filter_options, - 'rows_limit': rows_limit, - 'filter_dialog': filter_dialog, - 'delete_row': delete_row, - 'paste_row': paste_row, - 'copy_row': copy_row, - 'save_file': save_file, - 'open_file': open_file, - 'move_next': move_next, - 'move_previous': move_previous, - 'download_csv': download_csv, - 'execute_query': execute_query, - 'explain_query': explain_query, - 'explain_analyze_query': explain_analyze_query, - 'find_options': find_options, - 'toggle_case': toggle_case - }, - } - - -def get_text_representation_of_shortcut(shortcut): - """ - Coverts shortcut object to text representation - - Args: - shortcut: Shortcut object - - Returns: - Text representation of given shortcut - """ - text_representation = '' - is_plus_required = False - - if not shortcut: - return text_representation - - if shortcut['alt']: - text_representation = gettext('Alt') - is_plus_required = True - - if shortcut['shift']: - if is_plus_required: - text_representation += '+' - text_representation += gettext('Shift') - is_plus_required = True - - if shortcut['control']: - if is_plus_required: - text_representation += '+' - text_representation += gettext('Ctrl') - is_plus_required = True - - if shortcut['key'] and shortcut['key']['char']: - if is_plus_required: - text_representation += '+' - text_representation += '{0}'.format(shortcut['key']['char']) - - return text_representation diff --git a/web/regression/javascript/browser/preferences_spec.js b/web/regression/javascript/browser/preferences_spec.js new file mode 100644 index 00000000..956b2c36 --- /dev/null +++ b/web/regression/javascript/browser/preferences_spec.js @@ -0,0 +1,140 @@ +import {pgBrowser} from 'pgadmin.browser.preferences'; +import $ from 'jquery'; + +var dummy_cache = [ + { + id: 1, + mid: 1, + module:'module1', + name:'pref1', + value:{ + alt: false, + shift: false, + control: false, + key: { + char: 'a', + key_code: 65, + }, + }, + },{ + id: 2, + mid: 1, + module:'module1', + name:'pref2', + value: 123, + },{ + id: 3, + mid: 2, + module:'module2', + name:'pref2', + value: true, + }, +]; + +describe('preferences related functions test', function() { + describe('get preference data related functions', function(){ + beforeEach(function(){ + pgBrowser.preferences_cache = dummy_cache; + }); + + it('get_preference', function(){ + expect(pgBrowser.get_preference('module1','pref1')).toEqual({ + id: 1, + mid: 1, + module:'module1', + name:'pref1', + value:{ + alt: false, + shift: false, + control: false, + key: { + char: 'a', + key_code: 65, + }, + }, + }); + }); + + it('get_preferences_for_module', function() { + expect(pgBrowser.get_preferences_for_module('module1')).toEqual({ + 'pref1':{ + alt: false, + shift: false, + control: false, + key: { + char: 'a', + key_code: 65, + }, + }, + 'pref2': 123, + }); + }); + + it('get_preference_for_id', function() { + expect(pgBrowser.get_preference_for_id(3)).toEqual({ + id: 3, + mid: 2, + module:'module2', + name:'pref2', + value: true, + }); + }); + + it('reflectPreferences', function() { + + let editorOptions = { + 'tabSize':2, + 'lineWrapping':false, + 'autoCloseBrackets':true, + 'matchBrackets':true, + }; + pgBrowser.preferences_cache.push({ + id: 4, mid: 3, module:'sqleditor', name:'sql_font_size', value: 1.456, + }); + pgBrowser.preferences_cache.push({ + id: 4, mid: 3, module:'sqleditor', name:'tab_size', value: editorOptions.tabSize, + }); + pgBrowser.preferences_cache.push({ + id: 4, mid: 3, module:'sqleditor', name:'wrap_code', value: editorOptions.lineWrapping, + }); + pgBrowser.preferences_cache.push({ + id: 4, mid: 3, module:'sqleditor', name:'insert_pair_brackets', value: editorOptions.autoCloseBrackets, + }); + pgBrowser.preferences_cache.push({ + id: 4, mid: 3, module:'sqleditor', name:'brace_matching', value: editorOptions.matchBrackets, + }); + + /* Spies */ + pgBrowser.editor = jasmine.createSpyObj( + 'CodeMirror', ['setOption','refresh','getWrapperElement'] + ); + spyOn($.fn, 'css'); + + /* Call */ + pgBrowser.reflectPreferences(); + + /* Tests */ + expect(pgBrowser.editor.getWrapperElement).toHaveBeenCalled(); + expect($.fn.css).toHaveBeenCalledWith('font-size', '1.46em'); + + let setOptionCalls = pgBrowser.editor.setOption.calls; + expect(setOptionCalls.count()).toBe(Object.keys(editorOptions).length); + + for(let i = 0; i < Object.keys(editorOptions).length; i++) { + let option = Object.keys(editorOptions)[i]; + expect(setOptionCalls.argsFor(i)).toEqual([option, editorOptions[option]]); + } + expect(pgBrowser.editor.refresh).toHaveBeenCalled(); + }); + + it('onPreferencesChange', function() { + + window.parent.$ = $; + spyOn($.fn, 'on'); + + var eventHandler = jasmine.createSpy('eventHandler'); + pgBrowser.onPreferencesChange('somemodule', eventHandler); + expect($.fn.on.calls.mostRecent().args[0]).toEqual('prefchange:somemodule'); + }); + }); +}); diff --git a/web/regression/javascript/history/query_history_spec.jsx b/web/regression/javascript/history/query_history_spec.jsx index c49b19f0..b90d2a30 100644 --- a/web/regression/javascript/history/query_history_spec.jsx +++ b/web/regression/javascript/history/query_history_spec.jsx @@ -29,7 +29,7 @@ import '../helper/enzyme.helper'; describe('QueryHistory', () => { let historyCollection; let historyWrapper; - + let sqlEditorPref = {sql_font_size: '1em'}; beforeEach(() => { jasmineEnzyme(); }); @@ -37,7 +37,9 @@ describe('QueryHistory', () => { describe('when there is no history', () => { beforeEach(() => { historyCollection = new HistoryCollection([]); - historyWrapper = mount(<QueryHistory historyCollection={historyCollection}/>); + historyWrapper = mount(<QueryHistory historyCollection={historyCollection} + sqlEditorPref={sqlEditorPref} + />); }); describe('when we switch to the query history tab', () => { @@ -89,8 +91,9 @@ describe('QueryHistory', () => { message: 'something important ERROR: message from second sql query', }]; historyCollection = new HistoryCollection(historyObjects); - - historyWrapper = mount(<QueryHistory historyCollection={historyCollection}/>); + historyWrapper = mount(<QueryHistory historyCollection={historyCollection} + sqlEditorPref={sqlEditorPref} + />); queryHistoryEntriesComponent = historyWrapper.find(QueryHistoryEntries); isInvisibleSpy = spyOn(queryHistoryEntriesComponent.instance(), 'isInvisible') @@ -479,7 +482,9 @@ describe('QueryHistory', () => { }]; historyCollection = new HistoryCollection(historyObjects); - historyWrapper = mount(<QueryHistory historyCollection={historyCollection}/>); + historyWrapper = mount(<QueryHistory historyCollection={historyCollection} + sqlEditorPref={sqlEditorPref} + />); const queryHistoryEntriesComponent = historyWrapper.find(QueryHistoryEntries); isInvisibleSpy = spyOn(queryHistoryEntriesComponent.instance(), 'isInvisible') diff --git a/web/regression/javascript/sqleditor/keyboard_shortcuts_spec.js b/web/regression/javascript/sqleditor/keyboard_shortcuts_spec.js index 06586d34..0e774814 100644 --- a/web/regression/javascript/sqleditor/keyboard_shortcuts_spec.js +++ b/web/regression/javascript/sqleditor/keyboard_shortcuts_spec.js @@ -9,6 +9,7 @@ import keyboardShortcuts from 'sources/keyboard_shortcuts'; import {queryToolActions} from 'sources/sqleditor/query_tool_actions'; +import gettext from 'sources/gettext'; describe('the keyboard shortcuts', () => { const F1_KEY = 112, @@ -18,7 +19,7 @@ describe('the keyboard shortcuts', () => { PERIOD_KEY = 190, FWD_SLASH_KEY = 191; - let sqlEditorControllerSpy, event, queryToolActionsSpy, queryToolkeyboardShortcutsConfig; + let sqlEditorControllerSpy, event, queryToolActionsSpy; beforeEach(() => { event = { shift: false, @@ -29,8 +30,22 @@ describe('the keyboard shortcuts', () => { stopImmediatePropagation: jasmine.createSpy('stopImmediatePropagation'), }; - queryToolkeyboardShortcutsConfig = { - execute: { + let gridView = { + query_tool_obj: { + getSelection: jasmine.createSpy('getSelection'), + getValue: jasmine.createSpy('getValue'), + }, + }; + + sqlEditorControllerSpy = jasmine.createSpyObj('SqlEditorController', [ + 'isQueryRunning', + 'execute', + ]); + + sqlEditorControllerSpy.gridView = gridView; + + sqlEditorControllerSpy.preferences = { + execute_query: { alt: false, shift: false, control: false, @@ -38,7 +53,7 @@ describe('the keyboard shortcuts', () => { key_code: F5_KEY, }, }, - explain: { + explain_query: { alt: false, shift: false, control: false, @@ -46,7 +61,7 @@ describe('the keyboard shortcuts', () => { key_code: F7_KEY, }, }, - explain_analyze: { + explain_analyze_query: { alt: false, shift: true, control: false, @@ -80,20 +95,6 @@ describe('the keyboard shortcuts', () => { }, }; - let gridView = { - query_tool_obj: { - getSelection: jasmine.createSpy('getSelection'), - getValue: jasmine.createSpy('getValue'), - }, - }; - - sqlEditorControllerSpy = jasmine.createSpyObj('SqlEditorController', [ - 'isQueryRunning', - 'execute', - ]); - - sqlEditorControllerSpy.gridView = gridView; - queryToolActionsSpy = jasmine.createSpyObj(queryToolActions, [ 'explainAnalyze', 'explain', @@ -110,8 +111,7 @@ describe('the keyboard shortcuts', () => { beforeEach(() => { event.which = F1_KEY; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); @@ -128,8 +128,7 @@ describe('the keyboard shortcuts', () => { event.shiftKey = false; event.ctrlKey = false; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); @@ -151,8 +150,7 @@ describe('the keyboard shortcuts', () => { sqlEditorControllerSpy.isQueryRunning.and.returnValue(true); keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); expect(queryToolActionsSpy.executeQuery).not.toHaveBeenCalled(); @@ -168,8 +166,7 @@ describe('the keyboard shortcuts', () => { event.shiftKey = false; event.ctrlKey = false; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); @@ -189,8 +186,7 @@ describe('the keyboard shortcuts', () => { sqlEditorControllerSpy.isQueryRunning.and.returnValue(true); keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); expect(queryToolActionsSpy.explain).not.toHaveBeenCalled(); @@ -206,8 +202,7 @@ describe('the keyboard shortcuts', () => { event.altKey = false; event.ctrlKey = false; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); @@ -228,8 +223,7 @@ describe('the keyboard shortcuts', () => { sqlEditorControllerSpy.isQueryRunning.and.returnValue(true); keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); expect(queryToolActionsSpy.explainAnalyze).not.toHaveBeenCalled(); @@ -246,8 +240,7 @@ describe('the keyboard shortcuts', () => { event.ctrlKey = false; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); @@ -270,8 +263,7 @@ describe('the keyboard shortcuts', () => { sqlEditorControllerSpy.isQueryRunning.and.returnValue(true); keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); expect(queryToolActionsSpy.download).not.toHaveBeenCalled(); @@ -286,8 +278,7 @@ describe('the keyboard shortcuts', () => { macKeysSetup(); event.which = FWD_SLASH_KEY; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); @@ -303,8 +294,7 @@ describe('the keyboard shortcuts', () => { windowsKeysSetup(); event.which = FWD_SLASH_KEY; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); @@ -328,8 +318,7 @@ describe('the keyboard shortcuts', () => { it('does nothing', () => { keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); expect(queryToolActionsSpy.commentLineCode).not.toHaveBeenCalled(); @@ -344,8 +333,7 @@ describe('the keyboard shortcuts', () => { it('does nothing', () => { keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); expect(queryToolActionsSpy.commentLineCode).not.toHaveBeenCalled(); @@ -361,8 +349,7 @@ describe('the keyboard shortcuts', () => { macKeysSetup(); event.which = PERIOD_KEY; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); @@ -377,8 +364,7 @@ describe('the keyboard shortcuts', () => { windowsKeysSetup(); event.which = PERIOD_KEY; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); @@ -402,8 +388,7 @@ describe('the keyboard shortcuts', () => { it('does nothing', () => { keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); expect(queryToolActionsSpy.uncommentLineCode).not.toHaveBeenCalled(); }); @@ -416,8 +401,7 @@ describe('the keyboard shortcuts', () => { it('does nothing', () => { keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); expect(queryToolActionsSpy.uncommentLineCode).not.toHaveBeenCalled(); @@ -434,8 +418,7 @@ describe('the keyboard shortcuts', () => { event.which = FWD_SLASH_KEY; event.shiftKey = true; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); @@ -454,8 +437,7 @@ describe('the keyboard shortcuts', () => { event.which = FWD_SLASH_KEY; event.shiftKey = true; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); @@ -477,8 +459,7 @@ describe('the keyboard shortcuts', () => { event.which = FWD_SLASH_KEY; event.shiftKey = true; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); it('does nothing', () => { @@ -491,8 +472,7 @@ describe('the keyboard shortcuts', () => { event.which = FWD_SLASH_KEY; event.shiftKey = true; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); it('does nothing', () => { @@ -502,6 +482,45 @@ describe('the keyboard shortcuts', () => { }); }); + describe('shortcut to text converters', ()=> { + var shortcut = { + alt: false, + shift: false, + control: false, + key: { + char: 'a', + key_code: 65, + }, + }; + + it('shortcut_key',()=>{ + expect(keyboardShortcuts.shortcut_key(shortcut)).toBe('A'); + }); + + it('shortcut_accesskey_title',()=>{ + expect(keyboardShortcuts.shortcut_accesskey_title( + 'Title', shortcut)).toBe(gettext('Title (accesskey + A)')); + }); + + it('shortcut_title',()=>{ + shortcut.alt = true, shortcut.shift = false, shortcut.control = false; + expect(keyboardShortcuts.shortcut_title( + 'Title', shortcut)).toBe(gettext('Title (Alt+A)')); + + shortcut.alt = false, shortcut.shift = true, shortcut.control = false; + expect(keyboardShortcuts.shortcut_title( + 'Title', shortcut)).toBe(gettext('Title (Shift+A)')); + + shortcut.alt = false, shortcut.shift = false, shortcut.control = true; + expect(keyboardShortcuts.shortcut_title( + 'Title', shortcut)).toBe(gettext('Title (Ctrl+A)')); + + shortcut.alt = true, shortcut.shift = true, shortcut.control = true; + expect(keyboardShortcuts.shortcut_title( + 'Title', shortcut)).toBe(gettext('Title (Alt+Shift+Ctrl+A)')); + }); + }); + function expectEventPropagationToStop() { describe('stops all event propogation', () => { diff --git a/web/regression/javascript/sqleditor_utils_spec.js b/web/regression/javascript/sqleditor_utils_spec.js index c738f82a..75c34afc 100644 --- a/web/regression/javascript/sqleditor_utils_spec.js +++ b/web/regression/javascript/sqleditor_utils_spec.js @@ -28,5 +28,13 @@ function (SqlEditorUtils) { expect(SqlEditorUtils.capitalizeFirstLetter('create script')).toEqual('Create script'); }); }); + + describe('Calculate font size of input number passed', function () { + it('calcFontSize', function () { + expect(SqlEditorUtils.calcFontSize(1.456)).toEqual('1.46em'); + expect(SqlEditorUtils.calcFontSize()).toEqual('0em'); + expect(SqlEditorUtils.calcFontSize(2)).toEqual('2em'); + }); + }); }); }); diff --git a/web/webpack.shim.js b/web/webpack.shim.js index c12e7f3b..41bf1033 100644 --- a/web/webpack.shim.js +++ b/web/webpack.shim.js @@ -124,6 +124,7 @@ var webpackShimConfig = { 'bundled_codemirror': path.join(__dirname, './pgadmin/static/bundle/codemirror'), 'bundled_browser': path.join(__dirname, './pgadmin/static/bundle/browser'), 'sources': path.join(__dirname, './pgadmin/static/js'), + 'sourcesjsx': path.join(__dirname, './pgadmin/static/jsx'), 'pgadmin': path.join(__dirname, './pgadmin/static/js/pgadmin'), 'translations': path.join(__dirname, './pgadmin/tools/templates/js/translations'), 'sources/gettext': path.join(__dirname, './pgadmin/static/js/gettext'), @@ -179,6 +180,7 @@ var webpackShimConfig = { 'pgadmin.browser.error': path.join(__dirname, './pgadmin/browser/static/js/error'), 'pgadmin.browser.frame': path.join(__dirname, './pgadmin/browser/static/js/frame'), 'pgadmin.browser.keyboard': path.join(__dirname, './pgadmin/browser/static/js/keyboard'), + 'pgadmin.browser.preferences': path.join(__dirname, './pgadmin/browser/static/js/preferences'), 'pgadmin.browser.menu': path.join(__dirname, './pgadmin/browser/static/js/menu'), 'pgadmin.browser.messages': '/browser/js/messages', 'pgadmin.browser.node': path.join(__dirname, './pgadmin/browser/static/js/node'), diff --git a/web/webpack.test.config.js b/web/webpack.test.config.js index ef893e0b..757107ca 100644 --- a/web/webpack.test.config.js +++ b/web/webpack.test.config.js @@ -83,6 +83,7 @@ module.exports = { 'pgadmin.backform': sourcesDir + '/js/backform.pgadmin', 'pgbrowser': path.resolve(__dirname, 'regression/javascript/fake_browser'), 'pgadmin.schema.dir': path.resolve(__dirname, 'pgadmin/browser/server_groups/servers/databases/schemas/static/js'), + 'pgadmin.browser.preferences': path.join(__dirname, './pgadmin/browser/static/js/preferences'), }, }, }; ^ permalink raw reply [nested|flat] 14+ messages in thread
* Re: [pgAdmin4][RM3294] User need to reset the layout to see the changed preferences parameters @ 2018-06-29 10:12 Akshay Joshi <[email protected]> parent: Aditya Toshniwal <[email protected]> 0 siblings, 1 reply; 14+ messages in thread From: Akshay Joshi @ 2018-06-29 10:12 UTC (permalink / raw) To: Aditya Toshniwal <[email protected]>; +Cc: pgadmin-hackers Hi Aditya I have applied your patch and run pgAdmin4. I have found following two issue in the browser: - Found error while open Preferences dialog. Refer Open_Preferences_Dialog.png - Set the preferences setting "Open in new browser tab" to True and open the query tool. Refer "Open_In_New_Broswer.png". I haven't review the code. On Thu, Jun 28, 2018 at 8:04 PM, Aditya Toshniwal < [email protected]> wrote: > Hi Hackers, > > Attached is the patch for making preferences realtime and applying without > reseting the layout. Please note, the patch is only for one module - SQL > Editor and is the first part for the RM. There are lot of changes to be > done to cover all and hence sending in parts. This will not affect/break > existing code. Further patches will cover other modules. > > Highlights of this patch include: > - Changes will affect SQL Editors in Create dialog boxes, SQL tab of the > main screen, Query tool, History entries in the query tool, Query tool > opened in New Tab/Window > - All the components of SQL editor will refer to single source of > preferences which is cached in the Browser object. All other redundant ajax > get preference calls are removed. > - SQL editor will not refer template JS variables anymore, once all the > references are removed the template variables will also be removed. > - Code refactoring wherever possible. > - Covered JS test cases wherever possible. > > Request you to kindly review. > > -- > Thanks and Regards, > Aditya Toshniwal > Software Engineer | EnterpriseDB Software Solutions | Pune > "Don't Complain about Heat, Plant a tree" > -- *Akshay Joshi* *Sr. Software Architect * *Phone: +91 20-3058-9517Mobile: +91 976-788-8246* Attachments: [image/png] Open_In_New_Browser.png (95.6K, 3-Open_In_New_Browser.png) download | view image [image/png] Open_Preferences_Dialog.png (157.4K, 4-Open_Preferences_Dialog.png) download | view image ^ permalink raw reply [nested|flat] 14+ messages in thread
* Re: [pgAdmin4][RM3294] User need to reset the layout to see the changed preferences parameters @ 2018-06-29 11:16 Aditya Toshniwal <[email protected]> parent: Akshay Joshi <[email protected]> 0 siblings, 1 reply; 14+ messages in thread From: Aditya Toshniwal @ 2018-06-29 11:16 UTC (permalink / raw) To: Akshay Joshi <[email protected]>; +Cc: pgadmin-hackers Hi Akshay, On Fri, Jun 29, 2018 at 3:42 PM, Akshay Joshi <[email protected] > wrote: > Hi Aditya > > I have applied your patch and run pgAdmin4. I have found following two > issue in the browser: > > - Found error while open Preferences dialog. Refer > Open_Preferences_Dialog.png > > This error occurs even with the latest pull without changes. > > - Set the preferences setting "Open in new browser tab" to True and > open the query tool. Refer "Open_In_New_Broswer.png". > > Will look into this. > I haven't review the code. > > On Thu, Jun 28, 2018 at 8:04 PM, Aditya Toshniwal <aditya.toshniwal@ > enterprisedb.com> wrote: > >> Hi Hackers, >> >> Attached is the patch for making preferences realtime and applying >> without reseting the layout. Please note, the patch is only for one module >> - SQL Editor and is the first part for the RM. There are lot of changes to >> be done to cover all and hence sending in parts. This will not affect/break >> existing code. Further patches will cover other modules. >> >> Highlights of this patch include: >> - Changes will affect SQL Editors in Create dialog boxes, SQL tab of the >> main screen, Query tool, History entries in the query tool, Query tool >> opened in New Tab/Window >> - All the components of SQL editor will refer to single source of >> preferences which is cached in the Browser object. All other redundant ajax >> get preference calls are removed. >> - SQL editor will not refer template JS variables anymore, once all the >> references are removed the template variables will also be removed. >> - Code refactoring wherever possible. >> - Covered JS test cases wherever possible. >> >> Request you to kindly review. >> >> -- >> Thanks and Regards, >> Aditya Toshniwal >> Software Engineer | EnterpriseDB Software Solutions | Pune >> "Don't Complain about Heat, Plant a tree" >> > > > > -- > *Akshay Joshi* > > *Sr. Software Architect * > > > > *Phone: +91 20-3058-9517Mobile: +91 976-788-8246* > -- Thanks and Regards, Aditya Toshniwal Software Engineer | EnterpriseDB Software Solutions | Pune "Don't Complain about Heat, Plant a tree" ^ permalink raw reply [nested|flat] 14+ messages in thread
* Re: [pgAdmin4][RM3294] User need to reset the layout to see the changed preferences parameters @ 2018-06-29 14:14 Aditya Toshniwal <[email protected]> parent: Aditya Toshniwal <[email protected]> 0 siblings, 1 reply; 14+ messages in thread From: Aditya Toshniwal @ 2018-06-29 14:14 UTC (permalink / raw) To: Akshay Joshi <[email protected]>; +Cc: pgadmin-hackers Hi Hackers, Attached is the updated patch. On Fri, Jun 29, 2018 at 4:46 PM, Aditya Toshniwal < [email protected]> wrote: > Hi Akshay, > > On Fri, Jun 29, 2018 at 3:42 PM, Akshay Joshi < > [email protected]> wrote: > >> Hi Aditya >> >> I have applied your patch and run pgAdmin4. I have found following two >> issue in the browser: >> >> - Found error while open Preferences dialog. Refer >> Open_Preferences_Dialog.png >> >> This error occurs even with the latest pull without changes. > > >> >> - Set the preferences setting "Open in new browser tab" to True and >> open the query tool. Refer "Open_In_New_Broswer.png". >> >> Will look into this. > > >> I haven't review the code. >> >> On Thu, Jun 28, 2018 at 8:04 PM, Aditya Toshniwal < >> [email protected]> wrote: >> >>> Hi Hackers, >>> >>> Attached is the patch for making preferences realtime and applying >>> without reseting the layout. Please note, the patch is only for one module >>> - SQL Editor and is the first part for the RM. There are lot of changes to >>> be done to cover all and hence sending in parts. This will not affect/break >>> existing code. Further patches will cover other modules. >>> >>> Highlights of this patch include: >>> - Changes will affect SQL Editors in Create dialog boxes, SQL tab of the >>> main screen, Query tool, History entries in the query tool, Query tool >>> opened in New Tab/Window >>> - All the components of SQL editor will refer to single source of >>> preferences which is cached in the Browser object. All other redundant ajax >>> get preference calls are removed. >>> - SQL editor will not refer template JS variables anymore, once all the >>> references are removed the template variables will also be removed. >>> - Code refactoring wherever possible. >>> - Covered JS test cases wherever possible. >>> >>> Request you to kindly review. >>> >>> -- >>> Thanks and Regards, >>> Aditya Toshniwal >>> Software Engineer | EnterpriseDB Software Solutions | Pune >>> "Don't Complain about Heat, Plant a tree" >>> >> >> >> >> -- >> *Akshay Joshi* >> >> *Sr. Software Architect * >> >> >> >> *Phone: +91 20-3058-9517Mobile: +91 976-788-8246* >> > > > > -- > Thanks and Regards, > Aditya Toshniwal > Software Engineer | EnterpriseDB Software Solutions | Pune > "Don't Complain about Heat, Plant a tree" > -- Thanks and Regards, Aditya Toshniwal Software Engineer | EnterpriseDB Software Solutions | Pune "Don't Complain about Heat, Plant a tree" Attachments: [application/octet-stream] 0001-RM3294.patch (106.9K, 3-0001-RM3294.patch) download | inline diff: diff --git a/web/pgadmin/browser/__init__.py b/web/pgadmin/browser/__init__.py index 3741d9d3..fb1eb7db 100644 --- a/web/pgadmin/browser/__init__.py +++ b/web/pgadmin/browser/__init__.py @@ -680,17 +680,6 @@ def browser_css(): """Render and return CSS snippets from the nodes and modules.""" snippets = [] - # Get configurable options - prefs = Preferences.module('sqleditor') - - sql_font_size_pref = prefs.preference('sql_font_size') - sql_font_size = round(float(sql_font_size_pref.get()), 2) - - if sql_font_size != 0: - snippets.append( - '.CodeMirror { font-size: %sem; }' % str(sql_font_size) - ) - for submodule in blueprint.submodules: snippets.extend(submodule.csssnippets) return make_response( diff --git a/web/pgadmin/browser/static/css/browser.css b/web/pgadmin/browser/static/css/browser.css index 3ba330d3..1b2e06e7 100644 --- a/web/pgadmin/browser/static/css/browser.css +++ b/web/pgadmin/browser/static/css/browser.css @@ -1,3 +1,6 @@ +:root { + --codemirror-font-size : 1em; +} /* Styles for the main browser */ .browser-pane-container { position: absolute; @@ -66,3 +69,8 @@ samp, .pg-login-icon { font-size: 16px; } + +.CodeMirror { + font-size: var(--codemirror-font-size, '1em'); +} + diff --git a/web/pgadmin/browser/static/js/browser.js b/web/pgadmin/browser/static/js/browser.js index b26738cf..c330a871 100644 --- a/web/pgadmin/browser/static/js/browser.js +++ b/web/pgadmin/browser/static/js/browser.js @@ -2,8 +2,8 @@ define('pgadmin.browser', [ 'sources/tree/tree', 'sources/gettext', 'sources/url_for', 'require', 'jquery', 'underscore', 'underscore.string', 'bootstrap', 'sources/pgadmin', 'pgadmin.alertifyjs', 'bundled_codemirror', - 'sources/check_node_visibility', 'sources/modify_animation', 'pgadmin.browser.utils', 'wcdocker', - 'jquery.contextmenu', 'jquery.aciplugin', 'jquery.acitree', + 'sources/check_node_visibility', 'pgadmin.browser.utils', 'wcdocker', + 'jquery.contextmenu', 'jquery.aciplugin', 'jquery.acitree', 'pgadmin.browser.preferences', 'pgadmin.browser.messages', 'pgadmin.browser.menu', 'pgadmin.browser.panel', 'pgadmin.browser.error', 'pgadmin.browser.frame', @@ -13,7 +13,7 @@ define('pgadmin.browser', [ ], function( tree, gettext, url_for, require, $, _, S, Bootstrap, pgAdmin, Alertify, - codemirror, checkNodeVisibility, modifyAnimation + codemirror, checkNodeVisibility ) { window.jQuery = window.$ = $; // Some scripts do export their object in the window only. @@ -342,7 +342,7 @@ define('pgadmin.browser', [ // Cache preferences obj.cache_preferences(); - this.add_panels(); + obj.add_panels(); // Initialize the Docker obj.docker = new wcDocker( '#dockerContainer', { @@ -400,11 +400,22 @@ define('pgadmin.browser', [ mode: 'text/x-pgsql', readOnly: true, extraKeys: pgAdmin.Browser.editor_shortcut_keys, - tabSize: pgAdmin.Browser.editor_options.tabSize, - lineWrapping: pgAdmin.Browser.editor_options.wrapCode, - autoCloseBrackets: pgAdmin.Browser.editor_options.insert_pair_brackets, - matchBrackets: pgAdmin.Browser.editor_options.brace_matching, }); + /* Cache may take time to load for the first time + * Reflect the changes once cache is available + */ + let cacheIntervalId = setInterval(()=> { + let sqlEditPreferences = obj.get_preferences_for_module('sqleditor'); + if(sqlEditPreferences) { + clearInterval(cacheIntervalId); + obj.reflectPreferences('sqleditor'); + } + }, 500); + + /* Check for sql editor preference changes */ + obj.onPreferencesChange('sqleditor', function() { + obj.reflectPreferences('sqleditor'); + }); setTimeout(function() { obj.editor.setValue('-- ' + select_object_msg); @@ -514,10 +525,6 @@ define('pgadmin.browser', [ }; }, - // This will hold preference data (Works as a cache object) - // Here node will be a key and it's preference data will be value - preferences_cache: {}, - // Add menus of module/extension at appropriate menu add_menus: function(menus) { var self = this, @@ -661,46 +668,6 @@ define('pgadmin.browser', [ } } }, - - // Get preference value from cache - get_preference: function(module, preference) { - var self = this; - // If cache is not yet loaded then keep checking - if(_.size(self.preferences_cache) == 0) { - var check_preference = function() { - if(_.size(self.preferences_cache) > 0) { - clearInterval(preferenceTimeout); - return _.findWhere( - self.preferences_cache, {'module': module, 'name': preference} - ); - } - }, - preferenceTimeout = setInterval(check_preference, 1000); - } - else { - return _.findWhere( - self.preferences_cache, {'module': module, 'name': preference} - ); - } - }, - - // Get and cache the preferences - cache_preferences: function () { - var self = this; - $.ajax({ - url: url_for('preferences.get_all'), - success: function(res) { - self.preferences_cache = res; - pgBrowser.keyboardNavigation.init(); - modifyAnimation.modifyAcitreeAnimation(self); - modifyAnimation.modifyAlertifyAnimation(self); - }, - error: function(xhr, status, error) { - Alertify.pgRespErrorNotify(xhr, error); - }, - }); - }, - _findTreeChildNode: function(_i, _d, _o) { var loaded = _o.t.wasLoad(_i), onLoad = function() { diff --git a/web/pgadmin/browser/static/js/preferences.js b/web/pgadmin/browser/static/js/preferences.js new file mode 100644 index 00000000..6d80874f --- /dev/null +++ b/web/pgadmin/browser/static/js/preferences.js @@ -0,0 +1,135 @@ +import pgAdmin from 'sources/pgadmin'; +import url_for from 'sources/url_for'; +import * as modifyAnimation from 'sources/modify_animation'; +import $ from 'jquery'; +import * as Alertify from 'pgadmin.alertifyjs'; +import * as SqlEditorUtils from 'sources/sqleditor_utils'; + +const pgBrowser = pgAdmin.Browser = pgAdmin.Browser || {}; + +/* Add cache related methods and properties */ +_.extend(pgBrowser, { + /* This will hold preference data (Works as a cache object) + * Here node will be a key and it's preference data will be value + */ + preferences_cache: [], + + /* This will be used by poller of new tabs/windows to check + * if preference cache is updated in parent/window.opener. + */ + prefcache_version: 0, + + preference_version: function(version) { + if(version) { + this.prefcache_version = version; + } + else { + return this.prefcache_version; + } + }, + + /* Get cached preference */ + get_preference: function(module, preference){ + const self = this; + // If cache is not yet loaded then keep checking + if(_.size(self.preferences_cache) == 0) { + var check_preference = function() { + if(self.preferences_cache.length > 0) { + clearInterval(preferenceTimeout); + return _.findWhere( + self.preferences_cache, {'module': module, 'name': preference} + ); + } + }, + preferenceTimeout = setInterval(check_preference, 1000); + } + else { + return _.findWhere( + self.preferences_cache, {'module': module, 'name': preference} + ); + } + }, + + /* Get all the preferences of a module */ + get_preferences_for_module: function(module) { + var self = this; + let preferences = {}; + _.each( + _.where(self.preferences_cache, {'module': module}), + (preference) => { + preferences[preference.name] = preference.value; + } + ); + return preferences; + }, + + /* Get preference of an id, id is numeric */ + get_preference_for_id : function(id) { + var self = this; + return _.findWhere(self.preferences_cache, {'id': id}); + }, + + // Get and cache the preferences + cache_preferences: function (modulesChanged) { + var self = this; + return $.ajax({ + url: url_for('preferences.get_all'), + success: function(res) { + self.preferences_cache = res; + self.preference_version((new Date()).getTime()); + + pgBrowser.keyboardNavigation.init(); + if(pgBrowser.tree) { + modifyAnimation.modifyAcitreeAnimation(self); + modifyAnimation.modifyAlertifyAnimation(self); + } + + /* Once the cache is loaded after changing the preferences, + * notify the modules of the change + */ + if(modulesChanged) { + _.each(modulesChanged, (val, key)=> { + $.event.trigger('prefchange:'+key); + }); + } + }, + error: function(xhr, status, error) { + Alertify.pgRespErrorNotify(xhr, error); + }, + }); + }, + + reflectPreferences: function(module) { + let obj = this; + + if(module === 'sqleditor' || module === null || typeof module === 'undefined') { + let sqlEditPreferences = obj.get_preferences_for_module('sqleditor'); + + $(obj.editor.getWrapperElement()).css( + 'font-size',SqlEditorUtils.calcFontSize(sqlEditPreferences.sql_font_size) + ); + obj.editor.setOption('tabSize', sqlEditPreferences.tab_size); + obj.editor.setOption('lineWrapping', sqlEditPreferences.wrap_code); + obj.editor.setOption('autoCloseBrackets', sqlEditPreferences.insert_pair_brackets); + obj.editor.setOption('matchBrackets', sqlEditPreferences.brace_matching); + obj.editor.refresh(); + } + }, + + onPreferencesChange: function(module, eventHandler) { + window.parent.$(parent.document).on('prefchange:'+module, function(event) { + /* If a sqleditor is closed, event handler will be called + * but the window.top will be null. Unbind the event handler + */ + if(window.top === null) { + window.$(document).off(event); + } + else { + eventHandler(event); + } + }); + }, + +}); + +export {pgBrowser}; diff --git a/web/pgadmin/preferences/static/js/preferences.js b/web/pgadmin/preferences/static/js/preferences.js index cdbda0cd..7f21f80c 100644 --- a/web/pgadmin/preferences/static/js/preferences.js +++ b/web/pgadmin/preferences/static/js/preferences.js @@ -439,8 +439,20 @@ define('pgadmin.preferences', [ if (e.button.text == gettext('OK')) { preferences.updateAll(); + + /* Find the modules changed */ + let modulesChanged = {}; + _.each(changed, (val, key)=> { + let pref = pgBrowser.get_preference_for_id(Number(key)); + if(!modulesChanged[pref.module]) { + modulesChanged[pref.module] = true; + } + }); + // Refresh preferences cache - setTimeout(pgBrowser.cache_preferences(), 2000); + setTimeout(()=> { + pgBrowser.cache_preferences(modulesChanged); + }, 500); } }, build: function() { diff --git a/web/pgadmin/static/js/backform.pgadmin.js b/web/pgadmin/static/js/backform.pgadmin.js index c7b98496..7096ee7b 100644 --- a/web/pgadmin/static/js/backform.pgadmin.js +++ b/web/pgadmin/static/js/backform.pgadmin.js @@ -1,10 +1,11 @@ define([ 'sources/gettext', 'underscore', 'underscore.string', 'jquery', - 'backbone', 'backform', 'backgrid', 'codemirror', 'spectrum', - 'pgadmin.backgrid', 'select2', -], function(gettext, _, S, $, Backbone, Backform, Backgrid, CodeMirror) { + 'backbone', 'backform', 'backgrid', 'codemirror', 'sources/sqleditor_utils', + 'spectrum', 'pgadmin.backgrid', 'select2', +], function(gettext, _, S, $, Backbone, Backform, Backgrid, CodeMirror, SqlEditorUtils) { - var pgAdmin = (window.pgAdmin = window.pgAdmin || {}); + var pgAdmin = (window.pgAdmin = window.pgAdmin || {}), + pgBrowser = pgAdmin.Browser; pgAdmin.editableCell = function() { if (this.attributes && !_.isUndefined(this.attributes.disabled) && @@ -1259,8 +1260,7 @@ define([ var subnode = data.subnode.schema ? data.subnode : data.subnode.prototype, gridSchema = Backform.generateGridColumnsFromModel( data.node_info, subnode, this.field.get('mode'), data.columns, data.schema_node - ), - pgBrowser = window.pgAdmin.Browser; + ); // Clean up existing grid if any (in case of re-render) if (self.grid) { @@ -1428,6 +1428,23 @@ define([ getValueFromDOM: function() { return this.formatter.toRaw(this.$el.find('textarea').val(), this.model); }, + + reflectPreferences: function() { + var self = this; + /* self.sqlCtrl is null when SQL tab is not active */ + if(self.sqlCtrl) { + let sqlEditPreferences = pgAdmin.Browser.get_preferences_for_module('sqleditor'); + + $(self.sqlCtrl.getWrapperElement()).css( + 'font-size',SqlEditorUtils.calcFontSize(sqlEditPreferences.sql_font_size) + ); + self.sqlCtrl.setOption('tabSize', sqlEditPreferences.tab_size); + self.sqlCtrl.setOption('lineWrapping', sqlEditPreferences.wrap_code); + self.sqlCtrl.setOption('autoCloseBrackets', sqlEditPreferences.insert_pair_brackets); + self.sqlCtrl.setOption('matchBrackets', sqlEditPreferences.brace_matching); + self.sqlCtrl.refresh(); + } + }, render: function() { if (this.sqlCtrl) { this.sqlCtrl.toTextArea(); @@ -1446,12 +1463,16 @@ define([ mode: 'text/x-pgsql', readOnly: true, extraKeys: pgAdmin.Browser.editor_shortcut_keys, - tabSize: pgAdmin.Browser.editor_options.tabSize, - lineWrapping: pgAdmin.Browser.editor_options.wrapCode, - autoCloseBrackets: pgAdmin.Browser.editor_options.insert_pair_brackets, - matchBrackets: pgAdmin.Browser.editor_options.brace_matching, }); + this.reflectPreferences(); + + /* Check for sql editor preference changes */ + let self = this; + pgBrowser.onPreferencesChange('sqleditor', function() { + self.reflectPreferences(); + }); + /* * We will listen to the tab change event to check, if the SQL tab has * been clicked or, not. @@ -1571,7 +1592,6 @@ define([ ) { var proto = (Model && Model.prototype) || Model, schema = subschema || (proto && proto.schema), - pgBrowser = window.pgAdmin.Browser, fields = [], groupInfo = {}; @@ -2051,6 +2071,25 @@ define([ return this.sqlCtrl.getValue(); }, + reflectPreferences: function() { + var self = this; + /* self.sqlCtrl is null when Definition tab is not active */ + if(self.sqlCtrl) { + let sqlEditPreferences = pgAdmin.Browser.get_preferences_for_module('sqleditor'); + + $(self.sqlCtrl.getWrapperElement()).css( + 'font-size',SqlEditorUtils.calcFontSize(sqlEditPreferences.sql_font_size) + ); + self.sqlCtrl.setOption('indentWithTabs', !sqlEditPreferences.use_spaces); + self.sqlCtrl.setOption('indentUnit', sqlEditPreferences.tab_size); + self.sqlCtrl.setOption('tabSize', sqlEditPreferences.tab_size); + self.sqlCtrl.setOption('lineWrapping', sqlEditPreferences.wrap_code); + self.sqlCtrl.setOption('autoCloseBrackets', sqlEditPreferences.insert_pair_brackets); + self.sqlCtrl.setOption('matchBrackets', sqlEditPreferences.brace_matching); + self.sqlCtrl.refresh(); + } + }, + render: function() { // Clean up the existing sql control if (this.sqlCtrl) { @@ -2093,14 +2132,14 @@ define([ lineNumbers: true, mode: 'text/x-pgsql', extraKeys: pgAdmin.Browser.editor_shortcut_keys, - indentWithTabs: pgAdmin.Browser.editor_options.indent_with_tabs, - indentUnit: pgAdmin.Browser.editor_options.tabSize, - tabSize: pgAdmin.Browser.editor_options.tabSize, - lineWrapping: pgAdmin.Browser.editor_options.wrapCode, - autoCloseBrackets: pgAdmin.Browser.editor_options.insert_pair_brackets, - matchBrackets: pgAdmin.Browser.editor_options.brace_matching, }); + self.reflectPreferences(); + /* Check for sql editor preference changes */ + pgBrowser.onPreferencesChange('sqleditor', function() { + self.reflectPreferences(); + }); + // Disable editor if (isDisabled) { // set read only mode to true instead of 'nocursor', and hide cursor using a class so that copying is enabled diff --git a/web/pgadmin/static/js/keyboard_shortcuts.js b/web/pgadmin/static/js/keyboard_shortcuts.js index 1fe07e9b..57d8a303 100644 --- a/web/pgadmin/static/js/keyboard_shortcuts.js +++ b/web/pgadmin/static/js/keyboard_shortcuts.js @@ -8,6 +8,7 @@ ////////////////////////////////////////////////////////////////////////// import $ from 'jquery'; +import gettext from 'sources/gettext'; const PERIOD_KEY = 190, FWD_SLASH_KEY = 191, @@ -49,6 +50,52 @@ function isCtrlAltBoth(event) { return event.ctrlKey && event.altKey && !event.shiftKey; } +/* Returns the key of shortcut */ +function shortcut_key(shortcut) { + let key = ''; + if(shortcut['key'] && shortcut['key']['char']) { + key = shortcut['key']['char'].toUpperCase(); + } + return key; +} + +/* Converts shortcut object to title representation + * Shortcut object is browser.get_preference().value + */ +function shortcut_title(title, shortcut) { + let text_representation = ''; + + if (typeof shortcut === 'undefined' || shortcut === null) { + return text_representation; + } + if(shortcut['alt']) { + text_representation = gettext('Alt') + '+'; + } + if(shortcut['shift']) { + text_representation += gettext('Shift') + '+'; + } + if(shortcut['control']) { + text_representation += gettext('Ctrl') + '+'; + } + text_representation += shortcut_key(shortcut); + + return gettext('%(title)s (%(text_representation)s)',{ + 'title': title, + 'text_representation': text_representation, + }); +} + +/* Returns the key char of shortcut + * shortcut object is browser.get_preference().value + */ +function shortcut_accesskey_title(title, shortcut) { + return gettext('%(title)s (accesskey + %(key)s)',{ + 'title': title, + 'key': shortcut_key(shortcut), + }); +} + + function _stopEventPropagation(event) { event.cancelBubble = true; event.preventDefault(); @@ -124,19 +171,19 @@ function getInnerPanel($el, direction) { /* Query tool: Keyboard Shortcuts handling */ function keyboardShortcutsQueryTool( - sqlEditorController, keyboardShortcutConfig, queryToolActions, event + sqlEditorController, queryToolActions, event ) { if (sqlEditorController.isQueryRunning()) { return; } let keyCode = event.which || event.keyCode, panel_id; - let executeKeys = keyboardShortcutConfig['execute']; - let explainKeys = keyboardShortcutConfig['explain']; - let explainAnalyzeKeys = keyboardShortcutConfig['explain_analyze']; - let downloadCsvKeys = keyboardShortcutConfig['download_csv']; - let nextPanelKeys = keyboardShortcutConfig['move_next']; - let previousPanelKeys = keyboardShortcutConfig['move_previous']; - let toggleCaseKeys = keyboardShortcutConfig['toggle_case']; + let executeKeys = sqlEditorController.preferences.execute_query; + let explainKeys = sqlEditorController.preferences.explain_query; + let explainAnalyzeKeys = sqlEditorController.preferences.explain_analyze_query; + let downloadCsvKeys = sqlEditorController.preferences.download_csv; + let nextPanelKeys = sqlEditorController.preferences.move_next; + let previousPanelKeys = sqlEditorController.preferences.move_previous; + let toggleCaseKeys = sqlEditorController.preferences.toggle_case; if (this.validateShortcutKeys(executeKeys, event)) { this._stopEventPropagation(event); @@ -245,4 +292,7 @@ module.exports = { isAltShiftBoth: isAltShiftBoth, isCtrlShiftBoth: isCtrlShiftBoth, isCtrlAltBoth: isCtrlAltBoth, + shortcut_key : shortcut_key, + shortcut_title : shortcut_title, + shortcut_accesskey_title : shortcut_accesskey_title, }; diff --git a/web/pgadmin/static/js/sqleditor/query_tool_actions.js b/web/pgadmin/static/js/sqleditor/query_tool_actions.js index 411c6ed5..6cbbce0f 100644 --- a/web/pgadmin/static/js/sqleditor/query_tool_actions.js +++ b/web/pgadmin/static/js/sqleditor/query_tool_actions.js @@ -119,58 +119,6 @@ let queryToolActions = { window.top.document.activeElement.blur(); }, - getKeyboardShortcuts: function (sqlEditorController) { - let executeQueryPref = window.top.pgAdmin.Browser.get_preference( - 'sqleditor', 'execute_query'); - let explainQueryPref = window.top.pgAdmin.Browser.get_preference( - 'sqleditor', 'explain_query'); - let explainAnalyzeQueryPref = window.top.pgAdmin.Browser.get_preference( - 'sqleditor', 'explain_analyze_query'); - let downloadCsvPref = window.top.pgAdmin.Browser.get_preference( - 'sqleditor', 'download_csv'); - let nextPanelPerf = window.top.pgAdmin.Browser.get_preference( - 'sqleditor', 'move_next'); - let previousPanelPerf = window.top.pgAdmin.Browser.get_preference( - 'sqleditor', 'move_previous'); - let toggleCasePerf = window.top.pgAdmin.Browser.get_preference( - 'sqleditor', 'toggle_case'); - - if(!executeQueryPref && sqlEditorController.handler.is_new_browser_tab) { - executeQueryPref = window.opener.pgAdmin.Browser.get_preference( - 'sqleditor', 'execute_query' - ), - explainQueryPref = window.opener.pgAdmin.Browser.get_preference( - 'sqleditor', 'explain_query' - ), - explainAnalyzeQueryPref = window.opener.pgAdmin.Browser.get_preference( - 'sqleditor', 'explain_analyze_query' - ), - downloadCsvPref = window.opener.pgAdmin.Browser.get_preference( - 'sqleditor', 'download_csv' - ), - nextPanelPerf = window.opener.pgAdmin.Browser.get_preference( - 'sqleditor', 'move_next' - ), - previousPanelPerf = window.opener.pgAdmin.Browser.get_preference( - 'sqleditor', 'move_previous' - ), - toggleCasePerf = window.opener.pgAdmin.Browser.get_preference( - 'sqleditor', 'toggle_case' - ); - } - - return { - 'execute': executeQueryPref.value, - 'explain': explainQueryPref.value, - 'explain_analyze': explainAnalyzeQueryPref.value, - 'download_csv': downloadCsvPref.value, - 'move_next': nextPanelPerf.value, - 'move_previous': previousPanelPerf.value, - 'toggle_case': toggleCasePerf.value, - }; - - }, - toggleCaseOfSelectedText: function (sqlEditorController) { let codeMirrorObj = sqlEditorController.gridView.query_tool_obj; let selectedText = codeMirrorObj.getSelection(); diff --git a/web/pgadmin/static/js/sqleditor/query_tool_preferences.js b/web/pgadmin/static/js/sqleditor/query_tool_preferences.js new file mode 100644 index 00000000..3ee2f0bc --- /dev/null +++ b/web/pgadmin/static/js/sqleditor/query_tool_preferences.js @@ -0,0 +1,179 @@ +import {shortcut_key, shortcut_accesskey_title, shortcut_title} + from 'sources/keyboard_shortcuts'; +import * as SqlEditorUtils from 'sources/sqleditor_utils'; +import $ from 'jquery'; + +function reflectPreferences(sqlEditor) { + let $el = sqlEditor.$el, + preferences = sqlEditor.preferences; + + if(sqlEditor.handler.slickgrid) { + sqlEditor.handler.slickgrid.CSVOptions = { + quoting: sqlEditor.preferences.results_grid_quoting, + quote_char: sqlEditor.preferences.results_grid_quote_char, + field_separator: sqlEditor.preferences.results_grid_field_separator, + }; + } + + /* Accessed using accesskey direct w/o ctrl,atl,shift */ + $el.find('#btn-load-file') + .attr('title', shortcut_accesskey_title('Open File',preferences.btn_open_file)) + .attr('accesskey', shortcut_key(preferences.btn_open_file)); + + $el.find('#btn-save') + .attr('title', shortcut_accesskey_title('Save File',preferences.btn_save_file)) + .attr('accesskey', shortcut_key(preferences.btn_save_file)); + + $el.find('#btn-find-menu-dropdown') + .attr('title', shortcut_accesskey_title('Find',preferences.btn_find_options)) + .attr('accesskey', shortcut_key(preferences.btn_find_options)); + + $el.find('#btn-copy-row') + .attr('title', shortcut_accesskey_title('Copy',preferences.btn_copy_row)) + .attr('accesskey', shortcut_key(preferences.btn_copy_row)); + + $el.find('#btn-paste-row') + .attr('title', shortcut_accesskey_title('Paste',preferences.btn_paste_row)) + .attr('accesskey', shortcut_key(preferences.btn_paste_row)); + + $el.find('#btn-delete-row') + .attr('title', shortcut_accesskey_title('Delete',preferences.btn_delete_row)) + .attr('accesskey', shortcut_key(preferences.btn_delete_row)); + + $el.find('#btn-filter') + .attr('title', shortcut_accesskey_title('Filter',preferences.btn_filter_dialog)) + .attr('accesskey', shortcut_key(preferences.btn_filter_dialog)); + + $el.find('#btn-filter-dropdown') + .attr('title', shortcut_accesskey_title('Filter options',preferences.btn_filter_options)) + .attr('accesskey', shortcut_key(preferences.btn_filter_options)); + + $el.find('#btn-rows-limit') + .attr('title', shortcut_accesskey_title('Rows limit',preferences.btn_rows_limit)) + .attr('accesskey', shortcut_key(preferences.btn_rows_limit)); + + $el.find('#btn-query-dropdown') + .attr('title', shortcut_accesskey_title('Execute options',preferences.btn_execute_options)) + .attr('accesskey', shortcut_key(preferences.btn_execute_options)); + + $el.find('#btn-cancel-query') + .attr('title', shortcut_accesskey_title('Cancel query',preferences.btn_cancel_query)) + .attr('accesskey', shortcut_key(preferences.btn_cancel_query)); + + $el.find('#btn-clear-dropdown') + .attr('title', shortcut_accesskey_title('Clear',preferences.btn_clear_options)) + .attr('accesskey', shortcut_key(preferences.btn_clear_options)); + + $el.find('#btn-conn-status') + .attr('accesskey', shortcut_key(preferences.btn_conn_status)) + .find('i') + .attr('title', + shortcut_accesskey_title('Connection status (click for details)', + preferences.btn_conn_status)); + + /* Accessed using ctrl,atl,shift and key */ + $el.find('#btn-flash') + .attr('title', + shortcut_title('Execute/Refresh',preferences.execute_query)); + + $el.find('#btn-flash-menu span') + .text(shortcut_title('Execute/Refresh',preferences.execute_query)); + + $el.find('#btn-explain span') + .text(shortcut_title('Explain',preferences.explain_query)); + + $el.find('#btn-explain-analyze span') + .text(shortcut_title('Explain Analyze',preferences.explain_analyze_query)); + + $el.find('#btn-download') + .attr('title', + shortcut_title('Download as CSV',preferences.download_csv)); + + /* Set Auto-commit and auto-rollback on query editor */ + if (preferences.auto_commit) { + $el.find('.auto-commit').removeClass('visibility-hidden'); + } + else { + $el.find('.auto-commit').addClass('visibility-hidden'); + } + if (preferences.auto_rollback) { + $el.find('.auto-rollback').removeClass('visibility-hidden'); + } + else { + $el.find('.auto-rollback').addClass('visibility-hidden'); + } + + /* Set explain options on query editor */ + if (preferences.explain_verbose){ + $el.find('.explain-verbose').removeClass('visibility-hidden'); + } + else { + $el.find('.explain-verbose').addClass('visibility-hidden'); + } + + if (preferences.explain_costs){ + $el.find('.explain-costs').removeClass('visibility-hidden'); + } + else { + $el.find('.explain-costs').addClass('visibility-hidden'); + } + + if (preferences.explain_buffers){ + $el.find('.explain-buffers').removeClass('visibility-hidden'); + } + else { + $el.find('.explain-buffers').addClass('visibility-hidden'); + } + + if (preferences.explain_timing) { + $el.find('.explain-timing').removeClass('visibility-hidden'); + } + else { + $el.find('.explain-timing').addClass('visibility-hidden'); + } + + /* Connection status check */ + /* remove the status checker if present */ + if(sqlEditor.connIntervalId != null) { + clearInterval(sqlEditor.connIntervalId); + sqlEditor.connIntervalId = null; + } + if (preferences.connection_status) { + let $conn_status = $el.find('#btn-conn-status'), + $status_el = $conn_status.find('i'); + $conn_status.popover(); + + $conn_status.removeClass('connection-status-hide'); + $el.find('.editor-title').addClass('editor-title-connection'); + + // To set initial connection + SqlEditorUtils.fetchConnectionStatus(sqlEditor.handler, $conn_status, $status_el); + + // Calling it again in specified interval + sqlEditor.connIntervalId = setInterval( + SqlEditorUtils.fetchConnectionStatus.bind(null, sqlEditor.handler, $conn_status, $status_el), + preferences.connection_status_fetch_time * 1000 + ); + } + else { + $el.find('#btn-conn-status').addClass('connection-status-hide'); + $el.find('.editor-title').removeClass('editor-title-connection'); + } + + /* Code Mirror Preferences */ + let sql_font_size = SqlEditorUtils.calcFontSize(preferences.sql_font_size); + $(sqlEditor.query_tool_obj.getWrapperElement()).css('font-size', sql_font_size); + + sqlEditor.query_tool_obj.setOption('indentWithTabs', !preferences.use_spaces); + sqlEditor.query_tool_obj.setOption('indentUnit', preferences.tab_size); + sqlEditor.query_tool_obj.setOption('tabSize', preferences.tab_size); + sqlEditor.query_tool_obj.setOption('lineWrapping', preferences.wrap_code); + sqlEditor.query_tool_obj.setOption('autoCloseBrackets', preferences.insert_pair_brackets); + sqlEditor.query_tool_obj.setOption('matchBrackets', preferences.brace_matching); + sqlEditor.query_tool_obj.refresh(); + + /* Render history to reflect Font size change */ + sqlEditor.render_history_grid(); +} + +export {reflectPreferences}; diff --git a/web/pgadmin/static/js/sqleditor_utils.js b/web/pgadmin/static/js/sqleditor_utils.js index be41566f..0fff1d95 100644 --- a/web/pgadmin/static/js/sqleditor_utils.js +++ b/web/pgadmin/static/js/sqleditor_utils.js @@ -178,24 +178,6 @@ define(['jquery', 'sources/gettext', 'sources/url_for'], }); }, - // This function will update the connection status - updateConnectionStatus: function(target, poll_time) { - var $el = $(target.gridView.$el.find('.connection_status')), - $status_el = $($el.find('.fa-custom')); - - // Apply popover on element - $el.popover(); - - // To set initial connection statussource$el.popover() - sqlEditorUtils.fetchConnectionStatus(target, $el, $status_el); - - // Calling it again in specified interval - setInterval( - sqlEditorUtils.fetchConnectionStatus.bind(null, target, $el, $status_el), - poll_time * 1000 - ); - }, - // Updates the flag for connection status poll updateConnectionStatusFlag: function(status) { var $el = $('.connection_status'); @@ -203,6 +185,15 @@ define(['jquery', 'sources/gettext', 'sources/url_for'], $el.data('panel-visible', status); } }, + + calcFontSize: function(fontSize) { + if(fontSize) { + return Number((Math.round(fontSize + 'e+2') + 'e-2')) + 'em'; + } + else { + return '0em'; + } + }, }; return sqlEditorUtils; }); diff --git a/web/pgadmin/static/jsx/history/detail/code_mirror.jsx b/web/pgadmin/static/jsx/history/detail/code_mirror.jsx index 6e982128..038cc200 100644 --- a/web/pgadmin/static/jsx/history/detail/code_mirror.jsx +++ b/web/pgadmin/static/jsx/history/detail/code_mirror.jsx @@ -50,6 +50,11 @@ export default class CodeMirror extends React.Component { Object.keys(props.options || {}).forEach(key => this.editor.setOption(key, props.options[key])); this.editor.setValue(props.value || ''); + + if(props.sqlFontSize) { + $(this.editor.getWrapperElement()).css('font-size', props.sqlFontSize); + } + this.editor.refresh(); } diff --git a/web/pgadmin/static/jsx/history/detail/history_detail_query.jsx b/web/pgadmin/static/jsx/history/detail/history_detail_query.jsx index dce34607..eae55dee 100644 --- a/web/pgadmin/static/jsx/history/detail/history_detail_query.jsx +++ b/web/pgadmin/static/jsx/history/detail/history_detail_query.jsx @@ -64,6 +64,7 @@ export default class HistoryDetailQuery extends React.Component { mode: 'text/x-pgsql', readOnly: true, }} + sqlFontSize= {this.props.sqlEditorPref.sql_font_size} /> </div>); } @@ -71,4 +72,5 @@ export default class HistoryDetailQuery extends React.Component { HistoryDetailQuery.propTypes = { historyEntry: Shapes.historyDetail, + sqlEditorPref: Shapes.sqlEditorPrefObj, }; diff --git a/web/pgadmin/static/jsx/history/query_history.jsx b/web/pgadmin/static/jsx/history/query_history.jsx index 3c07b5bd..8b5ffd2a 100644 --- a/web/pgadmin/static/jsx/history/query_history.jsx +++ b/web/pgadmin/static/jsx/history/query_history.jsx @@ -97,13 +97,16 @@ export default class QueryHistory extends React.Component { selectedEntry={this.state.selectedEntry} onSelectEntry={this.selectHistoryEntry} /> - <QueryHistoryDetail historyEntry={this.state.currentHistoryDetail}/> + <QueryHistoryDetail historyEntry={this.state.currentHistoryDetail} + sqlEditorPref={this.props.sqlEditorPref} + /> </SplitPane>); } } QueryHistory.propTypes = { historyCollection: Shapes.historyCollectionClass.isRequired, + sqlEditorPref: Shapes.sqlEditorPrefObj, }; export { diff --git a/web/pgadmin/static/jsx/react_shapes.jsx b/web/pgadmin/static/jsx/react_shapes.jsx index 454ab446..f8948b5f 100644 --- a/web/pgadmin/static/jsx/react_shapes.jsx +++ b/web/pgadmin/static/jsx/react_shapes.jsx @@ -25,7 +25,13 @@ let historyCollectionClass = onChange: PropTypes.func.isRequired, }); +let sqlEditorPrefObj = + PropTypes.shape({ + sql_font_size: PropTypes.string.isRequired, + }); + export default { historyDetail, historyCollectionClass, + sqlEditorPrefObj, }; diff --git a/web/pgadmin/tools/datagrid/__init__.py b/web/pgadmin/tools/datagrid/__init__.py index d3c3bf9c..04e2a683 100644 --- a/web/pgadmin/tools/datagrid/__init__.py +++ b/web/pgadmin/tools/datagrid/__init__.py @@ -24,12 +24,9 @@ from pgadmin.utils.ajax import make_json_response, bad_request, \ internal_server_error from config import PG_DEFAULT_DRIVER -from pgadmin.utils.preferences import Preferences from pgadmin.model import Server from pgadmin.utils.driver import get_driver from pgadmin.utils.exception import ConnectionLost, SSHTunnelConnectionLost -from pgadmin.tools.sqleditor.utils.query_tool_preferences import \ - get_query_tool_keyboard_shortcuts, get_text_representation_of_shortcut class DataGridModule(PgAdminModule): @@ -184,13 +181,9 @@ def initialize_datagrid(cmd_type, obj_type, sgid, sid, did, obj_id): # Store the grid dictionary into the session variable session['gridData'] = sql_grid_data - pref = Preferences.module('sqleditor') - new_browser_tab = pref.preference('new_browser_tab').get() - return make_json_response( data={ - 'gridTransId': trans_id, - 'newBrowserTab': new_browser_tab + 'gridTransId': trans_id } ) @@ -246,12 +239,6 @@ def panel(trans_id, is_query_tool, editor_title): if "linux" in _platform: is_linux_platform = True - pref = Preferences.module('sqleditor') - if pref.preference('new_browser_tab').get(): - new_browser_tab = 'true' - else: - new_browser_tab = 'false' - # Fetch the server details bgcolor = None fgcolor = None @@ -271,16 +258,10 @@ def panel(trans_id, is_query_tool, editor_title): url_params = dict() if is_query_tool == 'true': - prompt_save_changes = pref.preference( - 'prompt_save_query_changes' - ).get() url_params['sgid'] = trans_obj.sgid url_params['sid'] = trans_obj.sid url_params['did'] = trans_obj.did else: - prompt_save_changes = pref.preference( - 'prompt_save_data_changes' - ).get() url_params['cmd_type'] = trans_obj.cmd_type url_params['obj_type'] = trans_obj.object_type url_params['sgid'] = trans_obj.sgid @@ -288,9 +269,6 @@ def panel(trans_id, is_query_tool, editor_title): url_params['did'] = trans_obj.did url_params['obj_id'] = trans_obj.obj_id - display_connection_status = pref.preference('connection_status').get() - queryToolShortcuts = get_query_tool_keyboard_shortcuts() - return render_template( "datagrid/index.html", _=gettext, @@ -300,19 +278,11 @@ def panel(trans_id, is_query_tool, editor_title): script_type_url=sURL, is_desktop_mode=app.PGADMIN_RUNTIME, is_linux=is_linux_platform, - is_new_browser_tab=new_browser_tab, server_type=server_type, client_platform=user_agent.platform, bgcolor=bgcolor, fgcolor=fgcolor, - # convert python boolean value to equivalent js boolean literal - # before passing it to html template. - prompt_save_changes='true' if prompt_save_changes else 'false', - display_connection_status=display_connection_status, - url_params=json.dumps(url_params), - key=queryToolShortcuts.get('keys'), - shortcuts=queryToolShortcuts.get('shortcuts'), - get_shortcut_text=get_text_representation_of_shortcut + url_params=json.dumps(url_params) ) @@ -387,13 +357,9 @@ def initialize_query_tool(sgid, sid, did=None): # Store the grid dictionary into the session variable session['gridData'] = sql_grid_data - pref = Preferences.module('sqleditor') - new_browser_tab = pref.preference('new_browser_tab').get() - return make_json_response( data={ - 'gridTransId': trans_id, - 'newBrowserTab': new_browser_tab + 'gridTransId': trans_id } ) diff --git a/web/pgadmin/tools/datagrid/static/js/datagrid.js b/web/pgadmin/tools/datagrid/static/js/datagrid.js index c730b180..4cdddf38 100644 --- a/web/pgadmin/tools/datagrid/static/js/datagrid.js +++ b/web/pgadmin/tools/datagrid/static/js/datagrid.js @@ -29,6 +29,23 @@ define('pgadmin.datagrid', [ this.initialized = true; this.title_index = 1; + + let self = this; + /* Cache may take time to load for the first time + * Keep trying till available + */ + let cacheIntervalId = setInterval(function() { + if(pgBrowser.preference_version() > 0) { + self.preferences = pgBrowser.get_preferences_for_module('sqleditor'); + clearInterval(cacheIntervalId); + } + },0); + + pgBrowser.onPreferencesChange('sqleditor', function() { + self.preferences = pgBrowser.get_preferences_for_module('sqleditor'); + }); + + this.spinner_el = '<div class="wcLoadingContainer">'+ '<div class="wcLoadingBackground"></div>'+ '<div class="wcLoadingIconContainer">'+ @@ -279,12 +296,12 @@ define('pgadmin.datagrid', [ lineNumbers: true, mode: 'text/x-pgsql', extraKeys: pgBrowser.editor_shortcut_keys, - indentWithTabs: pgAdmin.Browser.editor_options.indent_with_tabs, - indentUnit: pgAdmin.Browser.editor_options.tabSize, - tabSize: pgBrowser.editor_options.tabSize, - lineWrapping: pgAdmin.Browser.editor_options.wrapCode, - autoCloseBrackets: pgAdmin.Browser.editor_options.insert_pair_brackets, - matchBrackets: pgAdmin.Browser.editor_options.brace_matching, + indentWithTabs: !this.preferences.use_spaces, + indentUnit: this.preferences.tab_size, + tabSize: this.preferences.tab_size, + lineWrapping: this.preferences.wrap_code, + autoCloseBrackets: this.preferences.insert_pair_brackets, + matchBrackets: this.preferences.brace_matching, }); setTimeout(function() { @@ -415,13 +432,20 @@ define('pgadmin.datagrid', [ } } - if (trans_obj.newBrowserTab) { + if (self.preferences.new_browser_tab) { var newWin = window.open(baseUrl, '_blank'); // add a load listener to the window so that the title gets changed on page load newWin.addEventListener('load', function() { newWin.document.title = panel_title; + + /* Set the initial version of pref cache the new window is having + * This will be used by the poller to compare with window openers + * pref cache version + */ + //newWin.pgAdmin.Browser.preference_version(pgBrowser.preference_version()); }); + } else { /* On successfully initialization find the dashboard panel, * create new panel and add it to the dashboard panel. diff --git a/web/pgadmin/tools/datagrid/templates/datagrid/index.html b/web/pgadmin/tools/datagrid/templates/datagrid/index.html index ad090262..37187e45 100644 --- a/web/pgadmin/tools/datagrid/templates/datagrid/index.html +++ b/web/pgadmin/tools/datagrid/templates/datagrid/index.html @@ -10,13 +10,6 @@ .alertify .ajs-dialog.ajs-shake{-webkit-animation-name: none;} .sql-editor-busy-icon.fa-pulse{-webkit-animation: none;} {% endif %} - - {# Note: If we will display connection status then we have to provide some - space to display status icon else we can use all the space available #} - .editor-title { - width:{% if display_connection_status -%} calc(100% - 43px) - {% else %} 100% {%- endif %}; - } </style> <div id="main-editor_panel"> <div id="fetching_data" class="wcLoadingIconContainer sql-editor-busy-fetching hide"> @@ -28,14 +21,14 @@ <div id="btn-toolbar" class="pg-prop-btn-group bg-gray-2 border-gray-3" role="toolbar" aria-label=""> <div class="btn-group" role="group" aria-label=""> <button id="btn-load-file" type="button" class="btn btn-default btn-load-file" - title="{{ _('Open File') }}{{ _(' (accesskey+{0})'.format(key.open_file.upper())) }}" - accesskey="{{key.open_file}}" + title="" + accesskey="" tabindex="0"> <i class="fa fa-folder-open-o" aria-hidden="true"></i> </button> <button id="btn-save" type="button" class="btn btn-default" - title="{{ _('Save') }}{{ _(' (accesskey+{0})'.format(key.save_file.upper())) }}" - accesskey="{{key.save_file}}" + title="" + accesskey="" disabled> <i class="fa fa-floppy-o" aria-hidden="true" tabindex="0"></i> </button> @@ -63,8 +56,8 @@ </button> <button id="btn-find-menu-dropdown" type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" - title="{{ _('Find options') }}{{ _(' (accesskey+{0})'.format(key.find_options.upper())) }}" - accesskey="{{key.find_options}}" + title="" + accesskey="" tabindex="0"> <span class="caret"></span> <span class="sr-only">Toggle Dropdown</span> </button> @@ -122,22 +115,22 @@ </div> <div class="btn-group" role="group" aria-label=""> <button id="btn-copy-row" type="button" class="btn btn-default" - title="{{ _('Copy') }}{{ _(' (accesskey+{0})'.format(key.copy_row.upper())) }}" - accesskey="{{key.copy_row}}" + title="" + accesskey="" tabindex="0" disabled> <i class="fa fa-files-o" aria-hidden="true"></i> </button> <button id="btn-paste-row" type="button" class="btn btn-default" - title="{{ _('Paste') }}{{ _(' (accesskey+{0})'.format(key.paste_row.upper())) }}" - accesskey="{{key.paste_row}}" + title="" + accesskey="" tabindex="0" disabled> <i class="fa fa-clipboard" aria-hidden="true"></i> </button> </div> <div class="btn-group" role="group" aria-label=""> <button id="btn-delete-row" type="button" class="btn btn-default" - title="{{ _('Delete') }}{{ _(' (accesskey+{0})'.format(key.delete_row.upper())) }}" - accesskey="{{key.delete_row}}" + title="" + accesskey="" tabindex="0" disabled> <i class="fa fa-trash" aria-hidden="true"></i> </button> @@ -188,15 +181,15 @@ </div> <div class="btn-group" role="group" aria-label=""> <button id="btn-filter" type="button" class="btn btn-default" - title="{{ _('Filter') }}{{ _(' (accesskey+{0})'.format(key.filter_dialog.upper())) }}" - accesskey="{{key.filter_dialog}}" + title="" + accesskey="" tabindex="0" disabled> <i class="fa fa-filter" aria-hidden="true"></i> </button> <button id="btn-filter-dropdown" type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" - title="{{ _('Filter options') }}{{ _(' (accesskey+{0})'.format(key.filter_options.upper())) }}" - accesskey="{{key.filter_options}}" + title="" + accesskey="" disabled tabindex="0"> <span class="caret"></span> <span class="sr-only">{{ _('Toggle Dropdown') }}</span> </button> @@ -210,9 +203,9 @@ </ul> </div> <div class="btn-group" role="group" aria-label=""> - <select class="limit" style="height: 30px; width: 90px;" disabled - title="{{ _('Rows limit') }}{{ _(' (accesskey+{0})'.format(key.rows_limit.upper())) }}" - accesskey="{{key.rows_limit}}" + <select id="btn-rows-limit" class="limit" style="height: 30px; width: 90px;" disabled + title="" + accesskey="" tabindex="0"> <option value="-1">{{ _('No limit') }}</option> <option value="1000">{{ _('1000 rows') }}</option> @@ -223,31 +216,31 @@ <div class="btn-group" role="group" aria-label=""> <button id="btn-flash" data-test-selector="execute-refresh-button" type="button" class="btn btn-default" style="width: 40px;" - title="{{ _('Execute/Refresh') }}{{ _(' ({0})'.format(get_shortcut_text(shortcuts.execute_query))) }}" + title="" tabindex="0"> <i class="fa fa-bolt" aria-hidden="true"></i> </button> <button id="btn-query-dropdown" type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" - accesskey="{{key.execute_options}}" - title="{{ _('Execute options') }}{{ _(' (accesskey+{0})'.format(key.execute_options.upper())) }}" + accesskey="" + title="" tabindex="0"> <span class="caret"></span> <span class="sr-only">{{ _('Toggle Dropdown') }}</span> </button> <ul class="dropdown-menu" role="menu"> <li> <a id="btn-flash-menu" href="#" tabindex="0"> - <span>{{ _('Execute/Refresh') }}{{ _(' ({0})'.format(get_shortcut_text(shortcuts.execute_query))) }}</span> + <span></span> </a> </li> <li> <a id="btn-explain" href="#" tabindex="0"> - <span>{{ _('Explain') }}{{ _(' ({0})'.format(get_shortcut_text(shortcuts.explain_query))) }}</span> + <span></span> </a> </li> <li> <a id="btn-explain-analyze" href="#" tabindex="0"> - <span>{{ _('Explain Analyze') }}{{ _(' ({0})'.format(get_shortcut_text(shortcuts.explain_analyze_query))) }}</span> + <span></span> </a> </li> <li class="divider"></li> @@ -295,8 +288,8 @@ </li> </ul> <button id="btn-cancel-query" type="button" class="btn btn-default" - title="{{ _('Cancel query') }}{{ _(' (accesskey+{0})'.format(key.cancel_query.upper())) }}" - accesskey="{{key.cancel_query}}" + title="" + accesskey="" tabindex="0" disabled > <i class="fa fa-stop" aria-hidden="true"></i> </button> @@ -304,8 +297,8 @@ <div class="btn-group" role="group" aria-label=""> <button id="btn-clear-dropdown" type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" - title="{{ _('Clear') }}{{ _(' (accesskey+{0})'.format(key.clear_options.upper())) }}" - accesskey="{{key.clear_options}}" + title="" + accesskey="" tabindex="0"> <i class="fa fa-eraser" aria-hidden="true"></i> <span class="caret"></span> <span class="sr-only">{{ _('Toggle Dropdown') }}</span> @@ -325,7 +318,7 @@ </div> <div class="btn-group" role="group" aria-label=""> <button id="btn-download" type="button" class="btn btn-default" - title="{{ _('Download as CSV') }}{{ _(' ({0})'.format(get_shortcut_text(shortcuts.download_csv))) }}" + title="" tabindex="0"> <i class="fa fa-download" aria-hidden="true"></i> </button> @@ -333,21 +326,17 @@ </div> <div class="connection_status_wrapper"> - {% if display_connection_status %} - <div style="display: inline-block;" - title="{{ _('Connection status (click for details) (accesskey+{0})'.format(key.conn_status.upper())) }}"> - <div class="connection_status" data-container="body" - data-toggle="popover" data-placement="bottom" - data-content="" - data-panel-visible="visible" - accesskey="{{key.conn_status}}" - tabindex="0"> - <i class="fa-custom fa-query-tool-disconnected" aria-hidden="true" - title="{{ _('Connection status (click for details) (accesskey+{0})'.format(key.conn_status.upper())) }}"> - </i> - </div> + <div id="btn-conn-status" + class="connection_status connection-status-show" data-container="body" + data-toggle="popover" data-placement="bottom" + data-content="" + data-panel-visible="visible" + accesskey="" + tabindex="0"> + <i class="fa-custom fa-query-tool-disconnected" aria-hidden="true" + title=""> + </i> </div> - {% endif %} <div class="editor-title" style="background-color: {% if fgcolor %}{{ bgcolor or '#FFFFFF' }}{% else %}{{ bgcolor or '#2C76B4' }}{% endif %}; color: {{ fgcolor or 'white' }};"></div> </div> @@ -398,9 +387,7 @@ {{ is_query_tool }}, "{{ editor_title }}", script_type_url, - {{ is_new_browser_tab }}, "{{ server_type }}", - {{ prompt_save_changes }}, {{ url_params|safe}} ); }); diff --git a/web/pgadmin/tools/sqleditor/static/css/sqleditor.css b/web/pgadmin/tools/sqleditor/static/css/sqleditor.css index c54590d3..bd9b3091 100644 --- a/web/pgadmin/tools/sqleditor/static/css/sqleditor.css +++ b/web/pgadmin/tools/sqleditor/static/css/sqleditor.css @@ -625,3 +625,20 @@ input.editor-checkbox:focus { .data_sorting_dialog .data_sorting { padding: 10px 0px; } + +.editor-title { + width:100%; +} + +.editor-title-connection { + width:calc(100% - 43px); +} + +.connection-status-show { + display: inline-block; +} + +.connection-status-hide { + display: none; +} + diff --git a/web/pgadmin/tools/sqleditor/static/js/sqleditor.js b/web/pgadmin/tools/sqleditor/static/js/sqleditor.js index ce397692..f4cfd9dc 100644 --- a/web/pgadmin/tools/sqleditor/static/js/sqleditor.js +++ b/web/pgadmin/tools/sqleditor/static/js/sqleditor.js @@ -16,7 +16,7 @@ define('tools.querytool', [ 'sources/sqleditor/query_tool_http_error_handler', 'sources/sqleditor/filter_dialog', 'sources/history/index.js', - 'sources/../jsx/history/query_history', + 'sourcesjsx/history/query_history', 'react', 'react-dom', 'sources/keyboard_shortcuts', 'sources/sqleditor/query_tool_actions', @@ -25,6 +25,7 @@ define('tools.querytool', [ 'sources/modify_animation', 'sources/sqleditor/calculate_query_run_time', 'sources/sqleditor/call_render_after_poll', + 'sources/sqleditor/query_tool_preferences', 'sources/../bundle/slickgrid', 'pgadmin.file_manager', 'backgrid.sizeable.columns', @@ -38,7 +39,7 @@ define('tools.querytool', [ XCellSelectionModel, setStagedRows, SqlEditorUtils, ExecuteQuery, httpErrorHandler, FilterHandler, HistoryBundle, queryHistory, React, ReactDOM, keyboardShortcuts, queryToolActions, queryToolNotifications, Datagrid, - modifyAnimation, calculateQueryRunTime, callRenderAfterPoll) { + modifyAnimation, calculateQueryRunTime, callRenderAfterPoll, queryToolPref) { /* Return back, this has been called more than once */ if (pgAdmin.SqlEditor) return pgAdmin.SqlEditor; @@ -58,6 +59,11 @@ define('tools.querytool', [ this.$el = opts.el; this.handler = opts.handler; this.handler['col_size'] = {}; + let browser = window.opener ? + window.opener.pgAdmin.Browser : window.top.pgAdmin.Browser; + this.preferences = browser.get_preferences_for_module('sqleditor'); + this.handler.preferences = this.preferences; + this.connIntervalId = null; }, // Bind all the events @@ -117,10 +123,6 @@ define('tools.querytool', [ var self = this; $('.editor-title').text(_.unescape(self.editor_title)); - self.checkConnectionStatus(); - - // Fetch and assign the shortcuts to current instance - self.keyboardShortcutConfig = queryToolActions.getKeyboardShortcuts(self); // Updates connection status flag self.gain_focus = function() { @@ -183,13 +185,7 @@ define('tools.querytool', [ }, gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'], extraKeys: pgBrowser.editor_shortcut_keys, - indentWithTabs: pgAdmin.Browser.editor_options.indent_with_tabs, - indentUnit: pgAdmin.Browser.editor_options.tabSize, - tabSize: pgAdmin.Browser.editor_options.tabSize, - lineWrapping: pgAdmin.Browser.editor_options.wrapCode, scrollbarStyle: 'simple', - autoCloseBrackets: pgAdmin.Browser.editor_options.insert_pair_brackets, - matchBrackets: pgAdmin.Browser.editor_options.brace_matching, }); // Refresh Code mirror on SQL panel resize to @@ -270,32 +266,32 @@ define('tools.querytool', [ self.render_history_grid(); queryToolNotifications.renderNotificationsGrid(self.notifications_panel); - if (!self.handler.is_new_browser_tab) { + if (!self.preferences.new_browser_tab) { // Listen on the panel closed event and notify user to save modifications. _.each(window.top.pgAdmin.Browser.docker.findPanels('frm_datagrid'), function(p) { if (p.isVisible()) { - if (self.handler.prompt_save_changes) { - p.on(wcDocker.EVENT.CLOSING, function() { - // Only if we can edit data then perform this check - var notify = false, - msg; - if (self.handler.can_edit) { - var data_store = self.handler.data_store; - if (data_store && (_.size(data_store.added) || - _.size(data_store.updated))) { - msg = gettext('The data has changed. Do you want to save changes?'); - notify = true; - } - } else if (self.handler.is_query_tool && self.handler.is_query_changed) { - msg = gettext('The text has changed. Do you want to save changes?'); + p.on(wcDocker.EVENT.CLOSING, function() { + // Only if we can edit data then perform this check + var notify = false, + msg; + if (self.handler.can_edit + && self.preferences.prompt_save_data_changes) { + var data_store = self.handler.data_store; + if (data_store && (_.size(data_store.added) || + _.size(data_store.updated))) { + msg = gettext('The data has changed. Do you want to save changes?'); notify = true; } - if (notify) { - return self.user_confirmation(p, msg); - } - return true; - }); - } + } else if (self.handler.is_query_tool && self.handler.is_query_changed + && self.preferences.prompt_save_query_changes) { + msg = gettext('The text has changed. Do you want to save changes?'); + notify = true; + } + if (notify) { + return self.user_confirmation(p, msg); + } + return true; + }); // Set focus on query tool of active panel p.on(wcDocker.EVENT.GAIN_FOCUS, function() { @@ -483,33 +479,36 @@ define('tools.querytool', [ }.bind(ctx), }; }); - }, - // This function will check the connection status at specific - // interval defined by the user in preference - checkConnectionStatus: function() { - var self = this, - preference = window.top.pgAdmin.Browser.get_preference( - 'sqleditor', 'connection_status_fetch_time' - ), - display_status = window.top.pgAdmin.Browser.get_preference( - 'sqleditor', 'connection_status' - ); - if(!preference && self.handler.is_new_browser_tab) { - preference = window.opener.pgAdmin.Browser.get_preference( - 'sqleditor', 'connection_status_fetch_time' - ); - display_status = window.opener.pgAdmin.Browser.get_preference( - 'sqleditor', 'connection_status' - ); - } - // Only enable pooling if it is enabled - if (display_status && display_status.value) { - SqlEditorUtils.updateConnectionStatus( - self.handler, - preference.value - ); + queryToolPref.reflectPreferences(self); + /* Register for preference changed event broadcasted in parent + * to reload the shorcuts. As sqleditor is in iFrame of wcDocker + * window parent is referred + */ + pgBrowser.onPreferencesChange('sqleditor', function() { + let browser = window.opener ? + window.opener.pgAdmin.Browser : window.top.pgAdmin.Browser; + self.preferences = browser.get_preferences_for_module('sqleditor'); + self.handler.preferences = self.preferences; + queryToolPref.reflectPreferences(self); + }); + + /* If sql editor is in a new tab, event fired is not available + * instead, a poller is set up who will check if the window.opener + * prefcache_version is updated. If updated, the new tab will update its + * preferences and reflect it + */ + if(self.preferences.new_browser_tab) { + setInterval(()=>{ + if(window.opener.pgAdmin && + pgBrowser.preference_version() < window.opener.pgAdmin.Browser.preference_version()) + { + pgBrowser.preference_version(window.opener.pgAdmin.Browser.preference_version()); + self.preferences = window.opener.pgAdmin.Browser.get_preferences_for_module('sqleditor'); + queryToolPref.reflectPreferences(self); + } + }, 1000); } }, @@ -805,6 +804,11 @@ define('tools.querytool', [ }; self.handler.slickgrid = grid; + self.handler.slickgrid.CSVOptions = { + quoting: self.preferences.results_grid_quoting, + quote_char: self.preferences.results_grid_quote_char, + field_separator: self.preferences.results_grid_field_separator, + }; // Listener function to watch selected rows from grid if (editor_data.selection) { @@ -903,29 +907,6 @@ define('tools.querytool', [ handleQueryOutputKeyboardEvent(event, args); }); } else { - var pref_cache = undefined; - args.grid.CSVOptions = {}; - - if (self.handler.is_new_browser_tab) { - pref_cache = window.opener.pgAdmin.Browser.preferences_cache; - } else { - pref_cache = window.top.pgAdmin.Browser.preferences_cache; - } - - // Get CSV options from preferences cache - args.grid.CSVOptions.quoting = _.findWhere(pref_cache, { - 'module': 'sqleditor', - 'name': 'results_grid_quoting', - }).value; - args.grid.CSVOptions.quote_char = _.findWhere(pref_cache, { - 'module': 'sqleditor', - 'name': 'results_grid_quote_char', - }).value; - args.grid.CSVOptions.field_separator = _.findWhere(pref_cache, { - 'module': 'sqleditor', - 'name': 'results_grid_field_separator', - }).value; - handleQueryOutputKeyboardEvent(event, args); } }); @@ -1196,7 +1177,10 @@ define('tools.querytool', [ render_history_grid: function() { var self = this; - self.history_collection = new HistoryBundle.HistoryCollection([]); + /* Should not reset if function called again */ + if(!self.history_collection) { + self.history_collection = new HistoryBundle.HistoryCollection([]); + } var historyComponent; var historyCollectionReactElement = React.createElement( @@ -1205,9 +1189,13 @@ define('tools.querytool', [ ref: function(component) { historyComponent = component; }, + sqlEditorPref: { + sql_font_size: SqlEditorUtils.calcFontSize(this.preferences.sql_font_size), + }, }); ReactDOM.render(historyCollectionReactElement, $('#history_grid')[0]); + self.history_panel.off(wcDocker.EVENT.VISIBILITY_CHANGED); self.history_panel.on(wcDocker.EVENT.VISIBILITY_CHANGED, function() { historyComponent.refocus(); }); @@ -1416,29 +1404,7 @@ define('tools.querytool', [ // Callback function for copy button click. on_copy_row: function() { - var self = this, - pref_cache = undefined; - self.grid.CSVOptions = {}; - - if (self.handler.is_new_browser_tab) { - pref_cache = window.opener.pgAdmin.Browser.preferences_cache; - } else { - pref_cache = window.top.pgAdmin.Browser.preferences_cache; - } - - // Get CSV options from preferences cache - self.grid.CSVOptions.quoting = _.findWhere(pref_cache, { - 'module': 'sqleditor', - 'name': 'results_grid_quoting', - }).value; - self.grid.CSVOptions.quote_char = _.findWhere(pref_cache, { - 'module': 'sqleditor', - 'name': 'results_grid_quote_char', - }).value; - self.grid.CSVOptions.field_separator = _.findWhere(pref_cache, { - 'module': 'sqleditor', - 'name': 'results_grid_field_separator', - }).value; + var self = this; // Trigger the copy signal to the SqlEditorController class self.handler.trigger( @@ -1708,7 +1674,7 @@ define('tools.querytool', [ keyAction: function(event) { var panel_id, self = this; panel_id = keyboardShortcuts.processEventQueryTool( - this.handler, this.keyboardShortcutConfig, queryToolActions, event + this.handler, queryToolActions, event ); // If it return panel id then focus it @@ -1933,23 +1899,17 @@ define('tools.querytool', [ * header and loading icon and start execution of the sql query. */ start: function(transId, is_query_tool, editor_title, script_type_url, - is_new_browser_tab, server_type, prompt_save_changes, url_params + server_type, url_params ) { var self = this; self.is_query_tool = is_query_tool; self.rows_affected = 0; self.marked_line_no = 0; - self.explain_verbose = false; - self.explain_costs = false; - self.explain_buffers = false; - self.explain_timing = false; - self.is_new_browser_tab = is_new_browser_tab; self.has_more_rows = false; self.fetching_rows = false; self.close_on_save = false; self.server_type = server_type; - self.prompt_save_changes = prompt_save_changes; self.url_params = url_params; self.script_type_url = script_type_url; @@ -2022,7 +1982,6 @@ define('tools.querytool', [ // Listen to the codemirror on text change event // only in query editor tool if (self.is_query_tool) { - self.get_preferences(); self.gridView.query_tool_obj.on('change', self._on_query_change.bind(self)); } @@ -2830,7 +2789,7 @@ define('tools.querytool', [ setTitle: function(title, unsafe) { var self = this; - if (self.is_new_browser_tab) { + if (self.preferences.new_browser_tab) { window.document.title = title; } else { _.each(window.top.pgAdmin.Browser.docker.findPanels('frm_datagrid'), function(p) { @@ -2992,7 +2951,7 @@ define('tools.querytool', [ var title = self.gridView.current_file.replace(/^.*[\\\/]/g, '') + ' *'; self.setTitle(title, true); } else { - if (self.is_new_browser_tab) { + if (self.preferences.new_browser_tab) { title = window.document.title + ' *'; } else { // Find the title of the visible panel @@ -3570,22 +3529,8 @@ define('tools.querytool', [ }); }, - // This function will toggle "verbose" option in explain - _explain_verbose: function() { - var self = this; - if ($('.explain-verbose').hasClass('visibility-hidden') === true) { - $('.explain-verbose').removeClass('visibility-hidden'); - self.explain_verbose = true; - } else { - $('.explain-verbose').addClass('visibility-hidden'); - self.explain_verbose = false; - } - - // Set this option in preferences - var data = { - 'explain_verbose': self.explain_verbose, - }; - + explainPreferenceUpdate: function(subItem, data, caller) { + let self = this; $.ajax({ url: url_for('sqleditor.query_tool_preferences', { 'trans_id': self.transId, @@ -3596,133 +3541,94 @@ define('tools.querytool', [ success: function(res) { if (res.success == undefined || !res.success) { alertify.alert(gettext('Explain options error'), - gettext('Error occurred while setting verbose option in explain.') + gettext('Error occurred while setting %(subItem)s option in explain.', + {subItem : subItem}) ); } }, error: function(e) { let msg = httpErrorHandler.handleQueryToolAjaxError( - pgAdmin, self, e, '_explain_verbose', [], true + pgAdmin, self, e, caller, [], true ); alertify.alert(gettext('Explain options error'), msg); }, }); }, + // This function will toggle "verbose" option in explain + _explain_verbose: function() { + var self = this; + let explain_verbose = false; + if ($('.explain-verbose').hasClass('visibility-hidden') === true) { + $('.explain-verbose').removeClass('visibility-hidden'); + explain_verbose = true; + } else { + $('.explain-verbose').addClass('visibility-hidden'); + explain_verbose = false; + } + + self.explainPreferenceUpdate( + 'verbose', { + 'explain_verbose': explain_verbose, + }, '_explain_verbose' + ); + }, + // This function will toggle "costs" option in explain _explain_costs: function() { var self = this; + let explain_costs = false; if ($('.explain-costs').hasClass('visibility-hidden') === true) { $('.explain-costs').removeClass('visibility-hidden'); - self.explain_costs = true; + explain_costs = true; } else { $('.explain-costs').addClass('visibility-hidden'); - self.explain_costs = false; + explain_costs = false; } - // Set this option in preferences - var data = { - 'explain_costs': self.explain_costs, - }; - - $.ajax({ - url: url_for('sqleditor.query_tool_preferences', { - 'trans_id': self.transId, - }), - method: 'PUT', - contentType: 'application/json', - data: JSON.stringify(data), - success: function(res) { - if (res.success == undefined || !res.success) { - alertify.alert(gettext('Explain options error'), - gettext('Error occurred while setting costs option in explain.') - ); - } - }, - error: function(e) { - let msg = httpErrorHandler.handleQueryToolAjaxError( - pgAdmin, self, e, '_explain_costs', [], true - ); - alertify.alert(gettext('Explain options error'), msg); - }, - }); + self.explainPreferenceUpdate( + 'costs', { + 'explain_costs': explain_costs, + }, '_explain_costs' + ); }, // This function will toggle "buffers" option in explain _explain_buffers: function() { var self = this; + let explain_buffers = false; if ($('.explain-buffers').hasClass('visibility-hidden') === true) { $('.explain-buffers').removeClass('visibility-hidden'); - self.explain_buffers = true; + explain_buffers = true; } else { $('.explain-buffers').addClass('visibility-hidden'); - self.explain_buffers = false; + explain_buffers = false; } - // Set this option in preferences - var data = { - 'explain_buffers': self.explain_buffers, - }; - - $.ajax({ - url: url_for('sqleditor.query_tool_preferences', { - 'trans_id': self.transId, - }), - method: 'PUT', - contentType: 'application/json', - data: JSON.stringify(data), - success: function(res) { - if (res.success == undefined || !res.success) { - alertify.alert(gettext('Explain options error'), - gettext('Error occurred while setting buffers option in explain.') - ); - } - }, - error: function(e) { - let msg = httpErrorHandler.handleQueryToolAjaxError( - pgAdmin, self, e, '_explain_buffers', [], true - ); - alertify.alert(gettext('Explain options error'), msg); - }, - }); + self.explainPreferenceUpdate( + 'buffers', { + 'explain_buffers': explain_buffers, + }, '_explain_buffers' + ); }, // This function will toggle "timing" option in explain _explain_timing: function() { var self = this; + let explain_timing = false; if ($('.explain-timing').hasClass('visibility-hidden') === true) { $('.explain-timing').removeClass('visibility-hidden'); - self.explain_timing = true; + explain_timing = true; } else { $('.explain-timing').addClass('visibility-hidden'); - self.explain_timing = false; + explain_timing = false; } - // Set this option in preferences - var data = { - 'explain_timing': self.explain_timing, - }; - $.ajax({ - url: url_for('sqleditor.query_tool_preferences', { - 'trans_id': self.transId, - }), - method: 'PUT', - contentType: 'application/json', - data: JSON.stringify(data), - success: function(res) { - if (res.success == undefined || !res.success) { - alertify.alert(gettext('Explain options error'), - gettext('Error occurred while setting timing option in explain.') - ); - } - }, - error: function(e) { - let msg = httpErrorHandler.handleQueryToolAjaxError( - pgAdmin, self, e, '_explain_timing', [], true - ); - alertify.alert(gettext('Explain options error'), msg); - }, - }); + self.explainPreferenceUpdate( + 'timing', { + 'explain_timing': explain_timing, + }, '_explain_timing' + ); }, /* @@ -3751,85 +3657,6 @@ define('tools.querytool', [ is_query_running = value; }, - /* - * This function get explain options and auto rollback/auto commit - * values from preferences - */ - get_preferences: function() { - var self = this, - explain_verbose = false, - explain_costs = false, - explain_buffers = false, - explain_timing = false, - auto_commit = true, - auto_rollback = false, - updateUI = function() { - // Set Auto-commit and auto-rollback on query editor - if (auto_commit && - $('.auto-commit').hasClass('visibility-hidden') === true) - $('.auto-commit').removeClass('visibility-hidden'); - else { - $('.auto-commit').addClass('visibility-hidden'); - } - if (auto_rollback && - $('.auto-rollback').hasClass('visibility-hidden') === true) - $('.auto-rollback').removeClass('visibility-hidden'); - else { - $('.auto-rollback').addClass('visibility-hidden'); - } - - // Set explain options on query editor - if (explain_verbose && - $('.explain-verbose').hasClass('visibility-hidden') === true) - $('.explain-verbose').removeClass('visibility-hidden'); - else { - $('.explain-verbose').addClass('visibility-hidden'); - } - if (explain_costs && - $('.explain-costs').hasClass('visibility-hidden') === true) - $('.explain-costs').removeClass('visibility-hidden'); - else { - $('.explain-costs').addClass('visibility-hidden'); - } - if (explain_buffers && - $('.explain-buffers').hasClass('visibility-hidden') === true) - $('.explain-buffers').removeClass('visibility-hidden'); - else { - $('.explain-buffers').addClass('visibility-hidden'); - } - if (explain_timing && - $('.explain-timing').hasClass('visibility-hidden') === true) - $('.explain-timing').removeClass('visibility-hidden'); - else { - $('.explain-timing').addClass('visibility-hidden'); - } - }; - - $.ajax({ - url: url_for('sqleditor.query_tool_preferences', { - 'trans_id': self.transId, - }), - method: 'GET', - success: function(res) { - if (res.data) { - explain_verbose = res.data.explain_verbose; - explain_costs = res.data.explain_costs; - explain_buffers = res.data.explain_buffers; - explain_timing = res.data.explain_timing; - auto_commit = res.data.auto_commit; - auto_rollback = res.data.auto_rollback; - updateUI(); - } - }, - error: function(e) { - let msg = httpErrorHandler.handleQueryToolAjaxError( - pgAdmin, self, e, 'get_preferences', [], true - ); - updateUI(); - alertify.alert(gettext('Get Preferences error'), msg); - }, - }); - }, close: function() { var self = this; diff --git a/web/pgadmin/tools/sqleditor/tests/test_pref_utilities.py b/web/pgadmin/tools/sqleditor/tests/test_pref_utilities.py deleted file mode 100644 index cbd141b0..00000000 --- a/web/pgadmin/tools/sqleditor/tests/test_pref_utilities.py +++ /dev/null @@ -1,100 +0,0 @@ -########################################################################## -# -# pgAdmin 4 - PostgreSQL Tools -# -# Copyright (C) 2013 - 2018, The pgAdmin Development Team -# This software is released under the PostgreSQL Licence -# -########################################################################## -from pgadmin.utils.route import BaseTestGenerator -from pgadmin.tools.sqleditor.utils.query_tool_preferences import \ - get_text_representation_of_shortcut - - -class TestQueryToolPreference(BaseTestGenerator): - """ - Ensures that we are able to fetch preferences properly - """ - scenarios = [ - ('Check text representation of a valid shortcuts', dict( - fetch_pref=True, - sample_shortcut=dict( - alt=False, - shift=False, - control=False, - key=dict( - char='a', - keyCode=65 - ) - ), - expected_result='a' - )), - - ('Check text representation of a valid shortcuts', dict( - fetch_pref=True, - sample_shortcut=dict( - alt=True, - shift=False, - control=False, - key=dict( - char='a', - keyCode=65 - ) - ), - expected_result='Alt+a' - )), - - ('Check text representation of a valid shortcuts', dict( - fetch_pref=True, - sample_shortcut=dict( - alt=True, - shift=True, - control=True, - key=dict( - char='a', - keyCode=65 - ) - ), - expected_result='Alt+Shift+Ctrl+a' - )), - - ('Check text representation of a valid shortcuts', dict( - fetch_pref=True, - sample_shortcut=dict( - alt=False, - shift=True, - control=False, - key=dict( - char='a', - keyCode=65 - ) - ), - expected_result='Shift+a' - )), - - ('Check text representation of a valid shortcuts', dict( - fetch_pref=True, - sample_shortcut=dict( - alt=True, - shift=True, - control=False, - key=dict( - char='a', - keyCode=65 - ) - ), - expected_result='Alt+Shift+a' - )), - - ('Check text representation of a invalid shortcuts', dict( - fetch_pref=True, - sample_shortcut=None, - expected_result='' - )) - - ] - - def runTest(self): - """Check correct function is called to handle to run query.""" - result = get_text_representation_of_shortcut(self.sample_shortcut) - self.assertEquals(result, self.expected_result) diff --git a/web/pgadmin/tools/sqleditor/utils/query_tool_preferences.py b/web/pgadmin/tools/sqleditor/utils/query_tool_preferences.py index a5a7bcb8..5e2a8ef1 100644 --- a/web/pgadmin/tools/sqleditor/utils/query_tool_preferences.py +++ b/web/pgadmin/tools/sqleditor/utils/query_tool_preferences.py @@ -560,123 +560,3 @@ def RegisterQueryToolPreferences(self): help_str=gettext('If set to True, Keywords will be displayed ' 'in upper case for auto completion.') ) - - -def get_query_tool_keyboard_shortcuts(): - - """ - Fetch all the query tool shortcut preferences - - Returns: - List of query tool shortcut preferences - """ - qt_perf = Preferences.module('sqleditor') - conn_status = qt_perf.preference('btn_conn_status').get() - clear_options = qt_perf.preference('btn_clear_options').get() - cancel_query = qt_perf.preference('btn_cancel_query').get() - execute_options = qt_perf.preference('btn_execute_options').get() - filter_options = qt_perf.preference('btn_filter_options').get() - rows_limit = qt_perf.preference('btn_rows_limit').get() - filter_dialog = qt_perf.preference('btn_filter_dialog').get() - delete_row = qt_perf.preference('btn_delete_row').get() - paste_row = qt_perf.preference('btn_paste_row').get() - copy_row = qt_perf.preference('btn_copy_row').get() - save_file = qt_perf.preference('btn_save_file').get() - open_file = qt_perf.preference('btn_open_file').get() - move_next = qt_perf.preference('move_next').get() - move_previous = qt_perf.preference('move_previous').get() - download_csv = qt_perf.preference('download_csv').get() - execute_query = qt_perf.preference('execute_query').get() - explain_query = qt_perf.preference('explain_query').get() - explain_analyze_query = qt_perf.preference('explain_analyze_query').get() - find_options = qt_perf.preference('btn_find_options').get() - toggle_case = qt_perf.preference('toggle_case').get() - - return { - 'keys': { - 'conn_status': conn_status.get('key').get('char'), - 'clear_options': clear_options.get('key').get('char'), - 'cancel_query': cancel_query.get('key').get('char'), - 'execute_options': execute_options.get('key').get('char'), - 'filter_options': filter_options.get('key').get('char'), - 'rows_limit': rows_limit.get('key').get('char'), - 'filter_dialog': filter_dialog.get('key').get('char'), - 'delete_row': delete_row.get('key').get('char'), - 'paste_row': paste_row.get('key').get('char'), - 'copy_row': copy_row.get('key').get('char'), - 'save_file': save_file.get('key').get('char'), - 'open_file': open_file.get('key').get('char'), - 'move_next': move_next.get('key').get('char'), - 'move_previous': move_previous.get('key').get('char'), - 'download_csv': download_csv.get('key').get('char'), - 'execute_query': execute_query.get('key').get('char'), - 'explain_query': explain_query.get('key').get('char'), - 'explain_analyze_query': explain_analyze_query.get('key').get( - 'char' - ), - 'find_options': find_options.get('key').get('char'), - 'toggle_case': toggle_case.get('key').get('char') - }, - 'shortcuts': { - 'conn_status': conn_status, - 'clear_options': clear_options, - 'cancel_query': cancel_query, - 'execute_options': execute_options, - 'filter_options': filter_options, - 'rows_limit': rows_limit, - 'filter_dialog': filter_dialog, - 'delete_row': delete_row, - 'paste_row': paste_row, - 'copy_row': copy_row, - 'save_file': save_file, - 'open_file': open_file, - 'move_next': move_next, - 'move_previous': move_previous, - 'download_csv': download_csv, - 'execute_query': execute_query, - 'explain_query': explain_query, - 'explain_analyze_query': explain_analyze_query, - 'find_options': find_options, - 'toggle_case': toggle_case - }, - } - - -def get_text_representation_of_shortcut(shortcut): - """ - Coverts shortcut object to text representation - - Args: - shortcut: Shortcut object - - Returns: - Text representation of given shortcut - """ - text_representation = '' - is_plus_required = False - - if not shortcut: - return text_representation - - if shortcut['alt']: - text_representation = gettext('Alt') - is_plus_required = True - - if shortcut['shift']: - if is_plus_required: - text_representation += '+' - text_representation += gettext('Shift') - is_plus_required = True - - if shortcut['control']: - if is_plus_required: - text_representation += '+' - text_representation += gettext('Ctrl') - is_plus_required = True - - if shortcut['key'] and shortcut['key']['char']: - if is_plus_required: - text_representation += '+' - text_representation += '{0}'.format(shortcut['key']['char']) - - return text_representation diff --git a/web/regression/javascript/browser/preferences_spec.js b/web/regression/javascript/browser/preferences_spec.js new file mode 100644 index 00000000..956b2c36 --- /dev/null +++ b/web/regression/javascript/browser/preferences_spec.js @@ -0,0 +1,140 @@ +import {pgBrowser} from 'pgadmin.browser.preferences'; +import $ from 'jquery'; + +var dummy_cache = [ + { + id: 1, + mid: 1, + module:'module1', + name:'pref1', + value:{ + alt: false, + shift: false, + control: false, + key: { + char: 'a', + key_code: 65, + }, + }, + },{ + id: 2, + mid: 1, + module:'module1', + name:'pref2', + value: 123, + },{ + id: 3, + mid: 2, + module:'module2', + name:'pref2', + value: true, + }, +]; + +describe('preferences related functions test', function() { + describe('get preference data related functions', function(){ + beforeEach(function(){ + pgBrowser.preferences_cache = dummy_cache; + }); + + it('get_preference', function(){ + expect(pgBrowser.get_preference('module1','pref1')).toEqual({ + id: 1, + mid: 1, + module:'module1', + name:'pref1', + value:{ + alt: false, + shift: false, + control: false, + key: { + char: 'a', + key_code: 65, + }, + }, + }); + }); + + it('get_preferences_for_module', function() { + expect(pgBrowser.get_preferences_for_module('module1')).toEqual({ + 'pref1':{ + alt: false, + shift: false, + control: false, + key: { + char: 'a', + key_code: 65, + }, + }, + 'pref2': 123, + }); + }); + + it('get_preference_for_id', function() { + expect(pgBrowser.get_preference_for_id(3)).toEqual({ + id: 3, + mid: 2, + module:'module2', + name:'pref2', + value: true, + }); + }); + + it('reflectPreferences', function() { + + let editorOptions = { + 'tabSize':2, + 'lineWrapping':false, + 'autoCloseBrackets':true, + 'matchBrackets':true, + }; + pgBrowser.preferences_cache.push({ + id: 4, mid: 3, module:'sqleditor', name:'sql_font_size', value: 1.456, + }); + pgBrowser.preferences_cache.push({ + id: 4, mid: 3, module:'sqleditor', name:'tab_size', value: editorOptions.tabSize, + }); + pgBrowser.preferences_cache.push({ + id: 4, mid: 3, module:'sqleditor', name:'wrap_code', value: editorOptions.lineWrapping, + }); + pgBrowser.preferences_cache.push({ + id: 4, mid: 3, module:'sqleditor', name:'insert_pair_brackets', value: editorOptions.autoCloseBrackets, + }); + pgBrowser.preferences_cache.push({ + id: 4, mid: 3, module:'sqleditor', name:'brace_matching', value: editorOptions.matchBrackets, + }); + + /* Spies */ + pgBrowser.editor = jasmine.createSpyObj( + 'CodeMirror', ['setOption','refresh','getWrapperElement'] + ); + spyOn($.fn, 'css'); + + /* Call */ + pgBrowser.reflectPreferences(); + + /* Tests */ + expect(pgBrowser.editor.getWrapperElement).toHaveBeenCalled(); + expect($.fn.css).toHaveBeenCalledWith('font-size', '1.46em'); + + let setOptionCalls = pgBrowser.editor.setOption.calls; + expect(setOptionCalls.count()).toBe(Object.keys(editorOptions).length); + + for(let i = 0; i < Object.keys(editorOptions).length; i++) { + let option = Object.keys(editorOptions)[i]; + expect(setOptionCalls.argsFor(i)).toEqual([option, editorOptions[option]]); + } + expect(pgBrowser.editor.refresh).toHaveBeenCalled(); + }); + + it('onPreferencesChange', function() { + + window.parent.$ = $; + spyOn($.fn, 'on'); + + var eventHandler = jasmine.createSpy('eventHandler'); + pgBrowser.onPreferencesChange('somemodule', eventHandler); + expect($.fn.on.calls.mostRecent().args[0]).toEqual('prefchange:somemodule'); + }); + }); +}); diff --git a/web/regression/javascript/history/query_history_spec.jsx b/web/regression/javascript/history/query_history_spec.jsx index c49b19f0..b90d2a30 100644 --- a/web/regression/javascript/history/query_history_spec.jsx +++ b/web/regression/javascript/history/query_history_spec.jsx @@ -29,7 +29,7 @@ import '../helper/enzyme.helper'; describe('QueryHistory', () => { let historyCollection; let historyWrapper; - + let sqlEditorPref = {sql_font_size: '1em'}; beforeEach(() => { jasmineEnzyme(); }); @@ -37,7 +37,9 @@ describe('QueryHistory', () => { describe('when there is no history', () => { beforeEach(() => { historyCollection = new HistoryCollection([]); - historyWrapper = mount(<QueryHistory historyCollection={historyCollection}/>); + historyWrapper = mount(<QueryHistory historyCollection={historyCollection} + sqlEditorPref={sqlEditorPref} + />); }); describe('when we switch to the query history tab', () => { @@ -89,8 +91,9 @@ describe('QueryHistory', () => { message: 'something important ERROR: message from second sql query', }]; historyCollection = new HistoryCollection(historyObjects); - - historyWrapper = mount(<QueryHistory historyCollection={historyCollection}/>); + historyWrapper = mount(<QueryHistory historyCollection={historyCollection} + sqlEditorPref={sqlEditorPref} + />); queryHistoryEntriesComponent = historyWrapper.find(QueryHistoryEntries); isInvisibleSpy = spyOn(queryHistoryEntriesComponent.instance(), 'isInvisible') @@ -479,7 +482,9 @@ describe('QueryHistory', () => { }]; historyCollection = new HistoryCollection(historyObjects); - historyWrapper = mount(<QueryHistory historyCollection={historyCollection}/>); + historyWrapper = mount(<QueryHistory historyCollection={historyCollection} + sqlEditorPref={sqlEditorPref} + />); const queryHistoryEntriesComponent = historyWrapper.find(QueryHistoryEntries); isInvisibleSpy = spyOn(queryHistoryEntriesComponent.instance(), 'isInvisible') diff --git a/web/regression/javascript/sqleditor/keyboard_shortcuts_spec.js b/web/regression/javascript/sqleditor/keyboard_shortcuts_spec.js index 06586d34..0e774814 100644 --- a/web/regression/javascript/sqleditor/keyboard_shortcuts_spec.js +++ b/web/regression/javascript/sqleditor/keyboard_shortcuts_spec.js @@ -9,6 +9,7 @@ import keyboardShortcuts from 'sources/keyboard_shortcuts'; import {queryToolActions} from 'sources/sqleditor/query_tool_actions'; +import gettext from 'sources/gettext'; describe('the keyboard shortcuts', () => { const F1_KEY = 112, @@ -18,7 +19,7 @@ describe('the keyboard shortcuts', () => { PERIOD_KEY = 190, FWD_SLASH_KEY = 191; - let sqlEditorControllerSpy, event, queryToolActionsSpy, queryToolkeyboardShortcutsConfig; + let sqlEditorControllerSpy, event, queryToolActionsSpy; beforeEach(() => { event = { shift: false, @@ -29,8 +30,22 @@ describe('the keyboard shortcuts', () => { stopImmediatePropagation: jasmine.createSpy('stopImmediatePropagation'), }; - queryToolkeyboardShortcutsConfig = { - execute: { + let gridView = { + query_tool_obj: { + getSelection: jasmine.createSpy('getSelection'), + getValue: jasmine.createSpy('getValue'), + }, + }; + + sqlEditorControllerSpy = jasmine.createSpyObj('SqlEditorController', [ + 'isQueryRunning', + 'execute', + ]); + + sqlEditorControllerSpy.gridView = gridView; + + sqlEditorControllerSpy.preferences = { + execute_query: { alt: false, shift: false, control: false, @@ -38,7 +53,7 @@ describe('the keyboard shortcuts', () => { key_code: F5_KEY, }, }, - explain: { + explain_query: { alt: false, shift: false, control: false, @@ -46,7 +61,7 @@ describe('the keyboard shortcuts', () => { key_code: F7_KEY, }, }, - explain_analyze: { + explain_analyze_query: { alt: false, shift: true, control: false, @@ -80,20 +95,6 @@ describe('the keyboard shortcuts', () => { }, }; - let gridView = { - query_tool_obj: { - getSelection: jasmine.createSpy('getSelection'), - getValue: jasmine.createSpy('getValue'), - }, - }; - - sqlEditorControllerSpy = jasmine.createSpyObj('SqlEditorController', [ - 'isQueryRunning', - 'execute', - ]); - - sqlEditorControllerSpy.gridView = gridView; - queryToolActionsSpy = jasmine.createSpyObj(queryToolActions, [ 'explainAnalyze', 'explain', @@ -110,8 +111,7 @@ describe('the keyboard shortcuts', () => { beforeEach(() => { event.which = F1_KEY; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); @@ -128,8 +128,7 @@ describe('the keyboard shortcuts', () => { event.shiftKey = false; event.ctrlKey = false; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); @@ -151,8 +150,7 @@ describe('the keyboard shortcuts', () => { sqlEditorControllerSpy.isQueryRunning.and.returnValue(true); keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); expect(queryToolActionsSpy.executeQuery).not.toHaveBeenCalled(); @@ -168,8 +166,7 @@ describe('the keyboard shortcuts', () => { event.shiftKey = false; event.ctrlKey = false; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); @@ -189,8 +186,7 @@ describe('the keyboard shortcuts', () => { sqlEditorControllerSpy.isQueryRunning.and.returnValue(true); keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); expect(queryToolActionsSpy.explain).not.toHaveBeenCalled(); @@ -206,8 +202,7 @@ describe('the keyboard shortcuts', () => { event.altKey = false; event.ctrlKey = false; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); @@ -228,8 +223,7 @@ describe('the keyboard shortcuts', () => { sqlEditorControllerSpy.isQueryRunning.and.returnValue(true); keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); expect(queryToolActionsSpy.explainAnalyze).not.toHaveBeenCalled(); @@ -246,8 +240,7 @@ describe('the keyboard shortcuts', () => { event.ctrlKey = false; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); @@ -270,8 +263,7 @@ describe('the keyboard shortcuts', () => { sqlEditorControllerSpy.isQueryRunning.and.returnValue(true); keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); expect(queryToolActionsSpy.download).not.toHaveBeenCalled(); @@ -286,8 +278,7 @@ describe('the keyboard shortcuts', () => { macKeysSetup(); event.which = FWD_SLASH_KEY; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); @@ -303,8 +294,7 @@ describe('the keyboard shortcuts', () => { windowsKeysSetup(); event.which = FWD_SLASH_KEY; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); @@ -328,8 +318,7 @@ describe('the keyboard shortcuts', () => { it('does nothing', () => { keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); expect(queryToolActionsSpy.commentLineCode).not.toHaveBeenCalled(); @@ -344,8 +333,7 @@ describe('the keyboard shortcuts', () => { it('does nothing', () => { keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); expect(queryToolActionsSpy.commentLineCode).not.toHaveBeenCalled(); @@ -361,8 +349,7 @@ describe('the keyboard shortcuts', () => { macKeysSetup(); event.which = PERIOD_KEY; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); @@ -377,8 +364,7 @@ describe('the keyboard shortcuts', () => { windowsKeysSetup(); event.which = PERIOD_KEY; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); @@ -402,8 +388,7 @@ describe('the keyboard shortcuts', () => { it('does nothing', () => { keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); expect(queryToolActionsSpy.uncommentLineCode).not.toHaveBeenCalled(); }); @@ -416,8 +401,7 @@ describe('the keyboard shortcuts', () => { it('does nothing', () => { keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); expect(queryToolActionsSpy.uncommentLineCode).not.toHaveBeenCalled(); @@ -434,8 +418,7 @@ describe('the keyboard shortcuts', () => { event.which = FWD_SLASH_KEY; event.shiftKey = true; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); @@ -454,8 +437,7 @@ describe('the keyboard shortcuts', () => { event.which = FWD_SLASH_KEY; event.shiftKey = true; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); @@ -477,8 +459,7 @@ describe('the keyboard shortcuts', () => { event.which = FWD_SLASH_KEY; event.shiftKey = true; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); it('does nothing', () => { @@ -491,8 +472,7 @@ describe('the keyboard shortcuts', () => { event.which = FWD_SLASH_KEY; event.shiftKey = true; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); it('does nothing', () => { @@ -502,6 +482,45 @@ describe('the keyboard shortcuts', () => { }); }); + describe('shortcut to text converters', ()=> { + var shortcut = { + alt: false, + shift: false, + control: false, + key: { + char: 'a', + key_code: 65, + }, + }; + + it('shortcut_key',()=>{ + expect(keyboardShortcuts.shortcut_key(shortcut)).toBe('A'); + }); + + it('shortcut_accesskey_title',()=>{ + expect(keyboardShortcuts.shortcut_accesskey_title( + 'Title', shortcut)).toBe(gettext('Title (accesskey + A)')); + }); + + it('shortcut_title',()=>{ + shortcut.alt = true, shortcut.shift = false, shortcut.control = false; + expect(keyboardShortcuts.shortcut_title( + 'Title', shortcut)).toBe(gettext('Title (Alt+A)')); + + shortcut.alt = false, shortcut.shift = true, shortcut.control = false; + expect(keyboardShortcuts.shortcut_title( + 'Title', shortcut)).toBe(gettext('Title (Shift+A)')); + + shortcut.alt = false, shortcut.shift = false, shortcut.control = true; + expect(keyboardShortcuts.shortcut_title( + 'Title', shortcut)).toBe(gettext('Title (Ctrl+A)')); + + shortcut.alt = true, shortcut.shift = true, shortcut.control = true; + expect(keyboardShortcuts.shortcut_title( + 'Title', shortcut)).toBe(gettext('Title (Alt+Shift+Ctrl+A)')); + }); + }); + function expectEventPropagationToStop() { describe('stops all event propogation', () => { diff --git a/web/regression/javascript/sqleditor_utils_spec.js b/web/regression/javascript/sqleditor_utils_spec.js index c738f82a..75c34afc 100644 --- a/web/regression/javascript/sqleditor_utils_spec.js +++ b/web/regression/javascript/sqleditor_utils_spec.js @@ -28,5 +28,13 @@ function (SqlEditorUtils) { expect(SqlEditorUtils.capitalizeFirstLetter('create script')).toEqual('Create script'); }); }); + + describe('Calculate font size of input number passed', function () { + it('calcFontSize', function () { + expect(SqlEditorUtils.calcFontSize(1.456)).toEqual('1.46em'); + expect(SqlEditorUtils.calcFontSize()).toEqual('0em'); + expect(SqlEditorUtils.calcFontSize(2)).toEqual('2em'); + }); + }); }); }); diff --git a/web/webpack.shim.js b/web/webpack.shim.js index c12e7f3b..41bf1033 100644 --- a/web/webpack.shim.js +++ b/web/webpack.shim.js @@ -124,6 +124,7 @@ var webpackShimConfig = { 'bundled_codemirror': path.join(__dirname, './pgadmin/static/bundle/codemirror'), 'bundled_browser': path.join(__dirname, './pgadmin/static/bundle/browser'), 'sources': path.join(__dirname, './pgadmin/static/js'), + 'sourcesjsx': path.join(__dirname, './pgadmin/static/jsx'), 'pgadmin': path.join(__dirname, './pgadmin/static/js/pgadmin'), 'translations': path.join(__dirname, './pgadmin/tools/templates/js/translations'), 'sources/gettext': path.join(__dirname, './pgadmin/static/js/gettext'), @@ -179,6 +180,7 @@ var webpackShimConfig = { 'pgadmin.browser.error': path.join(__dirname, './pgadmin/browser/static/js/error'), 'pgadmin.browser.frame': path.join(__dirname, './pgadmin/browser/static/js/frame'), 'pgadmin.browser.keyboard': path.join(__dirname, './pgadmin/browser/static/js/keyboard'), + 'pgadmin.browser.preferences': path.join(__dirname, './pgadmin/browser/static/js/preferences'), 'pgadmin.browser.menu': path.join(__dirname, './pgadmin/browser/static/js/menu'), 'pgadmin.browser.messages': '/browser/js/messages', 'pgadmin.browser.node': path.join(__dirname, './pgadmin/browser/static/js/node'), diff --git a/web/webpack.test.config.js b/web/webpack.test.config.js index ef893e0b..757107ca 100644 --- a/web/webpack.test.config.js +++ b/web/webpack.test.config.js @@ -83,6 +83,7 @@ module.exports = { 'pgadmin.backform': sourcesDir + '/js/backform.pgadmin', 'pgbrowser': path.resolve(__dirname, 'regression/javascript/fake_browser'), 'pgadmin.schema.dir': path.resolve(__dirname, 'pgadmin/browser/server_groups/servers/databases/schemas/static/js'), + 'pgadmin.browser.preferences': path.join(__dirname, './pgadmin/browser/static/js/preferences'), }, }, }; ^ permalink raw reply [nested|flat] 14+ messages in thread
* Re: [pgAdmin4][RM3294] User need to reset the layout to see the changed preferences parameters @ 2018-06-29 16:00 Dave Page <[email protected]> parent: Aditya Toshniwal <[email protected]> 0 siblings, 1 reply; 14+ messages in thread From: Dave Page @ 2018-06-29 16:00 UTC (permalink / raw) To: Aditya Toshniwal <[email protected]>; +Cc: Akshay Joshi <[email protected]>; pgadmin-hackers Hi On Fri, Jun 29, 2018 at 3:14 PM, Aditya Toshniwal < [email protected]> wrote: > Hi Hackers, > > Attached is the updated patch. > This seems to work for the most part, however I saw what seemed like odd behaviour. If I have 2 query tool windows open; - Changing a preference from the Preferences dialogue updates both query tools. - Changing a preference from a Query Tool updates the Preferences dialogue. - Changing a preference from a Query Tool does *not* update the other Query Tool. The last point seems odd to me, though it also kinda makes sense to not have one query tool affect the other. The problem with that is that it could get quite confusing when they get out of sync. I think it would be better for a change in one Query Tool to update the other(s). What do you think? Was this behaviour intentional? (FYI, in case this was a one-off bug, I was testing using "Auto Commit?") > > On Fri, Jun 29, 2018 at 4:46 PM, Aditya Toshniwal <aditya.toshniwal@ > enterprisedb.com> wrote: > >> Hi Akshay, >> >> On Fri, Jun 29, 2018 at 3:42 PM, Akshay Joshi < >> [email protected]> wrote: >> >>> Hi Aditya >>> >>> I have applied your patch and run pgAdmin4. I have found following two >>> issue in the browser: >>> >>> - Found error while open Preferences dialog. Refer >>> Open_Preferences_Dialog.png >>> >>> This error occurs even with the latest pull without changes. >> >> >>> >>> - Set the preferences setting "Open in new browser tab" to True and >>> open the query tool. Refer "Open_In_New_Broswer.png". >>> >>> Will look into this. >> >> >>> I haven't review the code. >>> >>> On Thu, Jun 28, 2018 at 8:04 PM, Aditya Toshniwal < >>> [email protected]> wrote: >>> >>>> Hi Hackers, >>>> >>>> Attached is the patch for making preferences realtime and applying >>>> without reseting the layout. Please note, the patch is only for one module >>>> - SQL Editor and is the first part for the RM. There are lot of changes to >>>> be done to cover all and hence sending in parts. This will not affect/break >>>> existing code. Further patches will cover other modules. >>>> >>>> Highlights of this patch include: >>>> - Changes will affect SQL Editors in Create dialog boxes, SQL tab of >>>> the main screen, Query tool, History entries in the query tool, Query tool >>>> opened in New Tab/Window >>>> - All the components of SQL editor will refer to single source of >>>> preferences which is cached in the Browser object. All other redundant ajax >>>> get preference calls are removed. >>>> - SQL editor will not refer template JS variables anymore, once all >>>> the references are removed the template variables will also be removed. >>>> - Code refactoring wherever possible. >>>> - Covered JS test cases wherever possible. >>>> >>>> Request you to kindly review. >>>> >>>> -- >>>> Thanks and Regards, >>>> Aditya Toshniwal >>>> Software Engineer | EnterpriseDB Software Solutions | Pune >>>> "Don't Complain about Heat, Plant a tree" >>>> >>> >>> >>> >>> -- >>> *Akshay Joshi* >>> >>> *Sr. Software Architect * >>> >>> >>> >>> *Phone: +91 20-3058-9517Mobile: +91 976-788-8246* >>> >> >> >> >> -- >> Thanks and Regards, >> Aditya Toshniwal >> Software Engineer | EnterpriseDB Software Solutions | Pune >> "Don't Complain about Heat, Plant a tree" >> > > > > -- > Thanks and Regards, > Aditya Toshniwal > Software Engineer | EnterpriseDB Software Solutions | Pune > "Don't Complain about Heat, Plant a tree" > -- Dave Page Blog: http://pgsnake.blogspot.com Twitter: @pgsnake EnterpriseDB UK: http://www.enterprisedb.com The Enterprise PostgreSQL Company ^ permalink raw reply [nested|flat] 14+ messages in thread
* Re: [pgAdmin4][RM3294] User need to reset the layout to see the changed preferences parameters @ 2018-06-29 17:09 Aditya Toshniwal <[email protected]> parent: Dave Page <[email protected]> 0 siblings, 1 reply; 14+ messages in thread From: Aditya Toshniwal @ 2018-06-29 17:09 UTC (permalink / raw) To: Dave Page <[email protected]>; +Cc: Akshay Joshi <[email protected]>; pgadmin-hackers Hi Dave, On Fri, Jun 29, 2018 at 9:30 PM, Dave Page <[email protected]> wrote: > Hi > > On Fri, Jun 29, 2018 at 3:14 PM, Aditya Toshniwal <aditya.toshniwal@ > enterprisedb.com> wrote: > >> Hi Hackers, >> >> Attached is the updated patch. >> > > This seems to work for the most part, however I saw what seemed like odd > behaviour. If I have 2 query tool windows open; > > - Changing a preference from the Preferences dialogue updates both query > tools. > > - Changing a preference from a Query Tool updates the Preferences dialogue. > > - Changing a preference from a Query Tool does *not* update the other > Query Tool. > > The last point seems odd to me, though it also kinda makes sense to not > have one query tool affect the other. The problem with that is that it > could get quite confusing when they get out of sync. I think it would be > better for a change in one Query Tool to update the other(s). > > What do you think? Was this behaviour intentional? > No this was not intentional. It should reflect in other query tools as well because changing the flags like Auto Commit changes the preferences config and is not local to a Query tool. I missed the fact that some preferences can be changed from other than preference dialog. Will send the updated patch with the fix. > > (FYI, in case this was a one-off bug, I was testing using "Auto Commit?") > > >> >> On Fri, Jun 29, 2018 at 4:46 PM, Aditya Toshniwal < >> [email protected]> wrote: >> >>> Hi Akshay, >>> >>> On Fri, Jun 29, 2018 at 3:42 PM, Akshay Joshi < >>> [email protected]> wrote: >>> >>>> Hi Aditya >>>> >>>> I have applied your patch and run pgAdmin4. I have found following two >>>> issue in the browser: >>>> >>>> - Found error while open Preferences dialog. Refer >>>> Open_Preferences_Dialog.png >>>> >>>> This error occurs even with the latest pull without changes. >>> >>> >>>> >>>> - Set the preferences setting "Open in new browser tab" to True and >>>> open the query tool. Refer "Open_In_New_Broswer.png". >>>> >>>> Will look into this. >>> >>> >>>> I haven't review the code. >>>> >>>> On Thu, Jun 28, 2018 at 8:04 PM, Aditya Toshniwal < >>>> [email protected]> wrote: >>>> >>>>> Hi Hackers, >>>>> >>>>> Attached is the patch for making preferences realtime and applying >>>>> without reseting the layout. Please note, the patch is only for one module >>>>> - SQL Editor and is the first part for the RM. There are lot of changes to >>>>> be done to cover all and hence sending in parts. This will not affect/break >>>>> existing code. Further patches will cover other modules. >>>>> >>>>> Highlights of this patch include: >>>>> - Changes will affect SQL Editors in Create dialog boxes, SQL tab of >>>>> the main screen, Query tool, History entries in the query tool, Query tool >>>>> opened in New Tab/Window >>>>> - All the components of SQL editor will refer to single source of >>>>> preferences which is cached in the Browser object. All other redundant ajax >>>>> get preference calls are removed. >>>>> - SQL editor will not refer template JS variables anymore, once all >>>>> the references are removed the template variables will also be removed. >>>>> - Code refactoring wherever possible. >>>>> - Covered JS test cases wherever possible. >>>>> >>>>> Request you to kindly review. >>>>> >>>>> -- >>>>> Thanks and Regards, >>>>> Aditya Toshniwal >>>>> Software Engineer | EnterpriseDB Software Solutions | Pune >>>>> "Don't Complain about Heat, Plant a tree" >>>>> >>>> >>>> >>>> >>>> -- >>>> *Akshay Joshi* >>>> >>>> *Sr. Software Architect * >>>> >>>> >>>> >>>> *Phone: +91 20-3058-9517Mobile: +91 976-788-8246* >>>> >>> >>> >>> >>> -- >>> Thanks and Regards, >>> Aditya Toshniwal >>> Software Engineer | EnterpriseDB Software Solutions | Pune >>> "Don't Complain about Heat, Plant a tree" >>> >> >> >> >> -- >> Thanks and Regards, >> Aditya Toshniwal >> Software Engineer | EnterpriseDB Software Solutions | Pune >> "Don't Complain about Heat, Plant a tree" >> > > > > -- > Dave Page > Blog: http://pgsnake.blogspot.com > Twitter: @pgsnake > > EnterpriseDB UK: http://www.enterprisedb.com > The Enterprise PostgreSQL Company > -- Thanks and Regards, Aditya Toshniwal Software Engineer | EnterpriseDB Software Solutions | Pune "Don't Complain about Heat, Plant a tree" ^ permalink raw reply [nested|flat] 14+ messages in thread
* Re: [pgAdmin4][RM3294] User need to reset the layout to see the changed preferences parameters @ 2018-07-04 09:19 Aditya Toshniwal <[email protected]> parent: Aditya Toshniwal <[email protected]> 0 siblings, 1 reply; 14+ messages in thread From: Aditya Toshniwal @ 2018-07-04 09:19 UTC (permalink / raw) To: Dave Page <[email protected]>; +Cc: Akshay Joshi <[email protected]>; pgadmin-hackers Hi Hackers, Attached is the updated patch for the RM. Change of the flags like auto commit, explain->verbose, etc. will reflect in all other open sql editors. Kindly review. On Fri, Jun 29, 2018 at 10:39 PM, Aditya Toshniwal < [email protected]> wrote: > Hi Dave, > > On Fri, Jun 29, 2018 at 9:30 PM, Dave Page <[email protected]> wrote: > >> Hi >> >> On Fri, Jun 29, 2018 at 3:14 PM, Aditya Toshniwal < >> [email protected]> wrote: >> >>> Hi Hackers, >>> >>> Attached is the updated patch. >>> >> >> This seems to work for the most part, however I saw what seemed like odd >> behaviour. If I have 2 query tool windows open; >> >> - Changing a preference from the Preferences dialogue updates both query >> tools. >> >> - Changing a preference from a Query Tool updates the Preferences >> dialogue. >> >> - Changing a preference from a Query Tool does *not* update the other >> Query Tool. >> >> The last point seems odd to me, though it also kinda makes sense to not >> have one query tool affect the other. The problem with that is that it >> could get quite confusing when they get out of sync. I think it would be >> better for a change in one Query Tool to update the other(s). >> >> What do you think? Was this behaviour intentional? >> > > No this was not intentional. It should reflect in other query tools as > well because changing the flags like Auto Commit changes the preferences > config and is not local to a Query tool. I missed the fact that some > preferences can be changed from other than preference dialog. > > Will send the updated patch with the fix. > >> >> (FYI, in case this was a one-off bug, I was testing using "Auto Commit?") >> >> >>> >>> On Fri, Jun 29, 2018 at 4:46 PM, Aditya Toshniwal < >>> [email protected]> wrote: >>> >>>> Hi Akshay, >>>> >>>> On Fri, Jun 29, 2018 at 3:42 PM, Akshay Joshi < >>>> [email protected]> wrote: >>>> >>>>> Hi Aditya >>>>> >>>>> I have applied your patch and run pgAdmin4. I have found following two >>>>> issue in the browser: >>>>> >>>>> - Found error while open Preferences dialog. Refer >>>>> Open_Preferences_Dialog.png >>>>> >>>>> This error occurs even with the latest pull without changes. >>>> >>>> >>>>> >>>>> - Set the preferences setting "Open in new browser tab" to True >>>>> and open the query tool. Refer "Open_In_New_Broswer.png". >>>>> >>>>> Will look into this. >>>> >>>> >>>>> I haven't review the code. >>>>> >>>>> On Thu, Jun 28, 2018 at 8:04 PM, Aditya Toshniwal < >>>>> [email protected]> wrote: >>>>> >>>>>> Hi Hackers, >>>>>> >>>>>> Attached is the patch for making preferences realtime and applying >>>>>> without reseting the layout. Please note, the patch is only for one module >>>>>> - SQL Editor and is the first part for the RM. There are lot of changes to >>>>>> be done to cover all and hence sending in parts. This will not affect/break >>>>>> existing code. Further patches will cover other modules. >>>>>> >>>>>> Highlights of this patch include: >>>>>> - Changes will affect SQL Editors in Create dialog boxes, SQL tab of >>>>>> the main screen, Query tool, History entries in the query tool, Query tool >>>>>> opened in New Tab/Window >>>>>> - All the components of SQL editor will refer to single source of >>>>>> preferences which is cached in the Browser object. All other redundant ajax >>>>>> get preference calls are removed. >>>>>> - SQL editor will not refer template JS variables anymore, once all >>>>>> the references are removed the template variables will also be removed. >>>>>> - Code refactoring wherever possible. >>>>>> - Covered JS test cases wherever possible. >>>>>> >>>>>> Request you to kindly review. >>>>>> >>>>>> -- >>>>>> Thanks and Regards, >>>>>> Aditya Toshniwal >>>>>> Software Engineer | EnterpriseDB Software Solutions | Pune >>>>>> "Don't Complain about Heat, Plant a tree" >>>>>> >>>>> >>>>> >>>>> >>>>> -- >>>>> *Akshay Joshi* >>>>> >>>>> *Sr. Software Architect * >>>>> >>>>> >>>>> >>>>> *Phone: +91 20-3058-9517Mobile: +91 976-788-8246* >>>>> >>>> >>>> >>>> >>>> -- >>>> Thanks and Regards, >>>> Aditya Toshniwal >>>> Software Engineer | EnterpriseDB Software Solutions | Pune >>>> "Don't Complain about Heat, Plant a tree" >>>> >>> >>> >>> >>> -- >>> Thanks and Regards, >>> Aditya Toshniwal >>> Software Engineer | EnterpriseDB Software Solutions | Pune >>> "Don't Complain about Heat, Plant a tree" >>> >> >> >> >> -- >> Dave Page >> Blog: http://pgsnake.blogspot.com >> Twitter: @pgsnake >> >> EnterpriseDB UK: http://www.enterprisedb.com >> The Enterprise PostgreSQL Company >> > > > > -- > Thanks and Regards, > Aditya Toshniwal > Software Engineer | EnterpriseDB Software Solutions | Pune > "Don't Complain about Heat, Plant a tree" > -- Thanks and Regards, Aditya Toshniwal Software Engineer | EnterpriseDB Software Solutions | Pune "Don't Complain about Heat, Plant a tree" Attachments: [application/octet-stream] 0001-RM3294.patch (109.3K, 3-0001-RM3294.patch) download | inline diff: diff --git a/web/pgadmin/browser/__init__.py b/web/pgadmin/browser/__init__.py index 3741d9d3..fb1eb7db 100644 --- a/web/pgadmin/browser/__init__.py +++ b/web/pgadmin/browser/__init__.py @@ -680,17 +680,6 @@ def browser_css(): """Render and return CSS snippets from the nodes and modules.""" snippets = [] - # Get configurable options - prefs = Preferences.module('sqleditor') - - sql_font_size_pref = prefs.preference('sql_font_size') - sql_font_size = round(float(sql_font_size_pref.get()), 2) - - if sql_font_size != 0: - snippets.append( - '.CodeMirror { font-size: %sem; }' % str(sql_font_size) - ) - for submodule in blueprint.submodules: snippets.extend(submodule.csssnippets) return make_response( diff --git a/web/pgadmin/browser/static/css/browser.css b/web/pgadmin/browser/static/css/browser.css index 3ba330d3..502812b8 100644 --- a/web/pgadmin/browser/static/css/browser.css +++ b/web/pgadmin/browser/static/css/browser.css @@ -1,3 +1,6 @@ +:root { + --codemirror-font-size : 1em; +} /* Styles for the main browser */ .browser-pane-container { position: absolute; @@ -66,3 +69,7 @@ samp, .pg-login-icon { font-size: 16px; } + +.CodeMirror { + font-size: var(--codemirror-font-size, '1em'); +} diff --git a/web/pgadmin/browser/static/js/browser.js b/web/pgadmin/browser/static/js/browser.js index b26738cf..c330a871 100644 --- a/web/pgadmin/browser/static/js/browser.js +++ b/web/pgadmin/browser/static/js/browser.js @@ -2,8 +2,8 @@ define('pgadmin.browser', [ 'sources/tree/tree', 'sources/gettext', 'sources/url_for', 'require', 'jquery', 'underscore', 'underscore.string', 'bootstrap', 'sources/pgadmin', 'pgadmin.alertifyjs', 'bundled_codemirror', - 'sources/check_node_visibility', 'sources/modify_animation', 'pgadmin.browser.utils', 'wcdocker', - 'jquery.contextmenu', 'jquery.aciplugin', 'jquery.acitree', + 'sources/check_node_visibility', 'pgadmin.browser.utils', 'wcdocker', + 'jquery.contextmenu', 'jquery.aciplugin', 'jquery.acitree', 'pgadmin.browser.preferences', 'pgadmin.browser.messages', 'pgadmin.browser.menu', 'pgadmin.browser.panel', 'pgadmin.browser.error', 'pgadmin.browser.frame', @@ -13,7 +13,7 @@ define('pgadmin.browser', [ ], function( tree, gettext, url_for, require, $, _, S, Bootstrap, pgAdmin, Alertify, - codemirror, checkNodeVisibility, modifyAnimation + codemirror, checkNodeVisibility ) { window.jQuery = window.$ = $; // Some scripts do export their object in the window only. @@ -342,7 +342,7 @@ define('pgadmin.browser', [ // Cache preferences obj.cache_preferences(); - this.add_panels(); + obj.add_panels(); // Initialize the Docker obj.docker = new wcDocker( '#dockerContainer', { @@ -400,11 +400,22 @@ define('pgadmin.browser', [ mode: 'text/x-pgsql', readOnly: true, extraKeys: pgAdmin.Browser.editor_shortcut_keys, - tabSize: pgAdmin.Browser.editor_options.tabSize, - lineWrapping: pgAdmin.Browser.editor_options.wrapCode, - autoCloseBrackets: pgAdmin.Browser.editor_options.insert_pair_brackets, - matchBrackets: pgAdmin.Browser.editor_options.brace_matching, }); + /* Cache may take time to load for the first time + * Reflect the changes once cache is available + */ + let cacheIntervalId = setInterval(()=> { + let sqlEditPreferences = obj.get_preferences_for_module('sqleditor'); + if(sqlEditPreferences) { + clearInterval(cacheIntervalId); + obj.reflectPreferences('sqleditor'); + } + }, 500); + + /* Check for sql editor preference changes */ + obj.onPreferencesChange('sqleditor', function() { + obj.reflectPreferences('sqleditor'); + }); setTimeout(function() { obj.editor.setValue('-- ' + select_object_msg); @@ -514,10 +525,6 @@ define('pgadmin.browser', [ }; }, - // This will hold preference data (Works as a cache object) - // Here node will be a key and it's preference data will be value - preferences_cache: {}, - // Add menus of module/extension at appropriate menu add_menus: function(menus) { var self = this, @@ -661,46 +668,6 @@ define('pgadmin.browser', [ } } }, - - // Get preference value from cache - get_preference: function(module, preference) { - var self = this; - // If cache is not yet loaded then keep checking - if(_.size(self.preferences_cache) == 0) { - var check_preference = function() { - if(_.size(self.preferences_cache) > 0) { - clearInterval(preferenceTimeout); - return _.findWhere( - self.preferences_cache, {'module': module, 'name': preference} - ); - } - }, - preferenceTimeout = setInterval(check_preference, 1000); - } - else { - return _.findWhere( - self.preferences_cache, {'module': module, 'name': preference} - ); - } - }, - - // Get and cache the preferences - cache_preferences: function () { - var self = this; - $.ajax({ - url: url_for('preferences.get_all'), - success: function(res) { - self.preferences_cache = res; - pgBrowser.keyboardNavigation.init(); - modifyAnimation.modifyAcitreeAnimation(self); - modifyAnimation.modifyAlertifyAnimation(self); - }, - error: function(xhr, status, error) { - Alertify.pgRespErrorNotify(xhr, error); - }, - }); - }, - _findTreeChildNode: function(_i, _d, _o) { var loaded = _o.t.wasLoad(_i), onLoad = function() { diff --git a/web/pgadmin/browser/static/js/preferences.js b/web/pgadmin/browser/static/js/preferences.js new file mode 100644 index 00000000..b0c6dc48 --- /dev/null +++ b/web/pgadmin/browser/static/js/preferences.js @@ -0,0 +1,146 @@ +import pgAdmin from 'sources/pgadmin'; +import url_for from 'sources/url_for'; +import * as modifyAnimation from 'sources/modify_animation'; +import $ from 'jquery'; +import * as Alertify from 'pgadmin.alertifyjs'; +import * as SqlEditorUtils from 'sources/sqleditor_utils'; + +const pgBrowser = pgAdmin.Browser = pgAdmin.Browser || {}; + +/* Add cache related methods and properties */ +_.extend(pgBrowser, { + /* This will hold preference data (Works as a cache object) + * Here node will be a key and it's preference data will be value + */ + preferences_cache: [], + + /* This will be used by poller of new tabs/windows to check + * if preference cache is updated in parent/window.opener. + */ + prefcache_version: 0, + + /* Generate a unique version number */ + generate_preference_version: function() { + return (new Date()).getTime(); + }, + + preference_version: function(version) { + if(version) { + this.prefcache_version = version; + } + else { + return this.prefcache_version; + } + }, + + /* Get cached preference */ + get_preference: function(module, preference){ + const self = this; + // If cache is not yet loaded then keep checking + if(_.size(self.preferences_cache) == 0) { + var check_preference = function() { + if(self.preferences_cache.length > 0) { + clearInterval(preferenceTimeout); + return _.findWhere( + self.preferences_cache, {'module': module, 'name': preference} + ); + } + }, + preferenceTimeout = setInterval(check_preference, 1000); + } + else { + return _.findWhere( + self.preferences_cache, {'module': module, 'name': preference} + ); + } + }, + + /* Get all the preferences of a module */ + get_preferences_for_module: function(module) { + var self = this; + let preferences = {}; + _.each( + _.where(self.preferences_cache, {'module': module}), + (preference) => { + preferences[preference.name] = preference.value; + } + ); + return preferences; + }, + + /* Get preference of an id, id is numeric */ + get_preference_for_id : function(id) { + var self = this; + return _.findWhere(self.preferences_cache, {'id': id}); + }, + + // Get and cache the preferences + cache_preferences: function (modulesChanged) { + var self = this; + setTimeout(function() { + $.ajax({ + url: url_for('preferences.get_all'), + success: function(res) { + self.preferences_cache = res; + self.preference_version(self.generate_preference_version()); + + pgBrowser.keyboardNavigation.init(); + if(pgBrowser.tree) { + modifyAnimation.modifyAcitreeAnimation(self); + modifyAnimation.modifyAlertifyAnimation(self); + } + + /* Once the cache is loaded after changing the preferences, + * notify the modules of the change + */ + if(modulesChanged) { + if(typeof modulesChanged === 'string'){ + $.event.trigger('prefchange:'+modulesChanged); + } else { + _.each(modulesChanged, (val, key)=> { + $.event.trigger('prefchange:'+key); + }); + } + } + }, + error: function(xhr, status, error) { + Alertify.pgRespErrorNotify(xhr, error); + }, + }); + }, 500); + }, + + reflectPreferences: function(module) { + let obj = this; + + if(module === 'sqleditor' || module === null || typeof module === 'undefined') { + let sqlEditPreferences = obj.get_preferences_for_module('sqleditor'); + + $(obj.editor.getWrapperElement()).css( + 'font-size',SqlEditorUtils.calcFontSize(sqlEditPreferences.sql_font_size) + ); + obj.editor.setOption('tabSize', sqlEditPreferences.tab_size); + obj.editor.setOption('lineWrapping', sqlEditPreferences.wrap_code); + obj.editor.setOption('autoCloseBrackets', sqlEditPreferences.insert_pair_brackets); + obj.editor.setOption('matchBrackets', sqlEditPreferences.brace_matching); + obj.editor.refresh(); + } + }, + + onPreferencesChange: function(module, eventHandler) { + window.parent.$(parent.document).on('prefchange:'+module, function(event) { + /* If a sqleditor is closed, event handler will be called + * but the window.top will be null. Unbind the event handler + */ + if(window.top === null) { + window.$(document).off(event); + } + else { + eventHandler(event); + } + }); + }, + +}); + +export {pgBrowser}; diff --git a/web/pgadmin/preferences/static/js/preferences.js b/web/pgadmin/preferences/static/js/preferences.js index cdbda0cd..eeaf4bb0 100644 --- a/web/pgadmin/preferences/static/js/preferences.js +++ b/web/pgadmin/preferences/static/js/preferences.js @@ -439,8 +439,18 @@ define('pgadmin.preferences', [ if (e.button.text == gettext('OK')) { preferences.updateAll(); + + /* Find the modules changed */ + let modulesChanged = {}; + _.each(changed, (val, key)=> { + let pref = pgBrowser.get_preference_for_id(Number(key)); + if(!modulesChanged[pref.module]) { + modulesChanged[pref.module] = true; + } + }); + // Refresh preferences cache - setTimeout(pgBrowser.cache_preferences(), 2000); + pgBrowser.cache_preferences(modulesChanged); } }, build: function() { diff --git a/web/pgadmin/static/js/backform.pgadmin.js b/web/pgadmin/static/js/backform.pgadmin.js index f3364c9d..b979291b 100644 --- a/web/pgadmin/static/js/backform.pgadmin.js +++ b/web/pgadmin/static/js/backform.pgadmin.js @@ -1,10 +1,11 @@ define([ 'sources/gettext', 'underscore', 'underscore.string', 'jquery', - 'backbone', 'backform', 'backgrid', 'codemirror', 'spectrum', - 'pgadmin.backgrid', 'select2', -], function(gettext, _, S, $, Backbone, Backform, Backgrid, CodeMirror) { + 'backbone', 'backform', 'backgrid', 'codemirror', 'sources/sqleditor_utils', + 'spectrum', 'pgadmin.backgrid', 'select2', +], function(gettext, _, S, $, Backbone, Backform, Backgrid, CodeMirror, SqlEditorUtils) { - var pgAdmin = (window.pgAdmin = window.pgAdmin || {}); + var pgAdmin = (window.pgAdmin = window.pgAdmin || {}), + pgBrowser = pgAdmin.Browser; pgAdmin.editableCell = function() { if (this.attributes && !_.isUndefined(this.attributes.disabled) && @@ -1259,8 +1260,7 @@ define([ var subnode = data.subnode.schema ? data.subnode : data.subnode.prototype, gridSchema = Backform.generateGridColumnsFromModel( data.node_info, subnode, this.field.get('mode'), data.columns, data.schema_node - ), - pgBrowser = window.pgAdmin.Browser; + ); // Clean up existing grid if any (in case of re-render) if (self.grid) { @@ -1428,6 +1428,23 @@ define([ getValueFromDOM: function() { return this.formatter.toRaw(this.$el.find('textarea').val(), this.model); }, + + reflectPreferences: function() { + var self = this; + /* self.sqlCtrl is null when SQL tab is not active */ + if(self.sqlCtrl) { + let sqlEditPreferences = pgAdmin.Browser.get_preferences_for_module('sqleditor'); + + $(self.sqlCtrl.getWrapperElement()).css( + 'font-size',SqlEditorUtils.calcFontSize(sqlEditPreferences.sql_font_size) + ); + self.sqlCtrl.setOption('tabSize', sqlEditPreferences.tab_size); + self.sqlCtrl.setOption('lineWrapping', sqlEditPreferences.wrap_code); + self.sqlCtrl.setOption('autoCloseBrackets', sqlEditPreferences.insert_pair_brackets); + self.sqlCtrl.setOption('matchBrackets', sqlEditPreferences.brace_matching); + self.sqlCtrl.refresh(); + } + }, render: function() { if (this.sqlCtrl) { this.sqlCtrl.toTextArea(); @@ -1446,12 +1463,16 @@ define([ mode: 'text/x-pgsql', readOnly: true, extraKeys: pgAdmin.Browser.editor_shortcut_keys, - tabSize: pgAdmin.Browser.editor_options.tabSize, - lineWrapping: pgAdmin.Browser.editor_options.wrapCode, - autoCloseBrackets: pgAdmin.Browser.editor_options.insert_pair_brackets, - matchBrackets: pgAdmin.Browser.editor_options.brace_matching, }); + this.reflectPreferences(); + + /* Check for sql editor preference changes */ + let self = this; + pgBrowser.onPreferencesChange('sqleditor', function() { + self.reflectPreferences(); + }); + /* * We will listen to the tab change event to check, if the SQL tab has * been clicked or, not. @@ -1571,7 +1592,6 @@ define([ ) { var proto = (Model && Model.prototype) || Model, schema = subschema || (proto && proto.schema), - pgBrowser = window.pgAdmin.Browser, fields = [], groupInfo = {}; @@ -2051,6 +2071,25 @@ define([ return this.sqlCtrl.getValue(); }, + reflectPreferences: function() { + var self = this; + /* self.sqlCtrl is null when Definition tab is not active */ + if(self.sqlCtrl) { + let sqlEditPreferences = pgAdmin.Browser.get_preferences_for_module('sqleditor'); + + $(self.sqlCtrl.getWrapperElement()).css( + 'font-size',SqlEditorUtils.calcFontSize(sqlEditPreferences.sql_font_size) + ); + self.sqlCtrl.setOption('indentWithTabs', !sqlEditPreferences.use_spaces); + self.sqlCtrl.setOption('indentUnit', sqlEditPreferences.tab_size); + self.sqlCtrl.setOption('tabSize', sqlEditPreferences.tab_size); + self.sqlCtrl.setOption('lineWrapping', sqlEditPreferences.wrap_code); + self.sqlCtrl.setOption('autoCloseBrackets', sqlEditPreferences.insert_pair_brackets); + self.sqlCtrl.setOption('matchBrackets', sqlEditPreferences.brace_matching); + self.sqlCtrl.refresh(); + } + }, + render: function() { // Clean up the existing sql control if (this.sqlCtrl) { @@ -2093,14 +2132,14 @@ define([ lineNumbers: true, mode: 'text/x-pgsql', extraKeys: pgAdmin.Browser.editor_shortcut_keys, - indentWithTabs: pgAdmin.Browser.editor_options.indent_with_tabs, - indentUnit: pgAdmin.Browser.editor_options.tabSize, - tabSize: pgAdmin.Browser.editor_options.tabSize, - lineWrapping: pgAdmin.Browser.editor_options.wrapCode, - autoCloseBrackets: pgAdmin.Browser.editor_options.insert_pair_brackets, - matchBrackets: pgAdmin.Browser.editor_options.brace_matching, }); + self.reflectPreferences(); + /* Check for sql editor preference changes */ + pgBrowser.onPreferencesChange('sqleditor', function() { + self.reflectPreferences(); + }); + // Disable editor if (isDisabled) { // set read only mode to true instead of 'nocursor', and hide cursor using a class so that copying is enabled diff --git a/web/pgadmin/static/js/keyboard_shortcuts.js b/web/pgadmin/static/js/keyboard_shortcuts.js index 1fe07e9b..57d8a303 100644 --- a/web/pgadmin/static/js/keyboard_shortcuts.js +++ b/web/pgadmin/static/js/keyboard_shortcuts.js @@ -8,6 +8,7 @@ ////////////////////////////////////////////////////////////////////////// import $ from 'jquery'; +import gettext from 'sources/gettext'; const PERIOD_KEY = 190, FWD_SLASH_KEY = 191, @@ -49,6 +50,52 @@ function isCtrlAltBoth(event) { return event.ctrlKey && event.altKey && !event.shiftKey; } +/* Returns the key of shortcut */ +function shortcut_key(shortcut) { + let key = ''; + if(shortcut['key'] && shortcut['key']['char']) { + key = shortcut['key']['char'].toUpperCase(); + } + return key; +} + +/* Converts shortcut object to title representation + * Shortcut object is browser.get_preference().value + */ +function shortcut_title(title, shortcut) { + let text_representation = ''; + + if (typeof shortcut === 'undefined' || shortcut === null) { + return text_representation; + } + if(shortcut['alt']) { + text_representation = gettext('Alt') + '+'; + } + if(shortcut['shift']) { + text_representation += gettext('Shift') + '+'; + } + if(shortcut['control']) { + text_representation += gettext('Ctrl') + '+'; + } + text_representation += shortcut_key(shortcut); + + return gettext('%(title)s (%(text_representation)s)',{ + 'title': title, + 'text_representation': text_representation, + }); +} + +/* Returns the key char of shortcut + * shortcut object is browser.get_preference().value + */ +function shortcut_accesskey_title(title, shortcut) { + return gettext('%(title)s (accesskey + %(key)s)',{ + 'title': title, + 'key': shortcut_key(shortcut), + }); +} + + function _stopEventPropagation(event) { event.cancelBubble = true; event.preventDefault(); @@ -124,19 +171,19 @@ function getInnerPanel($el, direction) { /* Query tool: Keyboard Shortcuts handling */ function keyboardShortcutsQueryTool( - sqlEditorController, keyboardShortcutConfig, queryToolActions, event + sqlEditorController, queryToolActions, event ) { if (sqlEditorController.isQueryRunning()) { return; } let keyCode = event.which || event.keyCode, panel_id; - let executeKeys = keyboardShortcutConfig['execute']; - let explainKeys = keyboardShortcutConfig['explain']; - let explainAnalyzeKeys = keyboardShortcutConfig['explain_analyze']; - let downloadCsvKeys = keyboardShortcutConfig['download_csv']; - let nextPanelKeys = keyboardShortcutConfig['move_next']; - let previousPanelKeys = keyboardShortcutConfig['move_previous']; - let toggleCaseKeys = keyboardShortcutConfig['toggle_case']; + let executeKeys = sqlEditorController.preferences.execute_query; + let explainKeys = sqlEditorController.preferences.explain_query; + let explainAnalyzeKeys = sqlEditorController.preferences.explain_analyze_query; + let downloadCsvKeys = sqlEditorController.preferences.download_csv; + let nextPanelKeys = sqlEditorController.preferences.move_next; + let previousPanelKeys = sqlEditorController.preferences.move_previous; + let toggleCaseKeys = sqlEditorController.preferences.toggle_case; if (this.validateShortcutKeys(executeKeys, event)) { this._stopEventPropagation(event); @@ -245,4 +292,7 @@ module.exports = { isAltShiftBoth: isAltShiftBoth, isCtrlShiftBoth: isCtrlShiftBoth, isCtrlAltBoth: isCtrlAltBoth, + shortcut_key : shortcut_key, + shortcut_title : shortcut_title, + shortcut_accesskey_title : shortcut_accesskey_title, }; diff --git a/web/pgadmin/static/js/sqleditor/query_tool_actions.js b/web/pgadmin/static/js/sqleditor/query_tool_actions.js index 411c6ed5..6cbbce0f 100644 --- a/web/pgadmin/static/js/sqleditor/query_tool_actions.js +++ b/web/pgadmin/static/js/sqleditor/query_tool_actions.js @@ -119,58 +119,6 @@ let queryToolActions = { window.top.document.activeElement.blur(); }, - getKeyboardShortcuts: function (sqlEditorController) { - let executeQueryPref = window.top.pgAdmin.Browser.get_preference( - 'sqleditor', 'execute_query'); - let explainQueryPref = window.top.pgAdmin.Browser.get_preference( - 'sqleditor', 'explain_query'); - let explainAnalyzeQueryPref = window.top.pgAdmin.Browser.get_preference( - 'sqleditor', 'explain_analyze_query'); - let downloadCsvPref = window.top.pgAdmin.Browser.get_preference( - 'sqleditor', 'download_csv'); - let nextPanelPerf = window.top.pgAdmin.Browser.get_preference( - 'sqleditor', 'move_next'); - let previousPanelPerf = window.top.pgAdmin.Browser.get_preference( - 'sqleditor', 'move_previous'); - let toggleCasePerf = window.top.pgAdmin.Browser.get_preference( - 'sqleditor', 'toggle_case'); - - if(!executeQueryPref && sqlEditorController.handler.is_new_browser_tab) { - executeQueryPref = window.opener.pgAdmin.Browser.get_preference( - 'sqleditor', 'execute_query' - ), - explainQueryPref = window.opener.pgAdmin.Browser.get_preference( - 'sqleditor', 'explain_query' - ), - explainAnalyzeQueryPref = window.opener.pgAdmin.Browser.get_preference( - 'sqleditor', 'explain_analyze_query' - ), - downloadCsvPref = window.opener.pgAdmin.Browser.get_preference( - 'sqleditor', 'download_csv' - ), - nextPanelPerf = window.opener.pgAdmin.Browser.get_preference( - 'sqleditor', 'move_next' - ), - previousPanelPerf = window.opener.pgAdmin.Browser.get_preference( - 'sqleditor', 'move_previous' - ), - toggleCasePerf = window.opener.pgAdmin.Browser.get_preference( - 'sqleditor', 'toggle_case' - ); - } - - return { - 'execute': executeQueryPref.value, - 'explain': explainQueryPref.value, - 'explain_analyze': explainAnalyzeQueryPref.value, - 'download_csv': downloadCsvPref.value, - 'move_next': nextPanelPerf.value, - 'move_previous': previousPanelPerf.value, - 'toggle_case': toggleCasePerf.value, - }; - - }, - toggleCaseOfSelectedText: function (sqlEditorController) { let codeMirrorObj = sqlEditorController.gridView.query_tool_obj; let selectedText = codeMirrorObj.getSelection(); diff --git a/web/pgadmin/static/js/sqleditor/query_tool_preferences.js b/web/pgadmin/static/js/sqleditor/query_tool_preferences.js new file mode 100644 index 00000000..f26a23a2 --- /dev/null +++ b/web/pgadmin/static/js/sqleditor/query_tool_preferences.js @@ -0,0 +1,179 @@ +import {shortcut_key, shortcut_accesskey_title, shortcut_title} + from 'sources/keyboard_shortcuts'; +import * as SqlEditorUtils from 'sources/sqleditor_utils'; +import $ from 'jquery'; + +function updateUIPreferences(sqlEditor) { + let $el = sqlEditor.$el, + preferences = sqlEditor.preferences; + + if(sqlEditor.handler.slickgrid) { + sqlEditor.handler.slickgrid.CSVOptions = { + quoting: sqlEditor.preferences.results_grid_quoting, + quote_char: sqlEditor.preferences.results_grid_quote_char, + field_separator: sqlEditor.preferences.results_grid_field_separator, + }; + } + + /* Accessed using accesskey direct w/o ctrl,atl,shift */ + $el.find('#btn-load-file') + .attr('title', shortcut_accesskey_title('Open File',preferences.btn_open_file)) + .attr('accesskey', shortcut_key(preferences.btn_open_file)); + + $el.find('#btn-save') + .attr('title', shortcut_accesskey_title('Save File',preferences.btn_save_file)) + .attr('accesskey', shortcut_key(preferences.btn_save_file)); + + $el.find('#btn-find-menu-dropdown') + .attr('title', shortcut_accesskey_title('Find',preferences.btn_find_options)) + .attr('accesskey', shortcut_key(preferences.btn_find_options)); + + $el.find('#btn-copy-row') + .attr('title', shortcut_accesskey_title('Copy',preferences.btn_copy_row)) + .attr('accesskey', shortcut_key(preferences.btn_copy_row)); + + $el.find('#btn-paste-row') + .attr('title', shortcut_accesskey_title('Paste',preferences.btn_paste_row)) + .attr('accesskey', shortcut_key(preferences.btn_paste_row)); + + $el.find('#btn-delete-row') + .attr('title', shortcut_accesskey_title('Delete',preferences.btn_delete_row)) + .attr('accesskey', shortcut_key(preferences.btn_delete_row)); + + $el.find('#btn-filter') + .attr('title', shortcut_accesskey_title('Filter',preferences.btn_filter_dialog)) + .attr('accesskey', shortcut_key(preferences.btn_filter_dialog)); + + $el.find('#btn-filter-dropdown') + .attr('title', shortcut_accesskey_title('Filter options',preferences.btn_filter_options)) + .attr('accesskey', shortcut_key(preferences.btn_filter_options)); + + $el.find('#btn-rows-limit') + .attr('title', shortcut_accesskey_title('Rows limit',preferences.btn_rows_limit)) + .attr('accesskey', shortcut_key(preferences.btn_rows_limit)); + + $el.find('#btn-query-dropdown') + .attr('title', shortcut_accesskey_title('Execute options',preferences.btn_execute_options)) + .attr('accesskey', shortcut_key(preferences.btn_execute_options)); + + $el.find('#btn-cancel-query') + .attr('title', shortcut_accesskey_title('Cancel query',preferences.btn_cancel_query)) + .attr('accesskey', shortcut_key(preferences.btn_cancel_query)); + + $el.find('#btn-clear-dropdown') + .attr('title', shortcut_accesskey_title('Clear',preferences.btn_clear_options)) + .attr('accesskey', shortcut_key(preferences.btn_clear_options)); + + $el.find('#btn-conn-status') + .attr('accesskey', shortcut_key(preferences.btn_conn_status)) + .find('i') + .attr('title', + shortcut_accesskey_title('Connection status (click for details)', + preferences.btn_conn_status)); + + /* Accessed using ctrl,atl,shift and key */ + $el.find('#btn-flash') + .attr('title', + shortcut_title('Execute/Refresh',preferences.execute_query)); + + $el.find('#btn-flash-menu span') + .text(shortcut_title('Execute/Refresh',preferences.execute_query)); + + $el.find('#btn-explain span') + .text(shortcut_title('Explain',preferences.explain_query)); + + $el.find('#btn-explain-analyze span') + .text(shortcut_title('Explain Analyze',preferences.explain_analyze_query)); + + $el.find('#btn-download') + .attr('title', + shortcut_title('Download as CSV',preferences.download_csv)); + + /* Set Auto-commit and auto-rollback on query editor */ + if (preferences.auto_commit) { + $el.find('.auto-commit').removeClass('visibility-hidden'); + } + else { + $el.find('.auto-commit').addClass('visibility-hidden'); + } + if (preferences.auto_rollback) { + $el.find('.auto-rollback').removeClass('visibility-hidden'); + } + else { + $el.find('.auto-rollback').addClass('visibility-hidden'); + } + + /* Set explain options on query editor */ + if (preferences.explain_verbose){ + $el.find('.explain-verbose').removeClass('visibility-hidden'); + } + else { + $el.find('.explain-verbose').addClass('visibility-hidden'); + } + + if (preferences.explain_costs){ + $el.find('.explain-costs').removeClass('visibility-hidden'); + } + else { + $el.find('.explain-costs').addClass('visibility-hidden'); + } + + if (preferences.explain_buffers){ + $el.find('.explain-buffers').removeClass('visibility-hidden'); + } + else { + $el.find('.explain-buffers').addClass('visibility-hidden'); + } + + if (preferences.explain_timing) { + $el.find('.explain-timing').removeClass('visibility-hidden'); + } + else { + $el.find('.explain-timing').addClass('visibility-hidden'); + } + + /* Connection status check */ + /* remove the status checker if present */ + if(sqlEditor.connIntervalId != null) { + clearInterval(sqlEditor.connIntervalId); + sqlEditor.connIntervalId = null; + } + if (preferences.connection_status) { + let $conn_status = $el.find('#btn-conn-status'), + $status_el = $conn_status.find('i'); + $conn_status.popover(); + + $conn_status.removeClass('connection-status-hide'); + $el.find('.editor-title').addClass('editor-title-connection'); + + // To set initial connection + SqlEditorUtils.fetchConnectionStatus(sqlEditor.handler, $conn_status, $status_el); + + // Calling it again in specified interval + sqlEditor.connIntervalId = setInterval( + SqlEditorUtils.fetchConnectionStatus.bind(null, sqlEditor.handler, $conn_status, $status_el), + preferences.connection_status_fetch_time * 1000 + ); + } + else { + $el.find('#btn-conn-status').addClass('connection-status-hide'); + $el.find('.editor-title').removeClass('editor-title-connection'); + } + + /* Code Mirror Preferences */ + let sql_font_size = SqlEditorUtils.calcFontSize(preferences.sql_font_size); + $(sqlEditor.query_tool_obj.getWrapperElement()).css('font-size', sql_font_size); + + sqlEditor.query_tool_obj.setOption('indentWithTabs', !preferences.use_spaces); + sqlEditor.query_tool_obj.setOption('indentUnit', preferences.tab_size); + sqlEditor.query_tool_obj.setOption('tabSize', preferences.tab_size); + sqlEditor.query_tool_obj.setOption('lineWrapping', preferences.wrap_code); + sqlEditor.query_tool_obj.setOption('autoCloseBrackets', preferences.insert_pair_brackets); + sqlEditor.query_tool_obj.setOption('matchBrackets', preferences.brace_matching); + sqlEditor.query_tool_obj.refresh(); + + /* Render history to reflect Font size change */ + sqlEditor.render_history_grid(); +} + +export {updateUIPreferences}; diff --git a/web/pgadmin/static/js/sqleditor_utils.js b/web/pgadmin/static/js/sqleditor_utils.js index be41566f..0fff1d95 100644 --- a/web/pgadmin/static/js/sqleditor_utils.js +++ b/web/pgadmin/static/js/sqleditor_utils.js @@ -178,24 +178,6 @@ define(['jquery', 'sources/gettext', 'sources/url_for'], }); }, - // This function will update the connection status - updateConnectionStatus: function(target, poll_time) { - var $el = $(target.gridView.$el.find('.connection_status')), - $status_el = $($el.find('.fa-custom')); - - // Apply popover on element - $el.popover(); - - // To set initial connection statussource$el.popover() - sqlEditorUtils.fetchConnectionStatus(target, $el, $status_el); - - // Calling it again in specified interval - setInterval( - sqlEditorUtils.fetchConnectionStatus.bind(null, target, $el, $status_el), - poll_time * 1000 - ); - }, - // Updates the flag for connection status poll updateConnectionStatusFlag: function(status) { var $el = $('.connection_status'); @@ -203,6 +185,15 @@ define(['jquery', 'sources/gettext', 'sources/url_for'], $el.data('panel-visible', status); } }, + + calcFontSize: function(fontSize) { + if(fontSize) { + return Number((Math.round(fontSize + 'e+2') + 'e-2')) + 'em'; + } + else { + return '0em'; + } + }, }; return sqlEditorUtils; }); diff --git a/web/pgadmin/static/jsx/history/detail/code_mirror.jsx b/web/pgadmin/static/jsx/history/detail/code_mirror.jsx index 6e982128..038cc200 100644 --- a/web/pgadmin/static/jsx/history/detail/code_mirror.jsx +++ b/web/pgadmin/static/jsx/history/detail/code_mirror.jsx @@ -50,6 +50,11 @@ export default class CodeMirror extends React.Component { Object.keys(props.options || {}).forEach(key => this.editor.setOption(key, props.options[key])); this.editor.setValue(props.value || ''); + + if(props.sqlFontSize) { + $(this.editor.getWrapperElement()).css('font-size', props.sqlFontSize); + } + this.editor.refresh(); } diff --git a/web/pgadmin/static/jsx/history/detail/history_detail_query.jsx b/web/pgadmin/static/jsx/history/detail/history_detail_query.jsx index dce34607..eae55dee 100644 --- a/web/pgadmin/static/jsx/history/detail/history_detail_query.jsx +++ b/web/pgadmin/static/jsx/history/detail/history_detail_query.jsx @@ -64,6 +64,7 @@ export default class HistoryDetailQuery extends React.Component { mode: 'text/x-pgsql', readOnly: true, }} + sqlFontSize= {this.props.sqlEditorPref.sql_font_size} /> </div>); } @@ -71,4 +72,5 @@ export default class HistoryDetailQuery extends React.Component { HistoryDetailQuery.propTypes = { historyEntry: Shapes.historyDetail, + sqlEditorPref: Shapes.sqlEditorPrefObj, }; diff --git a/web/pgadmin/static/jsx/history/query_history.jsx b/web/pgadmin/static/jsx/history/query_history.jsx index 3c07b5bd..8b5ffd2a 100644 --- a/web/pgadmin/static/jsx/history/query_history.jsx +++ b/web/pgadmin/static/jsx/history/query_history.jsx @@ -97,13 +97,16 @@ export default class QueryHistory extends React.Component { selectedEntry={this.state.selectedEntry} onSelectEntry={this.selectHistoryEntry} /> - <QueryHistoryDetail historyEntry={this.state.currentHistoryDetail}/> + <QueryHistoryDetail historyEntry={this.state.currentHistoryDetail} + sqlEditorPref={this.props.sqlEditorPref} + /> </SplitPane>); } } QueryHistory.propTypes = { historyCollection: Shapes.historyCollectionClass.isRequired, + sqlEditorPref: Shapes.sqlEditorPrefObj, }; export { diff --git a/web/pgadmin/static/jsx/react_shapes.jsx b/web/pgadmin/static/jsx/react_shapes.jsx index 454ab446..f8948b5f 100644 --- a/web/pgadmin/static/jsx/react_shapes.jsx +++ b/web/pgadmin/static/jsx/react_shapes.jsx @@ -25,7 +25,13 @@ let historyCollectionClass = onChange: PropTypes.func.isRequired, }); +let sqlEditorPrefObj = + PropTypes.shape({ + sql_font_size: PropTypes.string.isRequired, + }); + export default { historyDetail, historyCollectionClass, + sqlEditorPrefObj, }; diff --git a/web/pgadmin/tools/datagrid/__init__.py b/web/pgadmin/tools/datagrid/__init__.py index d3c3bf9c..04e2a683 100644 --- a/web/pgadmin/tools/datagrid/__init__.py +++ b/web/pgadmin/tools/datagrid/__init__.py @@ -24,12 +24,9 @@ from pgadmin.utils.ajax import make_json_response, bad_request, \ internal_server_error from config import PG_DEFAULT_DRIVER -from pgadmin.utils.preferences import Preferences from pgadmin.model import Server from pgadmin.utils.driver import get_driver from pgadmin.utils.exception import ConnectionLost, SSHTunnelConnectionLost -from pgadmin.tools.sqleditor.utils.query_tool_preferences import \ - get_query_tool_keyboard_shortcuts, get_text_representation_of_shortcut class DataGridModule(PgAdminModule): @@ -184,13 +181,9 @@ def initialize_datagrid(cmd_type, obj_type, sgid, sid, did, obj_id): # Store the grid dictionary into the session variable session['gridData'] = sql_grid_data - pref = Preferences.module('sqleditor') - new_browser_tab = pref.preference('new_browser_tab').get() - return make_json_response( data={ - 'gridTransId': trans_id, - 'newBrowserTab': new_browser_tab + 'gridTransId': trans_id } ) @@ -246,12 +239,6 @@ def panel(trans_id, is_query_tool, editor_title): if "linux" in _platform: is_linux_platform = True - pref = Preferences.module('sqleditor') - if pref.preference('new_browser_tab').get(): - new_browser_tab = 'true' - else: - new_browser_tab = 'false' - # Fetch the server details bgcolor = None fgcolor = None @@ -271,16 +258,10 @@ def panel(trans_id, is_query_tool, editor_title): url_params = dict() if is_query_tool == 'true': - prompt_save_changes = pref.preference( - 'prompt_save_query_changes' - ).get() url_params['sgid'] = trans_obj.sgid url_params['sid'] = trans_obj.sid url_params['did'] = trans_obj.did else: - prompt_save_changes = pref.preference( - 'prompt_save_data_changes' - ).get() url_params['cmd_type'] = trans_obj.cmd_type url_params['obj_type'] = trans_obj.object_type url_params['sgid'] = trans_obj.sgid @@ -288,9 +269,6 @@ def panel(trans_id, is_query_tool, editor_title): url_params['did'] = trans_obj.did url_params['obj_id'] = trans_obj.obj_id - display_connection_status = pref.preference('connection_status').get() - queryToolShortcuts = get_query_tool_keyboard_shortcuts() - return render_template( "datagrid/index.html", _=gettext, @@ -300,19 +278,11 @@ def panel(trans_id, is_query_tool, editor_title): script_type_url=sURL, is_desktop_mode=app.PGADMIN_RUNTIME, is_linux=is_linux_platform, - is_new_browser_tab=new_browser_tab, server_type=server_type, client_platform=user_agent.platform, bgcolor=bgcolor, fgcolor=fgcolor, - # convert python boolean value to equivalent js boolean literal - # before passing it to html template. - prompt_save_changes='true' if prompt_save_changes else 'false', - display_connection_status=display_connection_status, - url_params=json.dumps(url_params), - key=queryToolShortcuts.get('keys'), - shortcuts=queryToolShortcuts.get('shortcuts'), - get_shortcut_text=get_text_representation_of_shortcut + url_params=json.dumps(url_params) ) @@ -387,13 +357,9 @@ def initialize_query_tool(sgid, sid, did=None): # Store the grid dictionary into the session variable session['gridData'] = sql_grid_data - pref = Preferences.module('sqleditor') - new_browser_tab = pref.preference('new_browser_tab').get() - return make_json_response( data={ - 'gridTransId': trans_id, - 'newBrowserTab': new_browser_tab + 'gridTransId': trans_id } ) diff --git a/web/pgadmin/tools/datagrid/static/js/datagrid.js b/web/pgadmin/tools/datagrid/static/js/datagrid.js index c730b180..4cdddf38 100644 --- a/web/pgadmin/tools/datagrid/static/js/datagrid.js +++ b/web/pgadmin/tools/datagrid/static/js/datagrid.js @@ -29,6 +29,23 @@ define('pgadmin.datagrid', [ this.initialized = true; this.title_index = 1; + + let self = this; + /* Cache may take time to load for the first time + * Keep trying till available + */ + let cacheIntervalId = setInterval(function() { + if(pgBrowser.preference_version() > 0) { + self.preferences = pgBrowser.get_preferences_for_module('sqleditor'); + clearInterval(cacheIntervalId); + } + },0); + + pgBrowser.onPreferencesChange('sqleditor', function() { + self.preferences = pgBrowser.get_preferences_for_module('sqleditor'); + }); + + this.spinner_el = '<div class="wcLoadingContainer">'+ '<div class="wcLoadingBackground"></div>'+ '<div class="wcLoadingIconContainer">'+ @@ -279,12 +296,12 @@ define('pgadmin.datagrid', [ lineNumbers: true, mode: 'text/x-pgsql', extraKeys: pgBrowser.editor_shortcut_keys, - indentWithTabs: pgAdmin.Browser.editor_options.indent_with_tabs, - indentUnit: pgAdmin.Browser.editor_options.tabSize, - tabSize: pgBrowser.editor_options.tabSize, - lineWrapping: pgAdmin.Browser.editor_options.wrapCode, - autoCloseBrackets: pgAdmin.Browser.editor_options.insert_pair_brackets, - matchBrackets: pgAdmin.Browser.editor_options.brace_matching, + indentWithTabs: !this.preferences.use_spaces, + indentUnit: this.preferences.tab_size, + tabSize: this.preferences.tab_size, + lineWrapping: this.preferences.wrap_code, + autoCloseBrackets: this.preferences.insert_pair_brackets, + matchBrackets: this.preferences.brace_matching, }); setTimeout(function() { @@ -415,13 +432,20 @@ define('pgadmin.datagrid', [ } } - if (trans_obj.newBrowserTab) { + if (self.preferences.new_browser_tab) { var newWin = window.open(baseUrl, '_blank'); // add a load listener to the window so that the title gets changed on page load newWin.addEventListener('load', function() { newWin.document.title = panel_title; + + /* Set the initial version of pref cache the new window is having + * This will be used by the poller to compare with window openers + * pref cache version + */ + //newWin.pgAdmin.Browser.preference_version(pgBrowser.preference_version()); }); + } else { /* On successfully initialization find the dashboard panel, * create new panel and add it to the dashboard panel. diff --git a/web/pgadmin/tools/datagrid/templates/datagrid/index.html b/web/pgadmin/tools/datagrid/templates/datagrid/index.html index ad090262..37187e45 100644 --- a/web/pgadmin/tools/datagrid/templates/datagrid/index.html +++ b/web/pgadmin/tools/datagrid/templates/datagrid/index.html @@ -10,13 +10,6 @@ .alertify .ajs-dialog.ajs-shake{-webkit-animation-name: none;} .sql-editor-busy-icon.fa-pulse{-webkit-animation: none;} {% endif %} - - {# Note: If we will display connection status then we have to provide some - space to display status icon else we can use all the space available #} - .editor-title { - width:{% if display_connection_status -%} calc(100% - 43px) - {% else %} 100% {%- endif %}; - } </style> <div id="main-editor_panel"> <div id="fetching_data" class="wcLoadingIconContainer sql-editor-busy-fetching hide"> @@ -28,14 +21,14 @@ <div id="btn-toolbar" class="pg-prop-btn-group bg-gray-2 border-gray-3" role="toolbar" aria-label=""> <div class="btn-group" role="group" aria-label=""> <button id="btn-load-file" type="button" class="btn btn-default btn-load-file" - title="{{ _('Open File') }}{{ _(' (accesskey+{0})'.format(key.open_file.upper())) }}" - accesskey="{{key.open_file}}" + title="" + accesskey="" tabindex="0"> <i class="fa fa-folder-open-o" aria-hidden="true"></i> </button> <button id="btn-save" type="button" class="btn btn-default" - title="{{ _('Save') }}{{ _(' (accesskey+{0})'.format(key.save_file.upper())) }}" - accesskey="{{key.save_file}}" + title="" + accesskey="" disabled> <i class="fa fa-floppy-o" aria-hidden="true" tabindex="0"></i> </button> @@ -63,8 +56,8 @@ </button> <button id="btn-find-menu-dropdown" type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" - title="{{ _('Find options') }}{{ _(' (accesskey+{0})'.format(key.find_options.upper())) }}" - accesskey="{{key.find_options}}" + title="" + accesskey="" tabindex="0"> <span class="caret"></span> <span class="sr-only">Toggle Dropdown</span> </button> @@ -122,22 +115,22 @@ </div> <div class="btn-group" role="group" aria-label=""> <button id="btn-copy-row" type="button" class="btn btn-default" - title="{{ _('Copy') }}{{ _(' (accesskey+{0})'.format(key.copy_row.upper())) }}" - accesskey="{{key.copy_row}}" + title="" + accesskey="" tabindex="0" disabled> <i class="fa fa-files-o" aria-hidden="true"></i> </button> <button id="btn-paste-row" type="button" class="btn btn-default" - title="{{ _('Paste') }}{{ _(' (accesskey+{0})'.format(key.paste_row.upper())) }}" - accesskey="{{key.paste_row}}" + title="" + accesskey="" tabindex="0" disabled> <i class="fa fa-clipboard" aria-hidden="true"></i> </button> </div> <div class="btn-group" role="group" aria-label=""> <button id="btn-delete-row" type="button" class="btn btn-default" - title="{{ _('Delete') }}{{ _(' (accesskey+{0})'.format(key.delete_row.upper())) }}" - accesskey="{{key.delete_row}}" + title="" + accesskey="" tabindex="0" disabled> <i class="fa fa-trash" aria-hidden="true"></i> </button> @@ -188,15 +181,15 @@ </div> <div class="btn-group" role="group" aria-label=""> <button id="btn-filter" type="button" class="btn btn-default" - title="{{ _('Filter') }}{{ _(' (accesskey+{0})'.format(key.filter_dialog.upper())) }}" - accesskey="{{key.filter_dialog}}" + title="" + accesskey="" tabindex="0" disabled> <i class="fa fa-filter" aria-hidden="true"></i> </button> <button id="btn-filter-dropdown" type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" - title="{{ _('Filter options') }}{{ _(' (accesskey+{0})'.format(key.filter_options.upper())) }}" - accesskey="{{key.filter_options}}" + title="" + accesskey="" disabled tabindex="0"> <span class="caret"></span> <span class="sr-only">{{ _('Toggle Dropdown') }}</span> </button> @@ -210,9 +203,9 @@ </ul> </div> <div class="btn-group" role="group" aria-label=""> - <select class="limit" style="height: 30px; width: 90px;" disabled - title="{{ _('Rows limit') }}{{ _(' (accesskey+{0})'.format(key.rows_limit.upper())) }}" - accesskey="{{key.rows_limit}}" + <select id="btn-rows-limit" class="limit" style="height: 30px; width: 90px;" disabled + title="" + accesskey="" tabindex="0"> <option value="-1">{{ _('No limit') }}</option> <option value="1000">{{ _('1000 rows') }}</option> @@ -223,31 +216,31 @@ <div class="btn-group" role="group" aria-label=""> <button id="btn-flash" data-test-selector="execute-refresh-button" type="button" class="btn btn-default" style="width: 40px;" - title="{{ _('Execute/Refresh') }}{{ _(' ({0})'.format(get_shortcut_text(shortcuts.execute_query))) }}" + title="" tabindex="0"> <i class="fa fa-bolt" aria-hidden="true"></i> </button> <button id="btn-query-dropdown" type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" - accesskey="{{key.execute_options}}" - title="{{ _('Execute options') }}{{ _(' (accesskey+{0})'.format(key.execute_options.upper())) }}" + accesskey="" + title="" tabindex="0"> <span class="caret"></span> <span class="sr-only">{{ _('Toggle Dropdown') }}</span> </button> <ul class="dropdown-menu" role="menu"> <li> <a id="btn-flash-menu" href="#" tabindex="0"> - <span>{{ _('Execute/Refresh') }}{{ _(' ({0})'.format(get_shortcut_text(shortcuts.execute_query))) }}</span> + <span></span> </a> </li> <li> <a id="btn-explain" href="#" tabindex="0"> - <span>{{ _('Explain') }}{{ _(' ({0})'.format(get_shortcut_text(shortcuts.explain_query))) }}</span> + <span></span> </a> </li> <li> <a id="btn-explain-analyze" href="#" tabindex="0"> - <span>{{ _('Explain Analyze') }}{{ _(' ({0})'.format(get_shortcut_text(shortcuts.explain_analyze_query))) }}</span> + <span></span> </a> </li> <li class="divider"></li> @@ -295,8 +288,8 @@ </li> </ul> <button id="btn-cancel-query" type="button" class="btn btn-default" - title="{{ _('Cancel query') }}{{ _(' (accesskey+{0})'.format(key.cancel_query.upper())) }}" - accesskey="{{key.cancel_query}}" + title="" + accesskey="" tabindex="0" disabled > <i class="fa fa-stop" aria-hidden="true"></i> </button> @@ -304,8 +297,8 @@ <div class="btn-group" role="group" aria-label=""> <button id="btn-clear-dropdown" type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" - title="{{ _('Clear') }}{{ _(' (accesskey+{0})'.format(key.clear_options.upper())) }}" - accesskey="{{key.clear_options}}" + title="" + accesskey="" tabindex="0"> <i class="fa fa-eraser" aria-hidden="true"></i> <span class="caret"></span> <span class="sr-only">{{ _('Toggle Dropdown') }}</span> @@ -325,7 +318,7 @@ </div> <div class="btn-group" role="group" aria-label=""> <button id="btn-download" type="button" class="btn btn-default" - title="{{ _('Download as CSV') }}{{ _(' ({0})'.format(get_shortcut_text(shortcuts.download_csv))) }}" + title="" tabindex="0"> <i class="fa fa-download" aria-hidden="true"></i> </button> @@ -333,21 +326,17 @@ </div> <div class="connection_status_wrapper"> - {% if display_connection_status %} - <div style="display: inline-block;" - title="{{ _('Connection status (click for details) (accesskey+{0})'.format(key.conn_status.upper())) }}"> - <div class="connection_status" data-container="body" - data-toggle="popover" data-placement="bottom" - data-content="" - data-panel-visible="visible" - accesskey="{{key.conn_status}}" - tabindex="0"> - <i class="fa-custom fa-query-tool-disconnected" aria-hidden="true" - title="{{ _('Connection status (click for details) (accesskey+{0})'.format(key.conn_status.upper())) }}"> - </i> - </div> + <div id="btn-conn-status" + class="connection_status connection-status-show" data-container="body" + data-toggle="popover" data-placement="bottom" + data-content="" + data-panel-visible="visible" + accesskey="" + tabindex="0"> + <i class="fa-custom fa-query-tool-disconnected" aria-hidden="true" + title=""> + </i> </div> - {% endif %} <div class="editor-title" style="background-color: {% if fgcolor %}{{ bgcolor or '#FFFFFF' }}{% else %}{{ bgcolor or '#2C76B4' }}{% endif %}; color: {{ fgcolor or 'white' }};"></div> </div> @@ -398,9 +387,7 @@ {{ is_query_tool }}, "{{ editor_title }}", script_type_url, - {{ is_new_browser_tab }}, "{{ server_type }}", - {{ prompt_save_changes }}, {{ url_params|safe}} ); }); diff --git a/web/pgadmin/tools/sqleditor/static/css/sqleditor.css b/web/pgadmin/tools/sqleditor/static/css/sqleditor.css index c54590d3..75ead263 100644 --- a/web/pgadmin/tools/sqleditor/static/css/sqleditor.css +++ b/web/pgadmin/tools/sqleditor/static/css/sqleditor.css @@ -625,3 +625,19 @@ input.editor-checkbox:focus { .data_sorting_dialog .data_sorting { padding: 10px 0px; } + +.editor-title { + width:100%; +} + +.editor-title-connection { + width:calc(100% - 43px); +} + +.connection-status-show { + display: inline-block; +} + +.connection-status-hide { + display: none; +} diff --git a/web/pgadmin/tools/sqleditor/static/js/sqleditor.js b/web/pgadmin/tools/sqleditor/static/js/sqleditor.js index c3604213..6d4eb31e 100644 --- a/web/pgadmin/tools/sqleditor/static/js/sqleditor.js +++ b/web/pgadmin/tools/sqleditor/static/js/sqleditor.js @@ -16,7 +16,7 @@ define('tools.querytool', [ 'sources/sqleditor/query_tool_http_error_handler', 'sources/sqleditor/filter_dialog', 'sources/history/index.js', - 'sources/../jsx/history/query_history', + 'sourcesjsx/history/query_history', 'react', 'react-dom', 'sources/keyboard_shortcuts', 'sources/sqleditor/query_tool_actions', @@ -25,6 +25,7 @@ define('tools.querytool', [ 'sources/modify_animation', 'sources/sqleditor/calculate_query_run_time', 'sources/sqleditor/call_render_after_poll', + 'sources/sqleditor/query_tool_preferences', 'sources/../bundle/slickgrid', 'pgadmin.file_manager', 'backgrid.sizeable.columns', @@ -38,7 +39,7 @@ define('tools.querytool', [ XCellSelectionModel, setStagedRows, SqlEditorUtils, ExecuteQuery, httpErrorHandler, FilterHandler, HistoryBundle, queryHistory, React, ReactDOM, keyboardShortcuts, queryToolActions, queryToolNotifications, Datagrid, - modifyAnimation, calculateQueryRunTime, callRenderAfterPoll) { + modifyAnimation, calculateQueryRunTime, callRenderAfterPoll, queryToolPref) { /* Return back, this has been called more than once */ if (pgAdmin.SqlEditor) return pgAdmin.SqlEditor; @@ -58,6 +59,11 @@ define('tools.querytool', [ this.$el = opts.el; this.handler = opts.handler; this.handler['col_size'] = {}; + let browser = window.opener ? + window.opener.pgAdmin.Browser : window.top.pgAdmin.Browser; + this.preferences = browser.get_preferences_for_module('sqleditor'); + this.handler.preferences = this.preferences; + this.connIntervalId = null; }, // Bind all the events @@ -112,15 +118,30 @@ define('tools.querytool', [ 'click #btn-unindent-code': 'on_unindent_code', }, + reflectPreferences: function() { + let self = this, + browser = window.opener ? + window.opener.pgAdmin.Browser : window.top.pgAdmin.Browser; + + /* pgBrowser is different obj from window.top.pgAdmin.Browser + * Make sure to get only the latest update. Older versions will be discarded + * if function is called by older events. + * This works for new tab sql editor also as it polls if latest version available + * This is required because sql editor can update preferences directly + */ + if(pgBrowser.preference_version() < browser.preference_version()){ + pgBrowser.preference_version(browser.preference_version()); + self.preferences = browser.get_preferences_for_module('sqleditor'); + self.handler.preferences = self.preferences; + queryToolPref.updateUIPreferences(self); + } + }, + // This function is used to render the template. render: function() { var self = this; $('.editor-title').text(_.unescape(self.editor_title)); - self.checkConnectionStatus(); - - // Fetch and assign the shortcuts to current instance - self.keyboardShortcutConfig = queryToolActions.getKeyboardShortcuts(self); // Updates connection status flag self.gain_focus = function() { @@ -183,13 +204,7 @@ define('tools.querytool', [ }, gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'], extraKeys: pgBrowser.editor_shortcut_keys, - indentWithTabs: pgAdmin.Browser.editor_options.indent_with_tabs, - indentUnit: pgAdmin.Browser.editor_options.tabSize, - tabSize: pgAdmin.Browser.editor_options.tabSize, - lineWrapping: pgAdmin.Browser.editor_options.wrapCode, scrollbarStyle: 'simple', - autoCloseBrackets: pgAdmin.Browser.editor_options.insert_pair_brackets, - matchBrackets: pgAdmin.Browser.editor_options.brace_matching, }); // Refresh Code mirror on SQL panel resize to @@ -270,32 +285,32 @@ define('tools.querytool', [ self.render_history_grid(); queryToolNotifications.renderNotificationsGrid(self.notifications_panel); - if (!self.handler.is_new_browser_tab) { + if (!self.preferences.new_browser_tab) { // Listen on the panel closed event and notify user to save modifications. _.each(window.top.pgAdmin.Browser.docker.findPanels('frm_datagrid'), function(p) { if (p.isVisible()) { - if (self.handler.prompt_save_changes) { - p.on(wcDocker.EVENT.CLOSING, function() { - // Only if we can edit data then perform this check - var notify = false, - msg; - if (self.handler.can_edit) { - var data_store = self.handler.data_store; - if (data_store && (_.size(data_store.added) || - _.size(data_store.updated))) { - msg = gettext('The data has changed. Do you want to save changes?'); - notify = true; - } - } else if (self.handler.is_query_tool && self.handler.is_query_changed) { - msg = gettext('The text has changed. Do you want to save changes?'); + p.on(wcDocker.EVENT.CLOSING, function() { + // Only if we can edit data then perform this check + var notify = false, + msg; + if (self.handler.can_edit + && self.preferences.prompt_save_data_changes) { + var data_store = self.handler.data_store; + if (data_store && (_.size(data_store.added) || + _.size(data_store.updated))) { + msg = gettext('The data has changed. Do you want to save changes?'); notify = true; } - if (notify) { - return self.user_confirmation(p, msg); - } - return true; - }); - } + } else if (self.handler.is_query_tool && self.handler.is_query_changed + && self.preferences.prompt_save_query_changes) { + msg = gettext('The text has changed. Do you want to save changes?'); + notify = true; + } + if (notify) { + return self.user_confirmation(p, msg); + } + return true; + }); // Set focus on query tool of active panel p.on(wcDocker.EVENT.GAIN_FOCUS, function() { @@ -483,33 +498,27 @@ define('tools.querytool', [ }.bind(ctx), }; }); - }, - // This function will check the connection status at specific - // interval defined by the user in preference - checkConnectionStatus: function() { - var self = this, - preference = window.top.pgAdmin.Browser.get_preference( - 'sqleditor', 'connection_status_fetch_time' - ), - display_status = window.top.pgAdmin.Browser.get_preference( - 'sqleditor', 'connection_status' - ); - if(!preference && self.handler.is_new_browser_tab) { - preference = window.opener.pgAdmin.Browser.get_preference( - 'sqleditor', 'connection_status_fetch_time' - ); - display_status = window.opener.pgAdmin.Browser.get_preference( - 'sqleditor', 'connection_status' - ); - } - // Only enable pooling if it is enabled - if (display_status && display_status.value) { - SqlEditorUtils.updateConnectionStatus( - self.handler, - preference.value - ); + self.reflectPreferences(); + + /* Register for preference changed event broadcasted in parent + * to reload the shorcuts. As sqleditor is in iFrame of wcDocker + * window parent is referred + */ + pgBrowser.onPreferencesChange('sqleditor', function() { + self.reflectPreferences(); + }); + + /* If sql editor is in a new tab, event fired is not available + * instead, a poller is set up who will check + */ + if(self.preferences.new_browser_tab) { + setInterval(()=>{ + if(window.opener.pgAdmin) { + self.reflectPreferences(); + } + }, 1000); } }, @@ -805,6 +814,11 @@ define('tools.querytool', [ }; self.handler.slickgrid = grid; + self.handler.slickgrid.CSVOptions = { + quoting: self.preferences.results_grid_quoting, + quote_char: self.preferences.results_grid_quote_char, + field_separator: self.preferences.results_grid_field_separator, + }; // Listener function to watch selected rows from grid if (editor_data.selection) { @@ -903,29 +917,6 @@ define('tools.querytool', [ handleQueryOutputKeyboardEvent(event, args); }); } else { - var pref_cache = undefined; - args.grid.CSVOptions = {}; - - if (self.handler.is_new_browser_tab) { - pref_cache = window.opener.pgAdmin.Browser.preferences_cache; - } else { - pref_cache = window.top.pgAdmin.Browser.preferences_cache; - } - - // Get CSV options from preferences cache - args.grid.CSVOptions.quoting = _.findWhere(pref_cache, { - 'module': 'sqleditor', - 'name': 'results_grid_quoting', - }).value; - args.grid.CSVOptions.quote_char = _.findWhere(pref_cache, { - 'module': 'sqleditor', - 'name': 'results_grid_quote_char', - }).value; - args.grid.CSVOptions.field_separator = _.findWhere(pref_cache, { - 'module': 'sqleditor', - 'name': 'results_grid_field_separator', - }).value; - handleQueryOutputKeyboardEvent(event, args); } }); @@ -1196,7 +1187,10 @@ define('tools.querytool', [ render_history_grid: function() { var self = this; - self.history_collection = new HistoryBundle.HistoryCollection([]); + /* Should not reset if function called again */ + if(!self.history_collection) { + self.history_collection = new HistoryBundle.HistoryCollection([]); + } var historyComponent; var historyCollectionReactElement = React.createElement( @@ -1205,9 +1199,13 @@ define('tools.querytool', [ ref: function(component) { historyComponent = component; }, + sqlEditorPref: { + sql_font_size: SqlEditorUtils.calcFontSize(this.preferences.sql_font_size), + }, }); ReactDOM.render(historyCollectionReactElement, $('#history_grid')[0]); + self.history_panel.off(wcDocker.EVENT.VISIBILITY_CHANGED); self.history_panel.on(wcDocker.EVENT.VISIBILITY_CHANGED, function() { historyComponent.refocus(); }); @@ -1416,29 +1414,7 @@ define('tools.querytool', [ // Callback function for copy button click. on_copy_row: function() { - var self = this, - pref_cache = undefined; - self.grid.CSVOptions = {}; - - if (self.handler.is_new_browser_tab) { - pref_cache = window.opener.pgAdmin.Browser.preferences_cache; - } else { - pref_cache = window.top.pgAdmin.Browser.preferences_cache; - } - - // Get CSV options from preferences cache - self.grid.CSVOptions.quoting = _.findWhere(pref_cache, { - 'module': 'sqleditor', - 'name': 'results_grid_quoting', - }).value; - self.grid.CSVOptions.quote_char = _.findWhere(pref_cache, { - 'module': 'sqleditor', - 'name': 'results_grid_quote_char', - }).value; - self.grid.CSVOptions.field_separator = _.findWhere(pref_cache, { - 'module': 'sqleditor', - 'name': 'results_grid_field_separator', - }).value; + var self = this; // Trigger the copy signal to the SqlEditorController class self.handler.trigger( @@ -1708,7 +1684,7 @@ define('tools.querytool', [ keyAction: function(event) { var panel_id, self = this; panel_id = keyboardShortcuts.processEventQueryTool( - this.handler, this.keyboardShortcutConfig, queryToolActions, event + this.handler, queryToolActions, event ); // If it return panel id then focus it @@ -1933,23 +1909,17 @@ define('tools.querytool', [ * header and loading icon and start execution of the sql query. */ start: function(transId, is_query_tool, editor_title, script_type_url, - is_new_browser_tab, server_type, prompt_save_changes, url_params + server_type, url_params ) { var self = this; self.is_query_tool = is_query_tool; self.rows_affected = 0; self.marked_line_no = 0; - self.explain_verbose = false; - self.explain_costs = false; - self.explain_buffers = false; - self.explain_timing = false; - self.is_new_browser_tab = is_new_browser_tab; self.has_more_rows = false; self.fetching_rows = false; self.close_on_save = false; self.server_type = server_type; - self.prompt_save_changes = prompt_save_changes; self.url_params = url_params; self.script_type_url = script_type_url; @@ -2022,7 +1992,6 @@ define('tools.querytool', [ // Listen to the codemirror on text change event // only in query editor tool if (self.is_query_tool) { - self.get_preferences(); self.gridView.query_tool_obj.on('change', self._on_query_change.bind(self)); } @@ -2830,7 +2799,7 @@ define('tools.querytool', [ setTitle: function(title, unsafe) { var self = this; - if (self.is_new_browser_tab) { + if (self.preferences.new_browser_tab) { window.document.title = title; } else { _.each(window.top.pgAdmin.Browser.docker.findPanels('frm_datagrid'), function(p) { @@ -2992,7 +2961,7 @@ define('tools.querytool', [ var title = self.gridView.current_file.replace(/^.*[\\\/]/g, '') + ' *'; self.setTitle(title, true); } else { - if (self.is_new_browser_tab) { + if (self.preferences.new_browser_tab) { title = window.document.title + ' *'; } else { // Find the title of the visible panel @@ -3505,6 +3474,15 @@ define('tools.querytool', [ link.attr('src', url); }, + call_cache_preferences: function() { + let browser = window.opener ? + window.opener.pgAdmin.Browser : window.top.pgAdmin.Browser; + browser.cache_preferences('sqleditor'); + + /* This will make sure to get latest updates only and not older events */ + pgBrowser.preference_version(pgBrowser.generate_preference_version()); + }, + _auto_rollback: function() { var self = this, auto_rollback = true; @@ -3527,6 +3505,8 @@ define('tools.querytool', [ success: function(res) { if (!res.data.status) alertify.alert(gettext('Auto Rollback Error'), res.data.result); + else + self.call_cache_preferences(); }, error: function(e) { @@ -3560,6 +3540,8 @@ define('tools.querytool', [ success: function(res) { if (!res.data.status) alertify.alert(gettext('Auto Commit Error'), res.data.result); + else + self.call_cache_preferences(); }, error: function(e) { let msg = httpErrorHandler.handleQueryToolAjaxError( @@ -3568,24 +3550,11 @@ define('tools.querytool', [ alertify.alert(gettext('Auto Commit Error'), msg); }, }); - }, - - // This function will toggle "verbose" option in explain - _explain_verbose: function() { - var self = this; - if ($('.explain-verbose').hasClass('visibility-hidden') === true) { - $('.explain-verbose').removeClass('visibility-hidden'); - self.explain_verbose = true; - } else { - $('.explain-verbose').addClass('visibility-hidden'); - self.explain_verbose = false; - } - // Set this option in preferences - var data = { - 'explain_verbose': self.explain_verbose, - }; + }, + explainPreferenceUpdate: function(subItem, data, caller) { + let self = this; $.ajax({ url: url_for('sqleditor.query_tool_preferences', { 'trans_id': self.transId, @@ -3596,133 +3565,96 @@ define('tools.querytool', [ success: function(res) { if (res.success == undefined || !res.success) { alertify.alert(gettext('Explain options error'), - gettext('Error occurred while setting verbose option in explain.') + gettext('Error occurred while setting %(subItem)s option in explain.', + {subItem : subItem}) ); } + else + self.call_cache_preferences(); }, error: function(e) { let msg = httpErrorHandler.handleQueryToolAjaxError( - pgAdmin, self, e, '_explain_verbose', [], true + pgAdmin, self, e, caller, [], true ); alertify.alert(gettext('Explain options error'), msg); }, }); }, + // This function will toggle "verbose" option in explain + _explain_verbose: function() { + var self = this; + let explain_verbose = false; + if ($('.explain-verbose').hasClass('visibility-hidden') === true) { + $('.explain-verbose').removeClass('visibility-hidden'); + explain_verbose = true; + } else { + $('.explain-verbose').addClass('visibility-hidden'); + explain_verbose = false; + } + + self.explainPreferenceUpdate( + 'verbose', { + 'explain_verbose': explain_verbose, + }, '_explain_verbose' + ); + }, + // This function will toggle "costs" option in explain _explain_costs: function() { var self = this; + let explain_costs = false; if ($('.explain-costs').hasClass('visibility-hidden') === true) { $('.explain-costs').removeClass('visibility-hidden'); - self.explain_costs = true; + explain_costs = true; } else { $('.explain-costs').addClass('visibility-hidden'); - self.explain_costs = false; + explain_costs = false; } - // Set this option in preferences - var data = { - 'explain_costs': self.explain_costs, - }; - - $.ajax({ - url: url_for('sqleditor.query_tool_preferences', { - 'trans_id': self.transId, - }), - method: 'PUT', - contentType: 'application/json', - data: JSON.stringify(data), - success: function(res) { - if (res.success == undefined || !res.success) { - alertify.alert(gettext('Explain options error'), - gettext('Error occurred while setting costs option in explain.') - ); - } - }, - error: function(e) { - let msg = httpErrorHandler.handleQueryToolAjaxError( - pgAdmin, self, e, '_explain_costs', [], true - ); - alertify.alert(gettext('Explain options error'), msg); - }, - }); + self.explainPreferenceUpdate( + 'costs', { + 'explain_costs': explain_costs, + }, '_explain_costs' + ); }, // This function will toggle "buffers" option in explain _explain_buffers: function() { var self = this; + let explain_buffers = false; if ($('.explain-buffers').hasClass('visibility-hidden') === true) { $('.explain-buffers').removeClass('visibility-hidden'); - self.explain_buffers = true; + explain_buffers = true; } else { $('.explain-buffers').addClass('visibility-hidden'); - self.explain_buffers = false; + explain_buffers = false; } - // Set this option in preferences - var data = { - 'explain_buffers': self.explain_buffers, - }; - - $.ajax({ - url: url_for('sqleditor.query_tool_preferences', { - 'trans_id': self.transId, - }), - method: 'PUT', - contentType: 'application/json', - data: JSON.stringify(data), - success: function(res) { - if (res.success == undefined || !res.success) { - alertify.alert(gettext('Explain options error'), - gettext('Error occurred while setting buffers option in explain.') - ); - } - }, - error: function(e) { - let msg = httpErrorHandler.handleQueryToolAjaxError( - pgAdmin, self, e, '_explain_buffers', [], true - ); - alertify.alert(gettext('Explain options error'), msg); - }, - }); + self.explainPreferenceUpdate( + 'buffers', { + 'explain_buffers': explain_buffers, + }, '_explain_buffers' + ); }, // This function will toggle "timing" option in explain _explain_timing: function() { var self = this; + let explain_timing = false; if ($('.explain-timing').hasClass('visibility-hidden') === true) { $('.explain-timing').removeClass('visibility-hidden'); - self.explain_timing = true; + explain_timing = true; } else { $('.explain-timing').addClass('visibility-hidden'); - self.explain_timing = false; + explain_timing = false; } - // Set this option in preferences - var data = { - 'explain_timing': self.explain_timing, - }; - $.ajax({ - url: url_for('sqleditor.query_tool_preferences', { - 'trans_id': self.transId, - }), - method: 'PUT', - contentType: 'application/json', - data: JSON.stringify(data), - success: function(res) { - if (res.success == undefined || !res.success) { - alertify.alert(gettext('Explain options error'), - gettext('Error occurred while setting timing option in explain.') - ); - } - }, - error: function(e) { - let msg = httpErrorHandler.handleQueryToolAjaxError( - pgAdmin, self, e, '_explain_timing', [], true - ); - alertify.alert(gettext('Explain options error'), msg); - }, - }); + self.explainPreferenceUpdate( + 'timing', { + 'explain_timing': explain_timing, + }, '_explain_timing' + ); }, /* @@ -3751,85 +3683,6 @@ define('tools.querytool', [ is_query_running = value; }, - /* - * This function get explain options and auto rollback/auto commit - * values from preferences - */ - get_preferences: function() { - var self = this, - explain_verbose = false, - explain_costs = false, - explain_buffers = false, - explain_timing = false, - auto_commit = true, - auto_rollback = false, - updateUI = function() { - // Set Auto-commit and auto-rollback on query editor - if (auto_commit && - $('.auto-commit').hasClass('visibility-hidden') === true) - $('.auto-commit').removeClass('visibility-hidden'); - else { - $('.auto-commit').addClass('visibility-hidden'); - } - if (auto_rollback && - $('.auto-rollback').hasClass('visibility-hidden') === true) - $('.auto-rollback').removeClass('visibility-hidden'); - else { - $('.auto-rollback').addClass('visibility-hidden'); - } - - // Set explain options on query editor - if (explain_verbose && - $('.explain-verbose').hasClass('visibility-hidden') === true) - $('.explain-verbose').removeClass('visibility-hidden'); - else { - $('.explain-verbose').addClass('visibility-hidden'); - } - if (explain_costs && - $('.explain-costs').hasClass('visibility-hidden') === true) - $('.explain-costs').removeClass('visibility-hidden'); - else { - $('.explain-costs').addClass('visibility-hidden'); - } - if (explain_buffers && - $('.explain-buffers').hasClass('visibility-hidden') === true) - $('.explain-buffers').removeClass('visibility-hidden'); - else { - $('.explain-buffers').addClass('visibility-hidden'); - } - if (explain_timing && - $('.explain-timing').hasClass('visibility-hidden') === true) - $('.explain-timing').removeClass('visibility-hidden'); - else { - $('.explain-timing').addClass('visibility-hidden'); - } - }; - - $.ajax({ - url: url_for('sqleditor.query_tool_preferences', { - 'trans_id': self.transId, - }), - method: 'GET', - success: function(res) { - if (res.data) { - explain_verbose = res.data.explain_verbose; - explain_costs = res.data.explain_costs; - explain_buffers = res.data.explain_buffers; - explain_timing = res.data.explain_timing; - auto_commit = res.data.auto_commit; - auto_rollback = res.data.auto_rollback; - updateUI(); - } - }, - error: function(e) { - let msg = httpErrorHandler.handleQueryToolAjaxError( - pgAdmin, self, e, 'get_preferences', [], true - ); - updateUI(); - alertify.alert(gettext('Get Preferences error'), msg); - }, - }); - }, close: function() { var self = this; diff --git a/web/pgadmin/tools/sqleditor/tests/test_pref_utilities.py b/web/pgadmin/tools/sqleditor/tests/test_pref_utilities.py deleted file mode 100644 index cbd141b0..00000000 --- a/web/pgadmin/tools/sqleditor/tests/test_pref_utilities.py +++ /dev/null @@ -1,100 +0,0 @@ -########################################################################## -# -# pgAdmin 4 - PostgreSQL Tools -# -# Copyright (C) 2013 - 2018, The pgAdmin Development Team -# This software is released under the PostgreSQL Licence -# -########################################################################## -from pgadmin.utils.route import BaseTestGenerator -from pgadmin.tools.sqleditor.utils.query_tool_preferences import \ - get_text_representation_of_shortcut - - -class TestQueryToolPreference(BaseTestGenerator): - """ - Ensures that we are able to fetch preferences properly - """ - scenarios = [ - ('Check text representation of a valid shortcuts', dict( - fetch_pref=True, - sample_shortcut=dict( - alt=False, - shift=False, - control=False, - key=dict( - char='a', - keyCode=65 - ) - ), - expected_result='a' - )), - - ('Check text representation of a valid shortcuts', dict( - fetch_pref=True, - sample_shortcut=dict( - alt=True, - shift=False, - control=False, - key=dict( - char='a', - keyCode=65 - ) - ), - expected_result='Alt+a' - )), - - ('Check text representation of a valid shortcuts', dict( - fetch_pref=True, - sample_shortcut=dict( - alt=True, - shift=True, - control=True, - key=dict( - char='a', - keyCode=65 - ) - ), - expected_result='Alt+Shift+Ctrl+a' - )), - - ('Check text representation of a valid shortcuts', dict( - fetch_pref=True, - sample_shortcut=dict( - alt=False, - shift=True, - control=False, - key=dict( - char='a', - keyCode=65 - ) - ), - expected_result='Shift+a' - )), - - ('Check text representation of a valid shortcuts', dict( - fetch_pref=True, - sample_shortcut=dict( - alt=True, - shift=True, - control=False, - key=dict( - char='a', - keyCode=65 - ) - ), - expected_result='Alt+Shift+a' - )), - - ('Check text representation of a invalid shortcuts', dict( - fetch_pref=True, - sample_shortcut=None, - expected_result='' - )) - - ] - - def runTest(self): - """Check correct function is called to handle to run query.""" - result = get_text_representation_of_shortcut(self.sample_shortcut) - self.assertEquals(result, self.expected_result) diff --git a/web/pgadmin/tools/sqleditor/utils/query_tool_preferences.py b/web/pgadmin/tools/sqleditor/utils/query_tool_preferences.py index a5a7bcb8..5e2a8ef1 100644 --- a/web/pgadmin/tools/sqleditor/utils/query_tool_preferences.py +++ b/web/pgadmin/tools/sqleditor/utils/query_tool_preferences.py @@ -560,123 +560,3 @@ def RegisterQueryToolPreferences(self): help_str=gettext('If set to True, Keywords will be displayed ' 'in upper case for auto completion.') ) - - -def get_query_tool_keyboard_shortcuts(): - - """ - Fetch all the query tool shortcut preferences - - Returns: - List of query tool shortcut preferences - """ - qt_perf = Preferences.module('sqleditor') - conn_status = qt_perf.preference('btn_conn_status').get() - clear_options = qt_perf.preference('btn_clear_options').get() - cancel_query = qt_perf.preference('btn_cancel_query').get() - execute_options = qt_perf.preference('btn_execute_options').get() - filter_options = qt_perf.preference('btn_filter_options').get() - rows_limit = qt_perf.preference('btn_rows_limit').get() - filter_dialog = qt_perf.preference('btn_filter_dialog').get() - delete_row = qt_perf.preference('btn_delete_row').get() - paste_row = qt_perf.preference('btn_paste_row').get() - copy_row = qt_perf.preference('btn_copy_row').get() - save_file = qt_perf.preference('btn_save_file').get() - open_file = qt_perf.preference('btn_open_file').get() - move_next = qt_perf.preference('move_next').get() - move_previous = qt_perf.preference('move_previous').get() - download_csv = qt_perf.preference('download_csv').get() - execute_query = qt_perf.preference('execute_query').get() - explain_query = qt_perf.preference('explain_query').get() - explain_analyze_query = qt_perf.preference('explain_analyze_query').get() - find_options = qt_perf.preference('btn_find_options').get() - toggle_case = qt_perf.preference('toggle_case').get() - - return { - 'keys': { - 'conn_status': conn_status.get('key').get('char'), - 'clear_options': clear_options.get('key').get('char'), - 'cancel_query': cancel_query.get('key').get('char'), - 'execute_options': execute_options.get('key').get('char'), - 'filter_options': filter_options.get('key').get('char'), - 'rows_limit': rows_limit.get('key').get('char'), - 'filter_dialog': filter_dialog.get('key').get('char'), - 'delete_row': delete_row.get('key').get('char'), - 'paste_row': paste_row.get('key').get('char'), - 'copy_row': copy_row.get('key').get('char'), - 'save_file': save_file.get('key').get('char'), - 'open_file': open_file.get('key').get('char'), - 'move_next': move_next.get('key').get('char'), - 'move_previous': move_previous.get('key').get('char'), - 'download_csv': download_csv.get('key').get('char'), - 'execute_query': execute_query.get('key').get('char'), - 'explain_query': explain_query.get('key').get('char'), - 'explain_analyze_query': explain_analyze_query.get('key').get( - 'char' - ), - 'find_options': find_options.get('key').get('char'), - 'toggle_case': toggle_case.get('key').get('char') - }, - 'shortcuts': { - 'conn_status': conn_status, - 'clear_options': clear_options, - 'cancel_query': cancel_query, - 'execute_options': execute_options, - 'filter_options': filter_options, - 'rows_limit': rows_limit, - 'filter_dialog': filter_dialog, - 'delete_row': delete_row, - 'paste_row': paste_row, - 'copy_row': copy_row, - 'save_file': save_file, - 'open_file': open_file, - 'move_next': move_next, - 'move_previous': move_previous, - 'download_csv': download_csv, - 'execute_query': execute_query, - 'explain_query': explain_query, - 'explain_analyze_query': explain_analyze_query, - 'find_options': find_options, - 'toggle_case': toggle_case - }, - } - - -def get_text_representation_of_shortcut(shortcut): - """ - Coverts shortcut object to text representation - - Args: - shortcut: Shortcut object - - Returns: - Text representation of given shortcut - """ - text_representation = '' - is_plus_required = False - - if not shortcut: - return text_representation - - if shortcut['alt']: - text_representation = gettext('Alt') - is_plus_required = True - - if shortcut['shift']: - if is_plus_required: - text_representation += '+' - text_representation += gettext('Shift') - is_plus_required = True - - if shortcut['control']: - if is_plus_required: - text_representation += '+' - text_representation += gettext('Ctrl') - is_plus_required = True - - if shortcut['key'] and shortcut['key']['char']: - if is_plus_required: - text_representation += '+' - text_representation += '{0}'.format(shortcut['key']['char']) - - return text_representation diff --git a/web/regression/javascript/browser/preferences_spec.js b/web/regression/javascript/browser/preferences_spec.js new file mode 100644 index 00000000..14bc32ee --- /dev/null +++ b/web/regression/javascript/browser/preferences_spec.js @@ -0,0 +1,152 @@ +import {pgBrowser} from 'pgadmin.browser.preferences'; +import $ from 'jquery'; + +var dummy_cache = [ + { + id: 1, + mid: 1, + module:'module1', + name:'pref1', + value:{ + alt: false, + shift: false, + control: false, + key: { + char: 'a', + key_code: 65, + }, + }, + },{ + id: 2, + mid: 1, + module:'module1', + name:'pref2', + value: 123, + },{ + id: 3, + mid: 2, + module:'module2', + name:'pref2', + value: true, + }, +]; + +describe('preferences related functions test', function() { + describe('get preference data related functions', function(){ + beforeEach(function(){ + pgBrowser.preferences_cache = dummy_cache; + }); + + it('generate_preference_version', function() { + pgBrowser.generate_preference_version(); + expect(pgBrowser.generate_preference_version()).toBeGreaterThan(0); + }); + + it('preference_version', function() { + let version = 123; + pgBrowser.preference_version(version); + expect(pgBrowser.prefcache_version).toEqual(version); + expect(pgBrowser.preference_version()).toEqual(version); + }); + + it('get_preference', function(){ + expect(pgBrowser.get_preference('module1','pref1')).toEqual({ + id: 1, + mid: 1, + module:'module1', + name:'pref1', + value:{ + alt: false, + shift: false, + control: false, + key: { + char: 'a', + key_code: 65, + }, + }, + }); + }); + + it('get_preferences_for_module', function() { + expect(pgBrowser.get_preferences_for_module('module1')).toEqual({ + 'pref1':{ + alt: false, + shift: false, + control: false, + key: { + char: 'a', + key_code: 65, + }, + }, + 'pref2': 123, + }); + }); + + it('get_preference_for_id', function() { + expect(pgBrowser.get_preference_for_id(3)).toEqual({ + id: 3, + mid: 2, + module:'module2', + name:'pref2', + value: true, + }); + }); + + it('reflectPreferences', function() { + + let editorOptions = { + 'tabSize':2, + 'lineWrapping':false, + 'autoCloseBrackets':true, + 'matchBrackets':true, + }; + pgBrowser.preferences_cache.push({ + id: 4, mid: 3, module:'sqleditor', name:'sql_font_size', value: 1.456, + }); + pgBrowser.preferences_cache.push({ + id: 4, mid: 3, module:'sqleditor', name:'tab_size', value: editorOptions.tabSize, + }); + pgBrowser.preferences_cache.push({ + id: 4, mid: 3, module:'sqleditor', name:'wrap_code', value: editorOptions.lineWrapping, + }); + pgBrowser.preferences_cache.push({ + id: 4, mid: 3, module:'sqleditor', name:'insert_pair_brackets', value: editorOptions.autoCloseBrackets, + }); + pgBrowser.preferences_cache.push({ + id: 4, mid: 3, module:'sqleditor', name:'brace_matching', value: editorOptions.matchBrackets, + }); + + /* Spies */ + pgBrowser.editor = jasmine.createSpyObj( + 'CodeMirror', ['setOption','refresh','getWrapperElement'] + ); + spyOn($.fn, 'css'); + + /* Call */ + pgBrowser.reflectPreferences(); + + /* Tests */ + expect(pgBrowser.editor.getWrapperElement).toHaveBeenCalled(); + expect($.fn.css).toHaveBeenCalledWith('font-size', '1.46em'); + + let setOptionCalls = pgBrowser.editor.setOption.calls; + expect(setOptionCalls.count()).toBe(Object.keys(editorOptions).length); + + for(let i = 0; i < Object.keys(editorOptions).length; i++) { + let option = Object.keys(editorOptions)[i]; + expect(setOptionCalls.argsFor(i)).toEqual([option, editorOptions[option]]); + } + expect(pgBrowser.editor.refresh).toHaveBeenCalled(); + }); + + it('onPreferencesChange', function() { + + window.parent.$ = $; + spyOn($.fn, 'on'); + + var eventHandler = jasmine.createSpy('eventHandler'); + pgBrowser.onPreferencesChange('somemodule', eventHandler); + expect($.fn.on.calls.mostRecent().args[0]).toEqual('prefchange:somemodule'); + }); + }); +}); diff --git a/web/regression/javascript/history/query_history_spec.jsx b/web/regression/javascript/history/query_history_spec.jsx index c49b19f0..b90d2a30 100644 --- a/web/regression/javascript/history/query_history_spec.jsx +++ b/web/regression/javascript/history/query_history_spec.jsx @@ -29,7 +29,7 @@ import '../helper/enzyme.helper'; describe('QueryHistory', () => { let historyCollection; let historyWrapper; - + let sqlEditorPref = {sql_font_size: '1em'}; beforeEach(() => { jasmineEnzyme(); }); @@ -37,7 +37,9 @@ describe('QueryHistory', () => { describe('when there is no history', () => { beforeEach(() => { historyCollection = new HistoryCollection([]); - historyWrapper = mount(<QueryHistory historyCollection={historyCollection}/>); + historyWrapper = mount(<QueryHistory historyCollection={historyCollection} + sqlEditorPref={sqlEditorPref} + />); }); describe('when we switch to the query history tab', () => { @@ -89,8 +91,9 @@ describe('QueryHistory', () => { message: 'something important ERROR: message from second sql query', }]; historyCollection = new HistoryCollection(historyObjects); - - historyWrapper = mount(<QueryHistory historyCollection={historyCollection}/>); + historyWrapper = mount(<QueryHistory historyCollection={historyCollection} + sqlEditorPref={sqlEditorPref} + />); queryHistoryEntriesComponent = historyWrapper.find(QueryHistoryEntries); isInvisibleSpy = spyOn(queryHistoryEntriesComponent.instance(), 'isInvisible') @@ -479,7 +482,9 @@ describe('QueryHistory', () => { }]; historyCollection = new HistoryCollection(historyObjects); - historyWrapper = mount(<QueryHistory historyCollection={historyCollection}/>); + historyWrapper = mount(<QueryHistory historyCollection={historyCollection} + sqlEditorPref={sqlEditorPref} + />); const queryHistoryEntriesComponent = historyWrapper.find(QueryHistoryEntries); isInvisibleSpy = spyOn(queryHistoryEntriesComponent.instance(), 'isInvisible') diff --git a/web/regression/javascript/sqleditor/keyboard_shortcuts_spec.js b/web/regression/javascript/sqleditor/keyboard_shortcuts_spec.js index 06586d34..0e774814 100644 --- a/web/regression/javascript/sqleditor/keyboard_shortcuts_spec.js +++ b/web/regression/javascript/sqleditor/keyboard_shortcuts_spec.js @@ -9,6 +9,7 @@ import keyboardShortcuts from 'sources/keyboard_shortcuts'; import {queryToolActions} from 'sources/sqleditor/query_tool_actions'; +import gettext from 'sources/gettext'; describe('the keyboard shortcuts', () => { const F1_KEY = 112, @@ -18,7 +19,7 @@ describe('the keyboard shortcuts', () => { PERIOD_KEY = 190, FWD_SLASH_KEY = 191; - let sqlEditorControllerSpy, event, queryToolActionsSpy, queryToolkeyboardShortcutsConfig; + let sqlEditorControllerSpy, event, queryToolActionsSpy; beforeEach(() => { event = { shift: false, @@ -29,8 +30,22 @@ describe('the keyboard shortcuts', () => { stopImmediatePropagation: jasmine.createSpy('stopImmediatePropagation'), }; - queryToolkeyboardShortcutsConfig = { - execute: { + let gridView = { + query_tool_obj: { + getSelection: jasmine.createSpy('getSelection'), + getValue: jasmine.createSpy('getValue'), + }, + }; + + sqlEditorControllerSpy = jasmine.createSpyObj('SqlEditorController', [ + 'isQueryRunning', + 'execute', + ]); + + sqlEditorControllerSpy.gridView = gridView; + + sqlEditorControllerSpy.preferences = { + execute_query: { alt: false, shift: false, control: false, @@ -38,7 +53,7 @@ describe('the keyboard shortcuts', () => { key_code: F5_KEY, }, }, - explain: { + explain_query: { alt: false, shift: false, control: false, @@ -46,7 +61,7 @@ describe('the keyboard shortcuts', () => { key_code: F7_KEY, }, }, - explain_analyze: { + explain_analyze_query: { alt: false, shift: true, control: false, @@ -80,20 +95,6 @@ describe('the keyboard shortcuts', () => { }, }; - let gridView = { - query_tool_obj: { - getSelection: jasmine.createSpy('getSelection'), - getValue: jasmine.createSpy('getValue'), - }, - }; - - sqlEditorControllerSpy = jasmine.createSpyObj('SqlEditorController', [ - 'isQueryRunning', - 'execute', - ]); - - sqlEditorControllerSpy.gridView = gridView; - queryToolActionsSpy = jasmine.createSpyObj(queryToolActions, [ 'explainAnalyze', 'explain', @@ -110,8 +111,7 @@ describe('the keyboard shortcuts', () => { beforeEach(() => { event.which = F1_KEY; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); @@ -128,8 +128,7 @@ describe('the keyboard shortcuts', () => { event.shiftKey = false; event.ctrlKey = false; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); @@ -151,8 +150,7 @@ describe('the keyboard shortcuts', () => { sqlEditorControllerSpy.isQueryRunning.and.returnValue(true); keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); expect(queryToolActionsSpy.executeQuery).not.toHaveBeenCalled(); @@ -168,8 +166,7 @@ describe('the keyboard shortcuts', () => { event.shiftKey = false; event.ctrlKey = false; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); @@ -189,8 +186,7 @@ describe('the keyboard shortcuts', () => { sqlEditorControllerSpy.isQueryRunning.and.returnValue(true); keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); expect(queryToolActionsSpy.explain).not.toHaveBeenCalled(); @@ -206,8 +202,7 @@ describe('the keyboard shortcuts', () => { event.altKey = false; event.ctrlKey = false; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); @@ -228,8 +223,7 @@ describe('the keyboard shortcuts', () => { sqlEditorControllerSpy.isQueryRunning.and.returnValue(true); keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); expect(queryToolActionsSpy.explainAnalyze).not.toHaveBeenCalled(); @@ -246,8 +240,7 @@ describe('the keyboard shortcuts', () => { event.ctrlKey = false; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); @@ -270,8 +263,7 @@ describe('the keyboard shortcuts', () => { sqlEditorControllerSpy.isQueryRunning.and.returnValue(true); keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); expect(queryToolActionsSpy.download).not.toHaveBeenCalled(); @@ -286,8 +278,7 @@ describe('the keyboard shortcuts', () => { macKeysSetup(); event.which = FWD_SLASH_KEY; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); @@ -303,8 +294,7 @@ describe('the keyboard shortcuts', () => { windowsKeysSetup(); event.which = FWD_SLASH_KEY; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); @@ -328,8 +318,7 @@ describe('the keyboard shortcuts', () => { it('does nothing', () => { keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); expect(queryToolActionsSpy.commentLineCode).not.toHaveBeenCalled(); @@ -344,8 +333,7 @@ describe('the keyboard shortcuts', () => { it('does nothing', () => { keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); expect(queryToolActionsSpy.commentLineCode).not.toHaveBeenCalled(); @@ -361,8 +349,7 @@ describe('the keyboard shortcuts', () => { macKeysSetup(); event.which = PERIOD_KEY; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); @@ -377,8 +364,7 @@ describe('the keyboard shortcuts', () => { windowsKeysSetup(); event.which = PERIOD_KEY; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); @@ -402,8 +388,7 @@ describe('the keyboard shortcuts', () => { it('does nothing', () => { keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); expect(queryToolActionsSpy.uncommentLineCode).not.toHaveBeenCalled(); }); @@ -416,8 +401,7 @@ describe('the keyboard shortcuts', () => { it('does nothing', () => { keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); expect(queryToolActionsSpy.uncommentLineCode).not.toHaveBeenCalled(); @@ -434,8 +418,7 @@ describe('the keyboard shortcuts', () => { event.which = FWD_SLASH_KEY; event.shiftKey = true; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); @@ -454,8 +437,7 @@ describe('the keyboard shortcuts', () => { event.which = FWD_SLASH_KEY; event.shiftKey = true; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); @@ -477,8 +459,7 @@ describe('the keyboard shortcuts', () => { event.which = FWD_SLASH_KEY; event.shiftKey = true; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); it('does nothing', () => { @@ -491,8 +472,7 @@ describe('the keyboard shortcuts', () => { event.which = FWD_SLASH_KEY; event.shiftKey = true; keyboardShortcuts.processEventQueryTool( - sqlEditorControllerSpy, queryToolkeyboardShortcutsConfig, - queryToolActionsSpy, event + sqlEditorControllerSpy, queryToolActionsSpy, event ); }); it('does nothing', () => { @@ -502,6 +482,45 @@ describe('the keyboard shortcuts', () => { }); }); + describe('shortcut to text converters', ()=> { + var shortcut = { + alt: false, + shift: false, + control: false, + key: { + char: 'a', + key_code: 65, + }, + }; + + it('shortcut_key',()=>{ + expect(keyboardShortcuts.shortcut_key(shortcut)).toBe('A'); + }); + + it('shortcut_accesskey_title',()=>{ + expect(keyboardShortcuts.shortcut_accesskey_title( + 'Title', shortcut)).toBe(gettext('Title (accesskey + A)')); + }); + + it('shortcut_title',()=>{ + shortcut.alt = true, shortcut.shift = false, shortcut.control = false; + expect(keyboardShortcuts.shortcut_title( + 'Title', shortcut)).toBe(gettext('Title (Alt+A)')); + + shortcut.alt = false, shortcut.shift = true, shortcut.control = false; + expect(keyboardShortcuts.shortcut_title( + 'Title', shortcut)).toBe(gettext('Title (Shift+A)')); + + shortcut.alt = false, shortcut.shift = false, shortcut.control = true; + expect(keyboardShortcuts.shortcut_title( + 'Title', shortcut)).toBe(gettext('Title (Ctrl+A)')); + + shortcut.alt = true, shortcut.shift = true, shortcut.control = true; + expect(keyboardShortcuts.shortcut_title( + 'Title', shortcut)).toBe(gettext('Title (Alt+Shift+Ctrl+A)')); + }); + }); + function expectEventPropagationToStop() { describe('stops all event propogation', () => { diff --git a/web/regression/javascript/sqleditor_utils_spec.js b/web/regression/javascript/sqleditor_utils_spec.js index c738f82a..75c34afc 100644 --- a/web/regression/javascript/sqleditor_utils_spec.js +++ b/web/regression/javascript/sqleditor_utils_spec.js @@ -28,5 +28,13 @@ function (SqlEditorUtils) { expect(SqlEditorUtils.capitalizeFirstLetter('create script')).toEqual('Create script'); }); }); + + describe('Calculate font size of input number passed', function () { + it('calcFontSize', function () { + expect(SqlEditorUtils.calcFontSize(1.456)).toEqual('1.46em'); + expect(SqlEditorUtils.calcFontSize()).toEqual('0em'); + expect(SqlEditorUtils.calcFontSize(2)).toEqual('2em'); + }); + }); }); }); diff --git a/web/webpack.shim.js b/web/webpack.shim.js index c12e7f3b..41bf1033 100644 --- a/web/webpack.shim.js +++ b/web/webpack.shim.js @@ -124,6 +124,7 @@ var webpackShimConfig = { 'bundled_codemirror': path.join(__dirname, './pgadmin/static/bundle/codemirror'), 'bundled_browser': path.join(__dirname, './pgadmin/static/bundle/browser'), 'sources': path.join(__dirname, './pgadmin/static/js'), + 'sourcesjsx': path.join(__dirname, './pgadmin/static/jsx'), 'pgadmin': path.join(__dirname, './pgadmin/static/js/pgadmin'), 'translations': path.join(__dirname, './pgadmin/tools/templates/js/translations'), 'sources/gettext': path.join(__dirname, './pgadmin/static/js/gettext'), @@ -179,6 +180,7 @@ var webpackShimConfig = { 'pgadmin.browser.error': path.join(__dirname, './pgadmin/browser/static/js/error'), 'pgadmin.browser.frame': path.join(__dirname, './pgadmin/browser/static/js/frame'), 'pgadmin.browser.keyboard': path.join(__dirname, './pgadmin/browser/static/js/keyboard'), + 'pgadmin.browser.preferences': path.join(__dirname, './pgadmin/browser/static/js/preferences'), 'pgadmin.browser.menu': path.join(__dirname, './pgadmin/browser/static/js/menu'), 'pgadmin.browser.messages': '/browser/js/messages', 'pgadmin.browser.node': path.join(__dirname, './pgadmin/browser/static/js/node'), diff --git a/web/webpack.test.config.js b/web/webpack.test.config.js index ef893e0b..757107ca 100644 --- a/web/webpack.test.config.js +++ b/web/webpack.test.config.js @@ -83,6 +83,7 @@ module.exports = { 'pgadmin.backform': sourcesDir + '/js/backform.pgadmin', 'pgbrowser': path.resolve(__dirname, 'regression/javascript/fake_browser'), 'pgadmin.schema.dir': path.resolve(__dirname, 'pgadmin/browser/server_groups/servers/databases/schemas/static/js'), + 'pgadmin.browser.preferences': path.join(__dirname, './pgadmin/browser/static/js/preferences'), }, }, }; ^ permalink raw reply [nested|flat] 14+ messages in thread
* Re: [pgAdmin4][RM3294] User need to reset the layout to see the changed preferences parameters @ 2018-07-05 10:39 Dave Page <[email protected]> parent: Aditya Toshniwal <[email protected]> 0 siblings, 1 reply; 14+ messages in thread From: Dave Page @ 2018-07-05 10:39 UTC (permalink / raw) To: Aditya Toshniwal <[email protected]>; +Cc: Akshay Joshi <[email protected]>; pgadmin-hackers Thanks - patch applied! On Wed, Jul 4, 2018 at 10:19 AM, Aditya Toshniwal < [email protected]> wrote: > Hi Hackers, > > Attached is the updated patch for the RM. Change of the flags like auto > commit, explain->verbose, etc. will reflect in all other open sql editors. > Kindly review. > > On Fri, Jun 29, 2018 at 10:39 PM, Aditya Toshniwal <aditya.toshniwal@ > enterprisedb.com> wrote: > >> Hi Dave, >> >> On Fri, Jun 29, 2018 at 9:30 PM, Dave Page <[email protected]> wrote: >> >>> Hi >>> >>> On Fri, Jun 29, 2018 at 3:14 PM, Aditya Toshniwal < >>> [email protected]> wrote: >>> >>>> Hi Hackers, >>>> >>>> Attached is the updated patch. >>>> >>> >>> This seems to work for the most part, however I saw what seemed like odd >>> behaviour. If I have 2 query tool windows open; >>> >>> - Changing a preference from the Preferences dialogue updates both query >>> tools. >>> >>> - Changing a preference from a Query Tool updates the Preferences >>> dialogue. >>> >>> - Changing a preference from a Query Tool does *not* update the other >>> Query Tool. >>> >>> The last point seems odd to me, though it also kinda makes sense to not >>> have one query tool affect the other. The problem with that is that it >>> could get quite confusing when they get out of sync. I think it would be >>> better for a change in one Query Tool to update the other(s). >>> >>> What do you think? Was this behaviour intentional? >>> >> >> No this was not intentional. It should reflect in other query tools as >> well because changing the flags like Auto Commit changes the preferences >> config and is not local to a Query tool. I missed the fact that some >> preferences can be changed from other than preference dialog. >> >> Will send the updated patch with the fix. >> >>> >>> (FYI, in case this was a one-off bug, I was testing using "Auto Commit?") >>> >>> >>>> >>>> On Fri, Jun 29, 2018 at 4:46 PM, Aditya Toshniwal < >>>> [email protected]> wrote: >>>> >>>>> Hi Akshay, >>>>> >>>>> On Fri, Jun 29, 2018 at 3:42 PM, Akshay Joshi < >>>>> [email protected]> wrote: >>>>> >>>>>> Hi Aditya >>>>>> >>>>>> I have applied your patch and run pgAdmin4. I have found following >>>>>> two issue in the browser: >>>>>> >>>>>> - Found error while open Preferences dialog. Refer >>>>>> Open_Preferences_Dialog.png >>>>>> >>>>>> This error occurs even with the latest pull without changes. >>>>> >>>>> >>>>>> >>>>>> - Set the preferences setting "Open in new browser tab" to True >>>>>> and open the query tool. Refer "Open_In_New_Broswer.png". >>>>>> >>>>>> Will look into this. >>>>> >>>>> >>>>>> I haven't review the code. >>>>>> >>>>>> On Thu, Jun 28, 2018 at 8:04 PM, Aditya Toshniwal < >>>>>> [email protected]> wrote: >>>>>> >>>>>>> Hi Hackers, >>>>>>> >>>>>>> Attached is the patch for making preferences realtime and applying >>>>>>> without reseting the layout. Please note, the patch is only for one module >>>>>>> - SQL Editor and is the first part for the RM. There are lot of changes to >>>>>>> be done to cover all and hence sending in parts. This will not affect/break >>>>>>> existing code. Further patches will cover other modules. >>>>>>> >>>>>>> Highlights of this patch include: >>>>>>> - Changes will affect SQL Editors in Create dialog boxes, SQL tab of >>>>>>> the main screen, Query tool, History entries in the query tool, Query tool >>>>>>> opened in New Tab/Window >>>>>>> - All the components of SQL editor will refer to single source of >>>>>>> preferences which is cached in the Browser object. All other redundant ajax >>>>>>> get preference calls are removed. >>>>>>> - SQL editor will not refer template JS variables anymore, once all >>>>>>> the references are removed the template variables will also be removed. >>>>>>> - Code refactoring wherever possible. >>>>>>> - Covered JS test cases wherever possible. >>>>>>> >>>>>>> Request you to kindly review. >>>>>>> >>>>>>> -- >>>>>>> Thanks and Regards, >>>>>>> Aditya Toshniwal >>>>>>> Software Engineer | EnterpriseDB Software Solutions | Pune >>>>>>> "Don't Complain about Heat, Plant a tree" >>>>>>> >>>>>> >>>>>> >>>>>> >>>>>> -- >>>>>> *Akshay Joshi* >>>>>> >>>>>> *Sr. Software Architect * >>>>>> >>>>>> >>>>>> >>>>>> *Phone: +91 20-3058-9517Mobile: +91 976-788-8246* >>>>>> >>>>> >>>>> >>>>> >>>>> -- >>>>> Thanks and Regards, >>>>> Aditya Toshniwal >>>>> Software Engineer | EnterpriseDB Software Solutions | Pune >>>>> "Don't Complain about Heat, Plant a tree" >>>>> >>>> >>>> >>>> >>>> -- >>>> Thanks and Regards, >>>> Aditya Toshniwal >>>> Software Engineer | EnterpriseDB Software Solutions | Pune >>>> "Don't Complain about Heat, Plant a tree" >>>> >>> >>> >>> >>> -- >>> Dave Page >>> Blog: http://pgsnake.blogspot.com >>> Twitter: @pgsnake >>> >>> EnterpriseDB UK: http://www.enterprisedb.com >>> The Enterprise PostgreSQL Company >>> >> >> >> >> -- >> Thanks and Regards, >> Aditya Toshniwal >> Software Engineer | EnterpriseDB Software Solutions | Pune >> "Don't Complain about Heat, Plant a tree" >> > > > > -- > Thanks and Regards, > Aditya Toshniwal > Software Engineer | EnterpriseDB Software Solutions | Pune > "Don't Complain about Heat, Plant a tree" > -- Dave Page Blog: http://pgsnake.blogspot.com Twitter: @pgsnake EnterpriseDB UK: http://www.enterprisedb.com The Enterprise PostgreSQL Company ^ permalink raw reply [nested|flat] 14+ messages in thread
* Re: [pgAdmin4][RM3294] User need to reset the layout to see the changed preferences parameters @ 2018-07-24 10:39 Aditya Toshniwal <[email protected]> parent: Dave Page <[email protected]> 0 siblings, 2 replies; 14+ messages in thread From: Aditya Toshniwal @ 2018-07-24 10:39 UTC (permalink / raw) To: Dave Page <[email protected]>; +Cc: Akshay Joshi <[email protected]>; pgadmin-hackers Hi Hackers, Attached is the second part of the changes for making preferences realtime. The patch includes dashboard and debugger modules. I would also request to create RMs for javascript test cases for dashboard and debugger modules as currently there is no setup for the test cases of these two modules. The changes are on the JS side and so patch does not have any test cases included. Kindly review. On Thu, Jul 5, 2018 at 4:09 PM, Dave Page <[email protected]> wrote: > Thanks - patch applied! > > On Wed, Jul 4, 2018 at 10:19 AM, Aditya Toshniwal <aditya.toshniwal@ > enterprisedb.com> wrote: > >> Hi Hackers, >> >> Attached is the updated patch for the RM. Change of the flags like auto >> commit, explain->verbose, etc. will reflect in all other open sql editors. >> Kindly review. >> >> On Fri, Jun 29, 2018 at 10:39 PM, Aditya Toshniwal < >> [email protected]> wrote: >> >>> Hi Dave, >>> >>> On Fri, Jun 29, 2018 at 9:30 PM, Dave Page <[email protected]> wrote: >>> >>>> Hi >>>> >>>> On Fri, Jun 29, 2018 at 3:14 PM, Aditya Toshniwal < >>>> [email protected]> wrote: >>>> >>>>> Hi Hackers, >>>>> >>>>> Attached is the updated patch. >>>>> >>>> >>>> This seems to work for the most part, however I saw what seemed like >>>> odd behaviour. If I have 2 query tool windows open; >>>> >>>> - Changing a preference from the Preferences dialogue updates both >>>> query tools. >>>> >>>> - Changing a preference from a Query Tool updates the Preferences >>>> dialogue. >>>> >>>> - Changing a preference from a Query Tool does *not* update the other >>>> Query Tool. >>>> >>>> The last point seems odd to me, though it also kinda makes sense to not >>>> have one query tool affect the other. The problem with that is that it >>>> could get quite confusing when they get out of sync. I think it would be >>>> better for a change in one Query Tool to update the other(s). >>>> >>>> What do you think? Was this behaviour intentional? >>>> >>> >>> No this was not intentional. It should reflect in other query tools as >>> well because changing the flags like Auto Commit changes the preferences >>> config and is not local to a Query tool. I missed the fact that some >>> preferences can be changed from other than preference dialog. >>> >>> Will send the updated patch with the fix. >>> >>>> >>>> (FYI, in case this was a one-off bug, I was testing using "Auto >>>> Commit?") >>>> >>>> >>>>> >>>>> On Fri, Jun 29, 2018 at 4:46 PM, Aditya Toshniwal < >>>>> [email protected]> wrote: >>>>> >>>>>> Hi Akshay, >>>>>> >>>>>> On Fri, Jun 29, 2018 at 3:42 PM, Akshay Joshi < >>>>>> [email protected]> wrote: >>>>>> >>>>>>> Hi Aditya >>>>>>> >>>>>>> I have applied your patch and run pgAdmin4. I have found following >>>>>>> two issue in the browser: >>>>>>> >>>>>>> - Found error while open Preferences dialog. Refer >>>>>>> Open_Preferences_Dialog.png >>>>>>> >>>>>>> This error occurs even with the latest pull without changes. >>>>>> >>>>>> >>>>>>> >>>>>>> - Set the preferences setting "Open in new browser tab" to True >>>>>>> and open the query tool. Refer "Open_In_New_Broswer.png". >>>>>>> >>>>>>> Will look into this. >>>>>> >>>>>> >>>>>>> I haven't review the code. >>>>>>> >>>>>>> On Thu, Jun 28, 2018 at 8:04 PM, Aditya Toshniwal < >>>>>>> [email protected]> wrote: >>>>>>> >>>>>>>> Hi Hackers, >>>>>>>> >>>>>>>> Attached is the patch for making preferences realtime and applying >>>>>>>> without reseting the layout. Please note, the patch is only for one module >>>>>>>> - SQL Editor and is the first part for the RM. There are lot of changes to >>>>>>>> be done to cover all and hence sending in parts. This will not affect/break >>>>>>>> existing code. Further patches will cover other modules. >>>>>>>> >>>>>>>> Highlights of this patch include: >>>>>>>> - Changes will affect SQL Editors in Create dialog boxes, SQL tab >>>>>>>> of the main screen, Query tool, History entries in the query tool, Query >>>>>>>> tool opened in New Tab/Window >>>>>>>> - All the components of SQL editor will refer to single source of >>>>>>>> preferences which is cached in the Browser object. All other redundant ajax >>>>>>>> get preference calls are removed. >>>>>>>> - SQL editor will not refer template JS variables anymore, once >>>>>>>> all the references are removed the template variables will also be removed. >>>>>>>> - Code refactoring wherever possible. >>>>>>>> - Covered JS test cases wherever possible. >>>>>>>> >>>>>>>> Request you to kindly review. >>>>>>>> >>>>>>>> -- >>>>>>>> Thanks and Regards, >>>>>>>> Aditya Toshniwal >>>>>>>> Software Engineer | EnterpriseDB Software Solutions | Pune >>>>>>>> "Don't Complain about Heat, Plant a tree" >>>>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>>>> -- >>>>>>> *Akshay Joshi* >>>>>>> >>>>>>> *Sr. Software Architect * >>>>>>> >>>>>>> >>>>>>> >>>>>>> *Phone: +91 20-3058-9517Mobile: +91 976-788-8246* >>>>>>> >>>>>> >>>>>> >>>>>> >>>>>> -- >>>>>> Thanks and Regards, >>>>>> Aditya Toshniwal >>>>>> Software Engineer | EnterpriseDB Software Solutions | Pune >>>>>> "Don't Complain about Heat, Plant a tree" >>>>>> >>>>> >>>>> >>>>> >>>>> -- >>>>> Thanks and Regards, >>>>> Aditya Toshniwal >>>>> Software Engineer | EnterpriseDB Software Solutions | Pune >>>>> "Don't Complain about Heat, Plant a tree" >>>>> >>>> >>>> >>>> >>>> -- >>>> Dave Page >>>> Blog: http://pgsnake.blogspot.com >>>> Twitter: @pgsnake >>>> >>>> EnterpriseDB UK: http://www.enterprisedb.com >>>> The Enterprise PostgreSQL Company >>>> >>> >>> >>> >>> -- >>> Thanks and Regards, >>> Aditya Toshniwal >>> Software Engineer | EnterpriseDB Software Solutions | Pune >>> "Don't Complain about Heat, Plant a tree" >>> >> >> >> >> -- >> Thanks and Regards, >> Aditya Toshniwal >> Software Engineer | EnterpriseDB Software Solutions | Pune >> "Don't Complain about Heat, Plant a tree" >> > > > > -- > Dave Page > Blog: http://pgsnake.blogspot.com > Twitter: @pgsnake > > EnterpriseDB UK: http://www.enterprisedb.com > The Enterprise PostgreSQL Company > -- Thanks and Regards, Aditya Toshniwal Software Engineer | EnterpriseDB Software Solutions | Pune "Don't Complain about Heat, Plant a tree" Attachments: [application/octet-stream] 0002-RM3294.patch (80.2K, 3-0002-RM3294.patch) download | inline diff: diff --git a/web/pgadmin/dashboard/__init__.py b/web/pgadmin/dashboard/__init__.py index 91162f76..ffd4a7bc 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 2fc7897c..61174f33 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 02c7d439..29a86bb0 100644 --- a/web/pgadmin/dashboard/static/js/dashboard.js +++ b/web/pgadmin/dashboard/static/js/dashboard.js @@ -205,6 +205,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 +243,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 +279,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 + '/'; } } @@ -309,6 +318,7 @@ define('pgadmin.dashboard', [ }) .done(function(data) { $(div).html(data); + self.init_dashboard(); }) .fail(function() { $(div).html( @@ -327,102 +337,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 - ) { - - // 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; - } + renderChartLoop: function(container, sid, did, url, options, counter, refresh) { + var data = [], + dataset = []; - // Animate - var setTimeoutFunc = function() { + var theIntervalFunc = function() { var path = url + sid; if (did != -1) { path += '/' + did; @@ -435,7 +359,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 +462,36 @@ define('pgadmin.dashboard', [ $(container).html( '<div class="alert alert-' + cls + ' pg-panel-message" role="alert">' + msg + '</div>' ); - - // 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_for('dashboard.session_stats'), + options, false, self.preferences[prefName] + ); + } }, // Handler function to support the "Add Server" link @@ -503,12 +523,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 +548,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 +637,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 +704,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 +820,7 @@ define('pgadmin.dashboard', [ cell: 'string', }]; - if (version < 90600) { + if (self.version < 90600) { server_activity_columns = server_activity_columns.concat( [{ name: 'waiting', @@ -766,7 +851,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 +860,7 @@ define('pgadmin.dashboard', [ label: '', cell: SessionDetailsCell, cell_priority: -1, - postgres_version: version, + postgres_version: self.version, schema: subNodeFieldsModel, }); @@ -788,7 +873,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 +884,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 +1014,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 +1050,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 +1071,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 +1111,7 @@ define('pgadmin.dashboard', [ cell: 'string', }]; - if (version < 90600) { + if (self.version < 90600) { database_activity_columns = database_activity_columns.concat( [{ name: 'waiting', @@ -1134,7 +1142,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 +1151,7 @@ define('pgadmin.dashboard', [ label: '', cell: SessionDetailsCell, cell_priority: -1, - postgres_version: version, + postgres_version: self.version, schema: subNodeFieldsModel, }); @@ -1155,7 +1163,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 +1173,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 +1266,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 +1295,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); diff --git a/web/pgadmin/dashboard/templates/dashboard/database_dashboard.html b/web/pgadmin/dashboard/templates/dashboard/database_dashboard.html index 37ff5b97..26cde01a 100644 --- a/web/pgadmin/dashboard/templates/dashboard/database_dashboard.html +++ b/web/pgadmin/dashboard/templates/dashboard/database_dashboard.html @@ -1,135 +1,110 @@ <div class="dashboard-container"> -{% if settings.show_graphs %} - <div class="row"> - <div class="col-xs-6"> - <div class="obj_properties"> - <legend class="badge">{{ _('Database sessions') }}</legend> + <div id="dashboard-graphs" class="dashboard-hidden"> + <div class="row"> + <div class="col-xs-6"> + <div class="obj_properties"> + <legend class="badge">{{ _('Database sessions') }}</legend> + </div> </div> - </div> - <div class="col-xs-6"> - <div class="obj_properties"> - <legend class="badge">{{ _('Transactions per second') }}</legend> + <div class="col-xs-6"> + <div class="obj_properties"> + <legend class="badge">{{ _('Transactions per second') }}</legend> + </div> </div> </div> - </div> - <div class="row"> - <div class="col-xs-6"> - <div id="graph-sessions" class="graph-container"></div> - </div> - <div class="col-xs-6"> - <div id="graph-tps" class="graph-container"></div> + <div class="row dashboard-row"> + <div class="col-xs-6"> + <div id="graph-sessions" class="graph-container"></div> + </div> + <div class="col-xs-6"> + <div id="graph-tps" class="graph-container"></div> + </div> </div> - </div> - <div class="row dashboard-header-spacer"> - <div class="col-xs-4"> - <div class="obj_properties"> - <legend class="badge">{{ _('Tuples in') }}</legend> + <div class="row"> + <div class="col-xs-4"> + <div class="obj_properties"> + <legend class="badge">{{ _('Tuples in') }}</legend> + </div> </div> - </div> - <div class="col-xs-4"> - <div class="obj_properties"> - <legend class="badge">{{ _('Tuples out') }}</legend> + <div class="col-xs-4"> + <div class="obj_properties"> + <legend class="badge">{{ _('Tuples out') }}</legend> + </div> </div> - </div> - <div class="col-xs-4"> - <div class="obj_properties"> - <legend class="badge">{{ _('Block I/O') }}</legend> + <div class="col-xs-4"> + <div class="obj_properties"> + <legend class="badge">{{ _('Block I/O') }}</legend> + </div> </div> </div> - </div> - <div class="row"> - <div class="col-xs-4"> - <div id="graph-ti" class="graph-container"></div> - </div> - <div class="col-xs-4"> - <div id="graph-to" class="graph-container"></div> - </div> - <div class="col-xs-4"> - <div id="graph-bio" class="graph-container"></div> + <div class="row dashboard-row"> + <div class="col-xs-4"> + <div id="graph-ti" class="graph-container"></div> + </div> + <div class="col-xs-4"> + <div id="graph-to" class="graph-container"></div> + </div> + <div class="col-xs-4"> + <div id="graph-bio" class="graph-container"></div> + </div> </div> </div> -{% endif %} -{% if settings.show_activity %} - {# If we are displaying graphs then only we need space on top #} - {% if settings.show_graphs %} - <div class="row dashboard-header-spacer"> - {% else %} - <div class="row"> - {% endif %} - <div class="col-xs-12"> - <div class="obj_properties"> - <legend class="badge">{{ _('Database activity') }}</legend> + <div id="dashboard-activity" class="dashboard-hidden"> + <div class="row"> + <div class="col-xs-12"> + <div class="obj_properties"> + <legend class="badge">{{ _('Database activity') }}</legend> + </div> </div> </div> - </div> - <div class="row"> - <div class="col-xs-12"> - <div class="dashboard-tab-container"> - <!-- Nav tabs --> - <ul class="nav nav-tabs dashboard-tab-panel" role="tablist"> - <li role="presentation" class="active dashboard-tab"><a href="#tab_panel_database_activity" - aria-controls="tab_database_activity" - role="tab" data-toggle="tab">{{ _('Sessions') }}</a> - </li> - <li role="presentation" class="dashboard-tab"><a href="#tab_panel_database_locks" - aria-controls="tab_database_locks" role="tab" - data-toggle="tab">{{ _('Locks') }}</a></li> - <li role="presentation" class="dashboard-tab"><a href="#tab_panel_database_prepared" - aria-controls="tab_database_prepared" role="tab" - data-toggle="tab">{{ _('Prepared Transactions') }}</a></li> - </ul> + <div class="row dashboard-row"> + <div class="col-xs-12"> + <div class="dashboard-tab-container"> + <!-- Nav tabs --> + <ul class="nav nav-tabs dashboard-tab-panel" role="tablist"> + <li role="presentation" class="active dashboard-tab"><a href="#tab_panel_database_activity" + aria-controls="tab_database_activity" + role="tab" data-toggle="tab">{{ _('Sessions') }}</a> + </li> + <li role="presentation" class="dashboard-tab"><a href="#tab_panel_database_locks" + aria-controls="tab_database_locks" role="tab" + data-toggle="tab">{{ _('Locks') }}</a></li> + <li role="presentation" class="dashboard-tab"><a href="#tab_panel_database_prepared" + aria-controls="tab_database_prepared" role="tab" + data-toggle="tab">{{ _('Prepared Transactions') }}</a></li> + </ul> - <!-- Tab panes --> - <div class="tab-content"> - <div role="tabpanel" class="tab-pane active" id="tab_panel_database_activity"> - <div class="dashboard-tab-btn-group pg-prop-btn-group-above"> - <button id="btn_database_activity_refresh" type="button" class="btn btn-default" title="{{ _('Refresh') }}"> <span class="fa fa-lg fa-refresh"></span></button> - <div id="database_activity_filter"></div> + <!-- Tab panes --> + <div class="tab-content"> + <div role="tabpanel" class="tab-pane active" id="tab_panel_database_activity"> + <div class="dashboard-tab-btn-group pg-prop-btn-group-above"> + <button id="btn_database_activity_refresh" type="button" class="btn btn-default" title="{{ _('Refresh') }}"> <span class="fa fa-lg fa-refresh"></span></button> + <div id="database_activity_filter"></div> + </div> + <div id="database_activity" class="grid-container"></div> </div> - <div id="database_activity" class="grid-container"></div> - </div> - <div role="tabpanel" class="tab-pane" id="tab_panel_database_locks"> - <div class="dashboard-tab-btn-group pg-prop-btn-group-above"> - <button id="btn_database_locks_refresh" type="button" class="btn btn-default" title="{{ _('Refresh') }}"> <span class="fa fa-lg fa-refresh"></span></button> - <div id="database_locks_filter"></div> + <div role="tabpanel" class="tab-pane" id="tab_panel_database_locks"> + <div class="dashboard-tab-btn-group pg-prop-btn-group-above"> + <button id="btn_database_locks_refresh" type="button" class="btn btn-default" title="{{ _('Refresh') }}"> <span class="fa fa-lg fa-refresh"></span></button> + <div id="database_locks_filter"></div> + </div> + <div id="database_locks" class="grid-container"></div> </div> - <div id="database_locks" class="grid-container"></div> - </div> - <div role="tabpanel" class="tab-pane" id="tab_panel_database_prepared"> - <div class="dashboard-tab-btn-group pg-prop-btn-group-above"> - <button id="btn_database_prepared_refresh" type="button" class="btn btn-default" title="{{ _('Refresh') }}"> <span class="fa fa-lg fa-refresh"></span></button> - <div id="database_prepared_filter"></div> + <div role="tabpanel" class="tab-pane" id="tab_panel_database_prepared"> + <div class="dashboard-tab-btn-group pg-prop-btn-group-above"> + <button id="btn_database_prepared_refresh" type="button" class="btn btn-default" title="{{ _('Refresh') }}"> <span class="fa fa-lg fa-refresh"></span></button> + <div id="database_prepared_filter"></div> + </div> + <div id="database_prepared" class="grid-container"></div> </div> - <div id="database_prepared" class="grid-container"></div> </div> </div> </div> </div> </div> -{% endif %} - -{% if not settings.show_graphs and not settings.show_activity %} - <div class="alert alert-info pg-panel-message" role="alert"> + <div id="dashboard-none-show" class="alert alert-info pg-panel-message dashboard-hidden" role="alert"> {{ _('All Dashboard elements are currently disabled.') }} </div> -{% endif %} - </div> - -<script type="text/javascript"> - // Initiate database dashboard - pgAdmin.Dashboard.init_database_dashboard( - {{ sid }}, - {{ did }}, - {{ version }}, - {{ rates.session_stats_refresh }}, - {{ rates.tps_stats_refresh }}, - {{ rates.ti_stats_refresh }}, - {{ rates.to_stats_refresh }}, - {{ rates.bio_stats_refresh }}, - {{ settings.show_graphs|lower }}, - {{ settings.show_activity|lower }} - ); -</script> diff --git a/web/pgadmin/dashboard/templates/dashboard/server_dashboard.html b/web/pgadmin/dashboard/templates/dashboard/server_dashboard.html index b3578253..5a4df66a 100644 --- a/web/pgadmin/dashboard/templates/dashboard/server_dashboard.html +++ b/web/pgadmin/dashboard/templates/dashboard/server_dashboard.html @@ -1,144 +1,120 @@ <div class="dashboard-container"> -{% if settings.show_graphs %} - <div class="row"> - <div class="col-xs-6"> - <div class="obj_properties"> - <legend class="badge">{{ _('Server sessions') }}</legend> + <div id="dashboard-graphs" class="dashboard-hidden"> + <div class="row"> + <div class="col-xs-6"> + <div class="obj_properties"> + <legend class="badge">{{ _('Server sessions') }}</legend> + </div> </div> - </div> - <div class="col-xs-6"> - <div class="obj_properties"> - <legend class="badge">{{ _('Transactions per second') }}</legend> + <div class="col-xs-6"> + <div class="obj_properties"> + <legend class="badge">{{ _('Transactions per second') }}</legend> + </div> </div> </div> - </div> - <div class="row"> - <div class="col-xs-6"> - <div id="graph-sessions" class="graph-container"></div> - </div> - <div class="col-xs-6"> - <div id="graph-tps" class="graph-container"></div> + <div class="row dashboard-row"> + <div class="col-xs-6"> + <div id="graph-sessions" class="graph-container"></div> + </div> + <div class="col-xs-6"> + <div id="graph-tps" class="graph-container"></div> + </div> </div> - </div> - <div class="row dashboard-header-spacer"> - <div class="col-xs-4"> - <div class="obj_properties"> - <legend class="badge">{{ _('Tuples in') }}</legend> + <div class="row"> + <div class="col-xs-4"> + <div class="obj_properties"> + <legend class="badge">{{ _('Tuples in') }}</legend> + </div> </div> - </div> - <div class="col-xs-4"> - <div class="obj_properties"> - <legend class="badge">{{ _('Tuples out') }}</legend> + <div class="col-xs-4"> + <div class="obj_properties"> + <legend class="badge">{{ _('Tuples out') }}</legend> + </div> </div> - </div> - <div class="col-xs-4"> - <div class="obj_properties"> - <legend class="badge">{{ _('Block I/O') }}</legend> + <div class="col-xs-4"> + <div class="obj_properties"> + <legend class="badge">{{ _('Block I/O') }}</legend> + </div> </div> </div> - </div> - <div class="row"> - <div class="col-xs-4"> - <div id="graph-ti" class="graph-container"></div> - </div> - <div class="col-xs-4"> - <div id="graph-to" class="graph-container"></div> - </div> - <div class="col-xs-4"> - <div id="graph-bio" class="graph-container"></div> + <div class="row dashboard-row"> + <div class="col-xs-4"> + <div id="graph-ti" class="graph-container"></div> + </div> + <div class="col-xs-4"> + <div id="graph-to" class="graph-container"></div> + </div> + <div class="col-xs-4"> + <div id="graph-bio" class="graph-container"></div> + </div> </div> </div> -{% endif %} -{% if settings.show_activity %} - {# If we are displaying graphs then only we need space on top #} - {% if settings.show_graphs %} - <div class="row dashboard-header-spacer"> - {% else %} - <div class="row"> - {% endif %} - <div class="col-xs-12"> - <div class="obj_properties"> - <legend class="badge">{{ _('Server activity') }}</legend> + <div id="dashboard-activity" class="dashboard-hidden"> + <div class="row"> + <div class="col-xs-12"> + <div class="obj_properties"> + <legend class="badge">{{ _('Server activity') }}</legend> + </div> </div> </div> - </div> - <div class="row"> - <div class="col-xs-12"> - <div class="dashboard-tab-container"> - <!-- Nav tabs --> - <ul class="nav nav-tabs dashboard-tab-panel" role="tablist"> - <li role="presentation" class="active dashboard-tab"><a href="#tab_panel_server_activity" - aria-controls="tab_server_activity" - role="tab" data-toggle="tab">{{ _('Sessions') }}</a> - </li> - <li role="presentation" class="dashboard-tab"><a href="#tab_panel_server_locks" - aria-controls="tab_server_locks" role="tab" - data-toggle="tab">{{ _('Locks') }}</a></li> - <li role="presentation" class="dashboard-tab"><a href="#tab_panel_server_prepared" - aria-controls="tab_server_prepared" role="tab" - data-toggle="tab">{{ _('Prepared Transactions') }}</a></li> - <li role="presentation" class="dashboard-tab"><a href="#tab_panel_server_config" - aria-controls="tab_server_config" role="tab" - data-toggle="tab">{{ _('Configuration') }}</a></li> - </ul> + <div class="row dashboard-row"> + <div class="col-xs-12"> + <div class="dashboard-tab-container"> + <!-- Nav tabs --> + <ul class="nav nav-tabs dashboard-tab-panel" role="tablist"> + <li role="presentation" class="active dashboard-tab"><a href="#tab_panel_server_activity" + aria-controls="tab_server_activity" + role="tab" data-toggle="tab">{{ _('Sessions') }}</a> + </li> + <li role="presentation" class="dashboard-tab"><a href="#tab_panel_server_locks" + aria-controls="tab_server_locks" role="tab" + data-toggle="tab">{{ _('Locks') }}</a></li> + <li role="presentation" class="dashboard-tab"><a href="#tab_panel_server_prepared" + aria-controls="tab_server_prepared" role="tab" + data-toggle="tab">{{ _('Prepared Transactions') }}</a></li> + <li role="presentation" class="dashboard-tab"><a href="#tab_panel_server_config" + aria-controls="tab_server_config" role="tab" + data-toggle="tab">{{ _('Configuration') }}</a></li> + </ul> - <!-- Tab panes --> - <div class="tab-content"> - <div role="tabpanel" class="tab-pane active" id="tab_panel_server_activity"> - <div class="dashboard-tab-btn-group pg-prop-btn-group-above"> - <button id="btn_server_activity_refresh" type="button" class="btn btn-default" title="{{ _('Refresh') }}"> <span class="fa fa-lg fa-refresh"></span></button> - <div id="server_activity_filter"></div> + <!-- Tab panes --> + <div class="tab-content"> + <div role="tabpanel" class="tab-pane active" id="tab_panel_server_activity"> + <div class="dashboard-tab-btn-group pg-prop-btn-group-above"> + <button id="btn_server_activity_refresh" type="button" class="btn btn-default" title="{{ _('Refresh') }}"> <span class="fa fa-lg fa-refresh"></span></button> + <div id="server_activity_filter"></div> + </div> + <div id="server_activity" class="grid-container"></div> </div> - <div id="server_activity" class="grid-container"></div> - </div> - <div role="tabpanel" class="tab-pane" id="tab_panel_server_locks"> - <div class="dashboard-tab-btn-group pg-prop-btn-group-above"> - <button id="btn_server_locks_refresh" type="button" class="btn btn-default" title="{{ _('Refresh') }}"> <span class="fa fa-lg fa-refresh"></span></button> - <div id="server_locks_filter"></div> + <div role="tabpanel" class="tab-pane" id="tab_panel_server_locks"> + <div class="dashboard-tab-btn-group pg-prop-btn-group-above"> + <button id="btn_server_locks_refresh" type="button" class="btn btn-default" title="{{ _('Refresh') }}"> <span class="fa fa-lg fa-refresh"></span></button> + <div id="server_locks_filter"></div> + </div> + <div id="server_locks" class="grid-container"></div> </div> - <div id="server_locks" class="grid-container"></div> - </div> - <div role="tabpanel" class="tab-pane" id="tab_panel_server_prepared"> - <div class="dashboard-tab-btn-group pg-prop-btn-group-above"> - <button id="btn_server_prepared_refresh" type="button" class="btn btn-default" title="{{ _('Refresh') }}"> <span class="fa fa-lg fa-refresh"></span></button> - <div id="server_prepared_filter"></div> + <div role="tabpanel" class="tab-pane" id="tab_panel_server_prepared"> + <div class="dashboard-tab-btn-group pg-prop-btn-group-above"> + <button id="btn_server_prepared_refresh" type="button" class="btn btn-default" title="{{ _('Refresh') }}"> <span class="fa fa-lg fa-refresh"></span></button> + <div id="server_prepared_filter"></div> + </div> + <div id="server_prepared" class="grid-container"></div> </div> - <div id="server_prepared" class="grid-container"></div> - </div> - <div role="tabpanel" class="tab-pane" id="tab_panel_server_config"> - <div class="dashboard-tab-btn-group pg-prop-btn-group-above"> - <button id="btn_server_config_refresh" type="button" class="btn btn-default" title="{{ _('Refresh') }}"> <span class="fa fa-lg fa-refresh"></span></button> - <div id="server_config_filter"></div> + <div role="tabpanel" class="tab-pane" id="tab_panel_server_config"> + <div class="dashboard-tab-btn-group pg-prop-btn-group-above"> + <button id="btn_server_config_refresh" type="button" class="btn btn-default" title="{{ _('Refresh') }}"> <span class="fa fa-lg fa-refresh"></span></button> + <div id="server_config_filter"></div> + </div> + <div id="server_config" class="grid-container"></div> </div> - <div id="server_config" class="grid-container"></div> </div> </div> </div> </div> </div> -{% endif %} - -{% if not settings.show_graphs and not settings.show_activity %} - <div class="alert alert-info pg-panel-message" role="alert"> - {{ _('Dashboard has been disabled by user.') }} + <div id="dashboard-none-show" class="alert alert-info pg-panel-message dashboard-hidden" role="alert"> + {{ _('All Dashboard elements are currently disabled.') }} </div> -{% endif %} - </div> - -<script type="text/javascript"> - // Initiate server dashboard - pgAdmin.Dashboard.init_server_dashboard( - {{ sid }}, - {{ version }}, - {{ rates.session_stats_refresh }}, - {{ rates.tps_stats_refresh }}, - {{ rates.ti_stats_refresh }}, - {{ rates.to_stats_refresh }}, - {{ rates.bio_stats_refresh }}, - {{ settings.show_graphs|lower }}, - {{ settings.show_activity|lower }} - ); -</script> 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 dd24bddc..00000000 --- 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 232f67fd..667129dd 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 f24942d7..4479f85c 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/<node_type>/<int:sid>/<int:did>/<int:scid>/<int:fid>', 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 d632343e..39caca71 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 bc1aff11..35a6970e 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 58d97a06..08412698 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;} </style> {% endif %} -<div class="dubugger_main_container" tabindex="0"> +<div class="debugger_main_container" tabindex="0"> <nav class="navbar-inverse navbar-fixed-top"> <div id="btn-toolbar" class="btn-toolbar pg-prop-btn-group bg-gray-2 border-gray-3" role="toolbar" aria-label=""> <div class="btn-group" role="group" aria-label=""> - <button type="button" class="btn btn-default btn-step-into" - title="{{ _('Step into') }}{{ _(' (accesskey+{0})'.format(accesskey.step_into)) }}" - accesskey="{{ accesskey.step_into }}" + <button type="button" class="btn btn-default btn-step-into" id="btn-step-into" + title="" + accesskey="" tabindex="0" autofocus="autofocus"> <i class="fa fa-indent"></i> </button> - <button type="button" class="btn btn-default btn-step-over" - title="{{ _('Step over') }}{{ _(' (accesskey+{0})'.format(accesskey.step_over)) }}" - accesskey="{{ accesskey.step_over }}" + <button type="button" class="btn btn-default btn-step-over" id="btn-step-over" + title="" + accesskey="" tabindex="0"> <i class="fa fa-outdent"></i> </button> - <button type="button" class="btn btn-default btn-continue" - title="{{ _('Continue/Start') }}{{ _(' (accesskey+{0})'.format(accesskey.start)) }}" - accesskey="{{ accesskey.start }}" + <button type="button" class="btn btn-default btn-continue" id="btn-continue" + title="" + accesskey="" tabindex="0"> <i class="fa fa-play-circle"></i> </button> </div> <div class="btn-group" role="group" aria-label=""> - <button type="button" class="btn btn-default btn-toggle-breakpoint" - title="{{ _('Toggle breakpoint') }}{{ _(' (accesskey+{0})'.format(accesskey.toggle_breakpoint)) }}" - accesskey="{{ accesskey.toggle_breakpoint }}" + <button type="button" class="btn btn-default btn-toggle-breakpoint" id="btn-toggle-breakpoint" + title="" + accesskey="" tabindex="0"> <i class="fa fa-circle"></i> </button> - <button type="button" class="btn btn-default btn-clear-breakpoint" - title="{{ _('Clear all breakpoints') }}{{ _(' (accesskey+{0})'.format(accesskey.clear_breakpoints)) }}" - accesskey="{{ accesskey.clear_breakpoints }}" + <button type="button" class="btn btn-default btn-clear-breakpoint" id="btn-clear-breakpoint" + title="" + accesskey="" tabindex="0"> <i class="fa fa-ban"></i> </button> </div> <div class="btn-group" role="group" aria-label=""> - <button type="button" class="btn btn-default btn-stop" - accesskey="{{ accesskey.stop }}" - title="{{ _('Stop') }}{{ _(' (accesskey+{0})'.format(accesskey.stop)) }}" + <button type="button" class="btn btn-default btn-stop" id="btn-stop" + accesskey="" + title="" tabindex="0"> <i class="fa fa-stop-circle"></i> </button> ^ permalink raw reply [nested|flat] 14+ messages in thread
* Re: [pgAdmin4][RM3294] User need to reset the layout to see the changed preferences parameters @ 2018-07-24 10:43 Aditya Toshniwal <[email protected]> parent: Aditya Toshniwal <[email protected]> 1 sibling, 0 replies; 14+ messages in thread From: Aditya Toshniwal @ 2018-07-24 10:43 UTC (permalink / raw) To: Dave Page <[email protected]>; +Cc: Akshay Joshi <[email protected]>; pgadmin-hackers Adding to previous mail, I have removed shadow from graph lines and increased resolution for better visibility and fixed few issues related to graphs. On Tue, Jul 24, 2018 at 4:09 PM, Aditya Toshniwal < [email protected]> wrote: > Hi Hackers, > > Attached is the second part of the changes for making preferences > realtime. The patch includes dashboard and debugger modules. > I would also request to create RMs for javascript test cases for dashboard > and debugger modules as currently there is no setup for the test cases of > these two modules. > The changes are on the JS side and so patch does not have any test cases > included. > > Kindly review. > > > On Thu, Jul 5, 2018 at 4:09 PM, Dave Page <[email protected]> wrote: > >> Thanks - patch applied! >> >> On Wed, Jul 4, 2018 at 10:19 AM, Aditya Toshniwal < >> [email protected]> wrote: >> >>> Hi Hackers, >>> >>> Attached is the updated patch for the RM. Change of the flags like auto >>> commit, explain->verbose, etc. will reflect in all other open sql editors. >>> Kindly review. >>> >>> On Fri, Jun 29, 2018 at 10:39 PM, Aditya Toshniwal < >>> [email protected]> wrote: >>> >>>> Hi Dave, >>>> >>>> On Fri, Jun 29, 2018 at 9:30 PM, Dave Page <[email protected]> wrote: >>>> >>>>> Hi >>>>> >>>>> On Fri, Jun 29, 2018 at 3:14 PM, Aditya Toshniwal < >>>>> [email protected]> wrote: >>>>> >>>>>> Hi Hackers, >>>>>> >>>>>> Attached is the updated patch. >>>>>> >>>>> >>>>> This seems to work for the most part, however I saw what seemed like >>>>> odd behaviour. If I have 2 query tool windows open; >>>>> >>>>> - Changing a preference from the Preferences dialogue updates both >>>>> query tools. >>>>> >>>>> - Changing a preference from a Query Tool updates the Preferences >>>>> dialogue. >>>>> >>>>> - Changing a preference from a Query Tool does *not* update the other >>>>> Query Tool. >>>>> >>>>> The last point seems odd to me, though it also kinda makes sense to >>>>> not have one query tool affect the other. The problem with that is that it >>>>> could get quite confusing when they get out of sync. I think it would be >>>>> better for a change in one Query Tool to update the other(s). >>>>> >>>>> What do you think? Was this behaviour intentional? >>>>> >>>> >>>> No this was not intentional. It should reflect in other query tools as >>>> well because changing the flags like Auto Commit changes the preferences >>>> config and is not local to a Query tool. I missed the fact that some >>>> preferences can be changed from other than preference dialog. >>>> >>>> Will send the updated patch with the fix. >>>> >>>>> >>>>> (FYI, in case this was a one-off bug, I was testing using "Auto >>>>> Commit?") >>>>> >>>>> >>>>>> >>>>>> On Fri, Jun 29, 2018 at 4:46 PM, Aditya Toshniwal < >>>>>> [email protected]> wrote: >>>>>> >>>>>>> Hi Akshay, >>>>>>> >>>>>>> On Fri, Jun 29, 2018 at 3:42 PM, Akshay Joshi < >>>>>>> [email protected]> wrote: >>>>>>> >>>>>>>> Hi Aditya >>>>>>>> >>>>>>>> I have applied your patch and run pgAdmin4. I have found following >>>>>>>> two issue in the browser: >>>>>>>> >>>>>>>> - Found error while open Preferences dialog. Refer >>>>>>>> Open_Preferences_Dialog.png >>>>>>>> >>>>>>>> This error occurs even with the latest pull without changes. >>>>>>> >>>>>>> >>>>>>>> >>>>>>>> - Set the preferences setting "Open in new browser tab" to True >>>>>>>> and open the query tool. Refer "Open_In_New_Broswer.png". >>>>>>>> >>>>>>>> Will look into this. >>>>>>> >>>>>>> >>>>>>>> I haven't review the code. >>>>>>>> >>>>>>>> On Thu, Jun 28, 2018 at 8:04 PM, Aditya Toshniwal < >>>>>>>> [email protected]> wrote: >>>>>>>> >>>>>>>>> Hi Hackers, >>>>>>>>> >>>>>>>>> Attached is the patch for making preferences realtime and applying >>>>>>>>> without reseting the layout. Please note, the patch is only for one module >>>>>>>>> - SQL Editor and is the first part for the RM. There are lot of changes to >>>>>>>>> be done to cover all and hence sending in parts. This will not affect/break >>>>>>>>> existing code. Further patches will cover other modules. >>>>>>>>> >>>>>>>>> Highlights of this patch include: >>>>>>>>> - Changes will affect SQL Editors in Create dialog boxes, SQL tab >>>>>>>>> of the main screen, Query tool, History entries in the query tool, Query >>>>>>>>> tool opened in New Tab/Window >>>>>>>>> - All the components of SQL editor will refer to single source of >>>>>>>>> preferences which is cached in the Browser object. All other redundant ajax >>>>>>>>> get preference calls are removed. >>>>>>>>> - SQL editor will not refer template JS variables anymore, once >>>>>>>>> all the references are removed the template variables will also be removed. >>>>>>>>> - Code refactoring wherever possible. >>>>>>>>> - Covered JS test cases wherever possible. >>>>>>>>> >>>>>>>>> Request you to kindly review. >>>>>>>>> >>>>>>>>> -- >>>>>>>>> Thanks and Regards, >>>>>>>>> Aditya Toshniwal >>>>>>>>> Software Engineer | EnterpriseDB Software Solutions | Pune >>>>>>>>> "Don't Complain about Heat, Plant a tree" >>>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> -- >>>>>>>> *Akshay Joshi* >>>>>>>> >>>>>>>> *Sr. Software Architect * >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> *Phone: +91 20-3058-9517Mobile: +91 976-788-8246* >>>>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>>>> -- >>>>>>> Thanks and Regards, >>>>>>> Aditya Toshniwal >>>>>>> Software Engineer | EnterpriseDB Software Solutions | Pune >>>>>>> "Don't Complain about Heat, Plant a tree" >>>>>>> >>>>>> >>>>>> >>>>>> >>>>>> -- >>>>>> Thanks and Regards, >>>>>> Aditya Toshniwal >>>>>> Software Engineer | EnterpriseDB Software Solutions | Pune >>>>>> "Don't Complain about Heat, Plant a tree" >>>>>> >>>>> >>>>> >>>>> >>>>> -- >>>>> Dave Page >>>>> Blog: http://pgsnake.blogspot.com >>>>> Twitter: @pgsnake >>>>> >>>>> EnterpriseDB UK: http://www.enterprisedb.com >>>>> The Enterprise PostgreSQL Company >>>>> >>>> >>>> >>>> >>>> -- >>>> Thanks and Regards, >>>> Aditya Toshniwal >>>> Software Engineer | EnterpriseDB Software Solutions | Pune >>>> "Don't Complain about Heat, Plant a tree" >>>> >>> >>> >>> >>> -- >>> Thanks and Regards, >>> Aditya Toshniwal >>> Software Engineer | EnterpriseDB Software Solutions | Pune >>> "Don't Complain about Heat, Plant a tree" >>> >> >> >> >> -- >> Dave Page >> Blog: http://pgsnake.blogspot.com >> Twitter: @pgsnake >> >> EnterpriseDB UK: http://www.enterprisedb.com >> The Enterprise PostgreSQL Company >> > > > > -- > Thanks and Regards, > Aditya Toshniwal > Software Engineer | EnterpriseDB Software Solutions | Pune > "Don't Complain about Heat, Plant a tree" > -- Thanks and Regards, Aditya Toshniwal Software Engineer | EnterpriseDB Software Solutions | Pune "Don't Complain about Heat, Plant a tree" ^ permalink raw reply [nested|flat] 14+ messages in thread
* Re: [pgAdmin4][RM3294] User need to reset the layout to see the changed preferences parameters @ 2018-07-24 11:02 Dave Page <[email protected]> parent: Aditya Toshniwal <[email protected]> 1 sibling, 1 reply; 14+ messages in thread From: Dave Page @ 2018-07-24 11:02 UTC (permalink / raw) To: Aditya Toshniwal <[email protected]>; +Cc: Akshay Joshi <[email protected]>; pgadmin-hackers Hi On Tue, Jul 24, 2018 at 11:39 AM, Aditya Toshniwal < [email protected]> wrote: > Hi Hackers, > > Attached is the second part of the changes for making preferences > realtime. The patch includes dashboard and debugger modules. > All my dashboard graphs now seem to be straight lines. I'm guessing there's a bug somewhere, as I've never seen one PG server sustain it's I/O levels so perfectly, let alone the three I tested with :-) > I would also request to create RMs for javascript test cases for dashboard > and debugger modules as currently there is no setup for the test cases of > these two modules. > Please do. As well as that I'd also like to see a Python test to ensure that the invocation SQL for various different types of function/procedure is correct. We've messed that up a few times over the years. Thanks. The changes are on the JS side and so patch does not have any test cases > included. > > Kindly review. > > > On Thu, Jul 5, 2018 at 4:09 PM, Dave Page <[email protected]> wrote: > >> Thanks - patch applied! >> >> On Wed, Jul 4, 2018 at 10:19 AM, Aditya Toshniwal < >> [email protected]> wrote: >> >>> Hi Hackers, >>> >>> Attached is the updated patch for the RM. Change of the flags like auto >>> commit, explain->verbose, etc. will reflect in all other open sql editors. >>> Kindly review. >>> >>> On Fri, Jun 29, 2018 at 10:39 PM, Aditya Toshniwal < >>> [email protected]> wrote: >>> >>>> Hi Dave, >>>> >>>> On Fri, Jun 29, 2018 at 9:30 PM, Dave Page <[email protected]> wrote: >>>> >>>>> Hi >>>>> >>>>> On Fri, Jun 29, 2018 at 3:14 PM, Aditya Toshniwal < >>>>> [email protected]> wrote: >>>>> >>>>>> Hi Hackers, >>>>>> >>>>>> Attached is the updated patch. >>>>>> >>>>> >>>>> This seems to work for the most part, however I saw what seemed like >>>>> odd behaviour. If I have 2 query tool windows open; >>>>> >>>>> - Changing a preference from the Preferences dialogue updates both >>>>> query tools. >>>>> >>>>> - Changing a preference from a Query Tool updates the Preferences >>>>> dialogue. >>>>> >>>>> - Changing a preference from a Query Tool does *not* update the other >>>>> Query Tool. >>>>> >>>>> The last point seems odd to me, though it also kinda makes sense to >>>>> not have one query tool affect the other. The problem with that is that it >>>>> could get quite confusing when they get out of sync. I think it would be >>>>> better for a change in one Query Tool to update the other(s). >>>>> >>>>> What do you think? Was this behaviour intentional? >>>>> >>>> >>>> No this was not intentional. It should reflect in other query tools as >>>> well because changing the flags like Auto Commit changes the preferences >>>> config and is not local to a Query tool. I missed the fact that some >>>> preferences can be changed from other than preference dialog. >>>> >>>> Will send the updated patch with the fix. >>>> >>>>> >>>>> (FYI, in case this was a one-off bug, I was testing using "Auto >>>>> Commit?") >>>>> >>>>> >>>>>> >>>>>> On Fri, Jun 29, 2018 at 4:46 PM, Aditya Toshniwal < >>>>>> [email protected]> wrote: >>>>>> >>>>>>> Hi Akshay, >>>>>>> >>>>>>> On Fri, Jun 29, 2018 at 3:42 PM, Akshay Joshi < >>>>>>> [email protected]> wrote: >>>>>>> >>>>>>>> Hi Aditya >>>>>>>> >>>>>>>> I have applied your patch and run pgAdmin4. I have found following >>>>>>>> two issue in the browser: >>>>>>>> >>>>>>>> - Found error while open Preferences dialog. Refer >>>>>>>> Open_Preferences_Dialog.png >>>>>>>> >>>>>>>> This error occurs even with the latest pull without changes. >>>>>>> >>>>>>> >>>>>>>> >>>>>>>> - Set the preferences setting "Open in new browser tab" to True >>>>>>>> and open the query tool. Refer "Open_In_New_Broswer.png". >>>>>>>> >>>>>>>> Will look into this. >>>>>>> >>>>>>> >>>>>>>> I haven't review the code. >>>>>>>> >>>>>>>> On Thu, Jun 28, 2018 at 8:04 PM, Aditya Toshniwal < >>>>>>>> [email protected]> wrote: >>>>>>>> >>>>>>>>> Hi Hackers, >>>>>>>>> >>>>>>>>> Attached is the patch for making preferences realtime and applying >>>>>>>>> without reseting the layout. Please note, the patch is only for one module >>>>>>>>> - SQL Editor and is the first part for the RM. There are lot of changes to >>>>>>>>> be done to cover all and hence sending in parts. This will not affect/break >>>>>>>>> existing code. Further patches will cover other modules. >>>>>>>>> >>>>>>>>> Highlights of this patch include: >>>>>>>>> - Changes will affect SQL Editors in Create dialog boxes, SQL tab >>>>>>>>> of the main screen, Query tool, History entries in the query tool, Query >>>>>>>>> tool opened in New Tab/Window >>>>>>>>> - All the components of SQL editor will refer to single source of >>>>>>>>> preferences which is cached in the Browser object. All other redundant ajax >>>>>>>>> get preference calls are removed. >>>>>>>>> - SQL editor will not refer template JS variables anymore, once >>>>>>>>> all the references are removed the template variables will also be removed. >>>>>>>>> - Code refactoring wherever possible. >>>>>>>>> - Covered JS test cases wherever possible. >>>>>>>>> >>>>>>>>> Request you to kindly review. >>>>>>>>> >>>>>>>>> -- >>>>>>>>> Thanks and Regards, >>>>>>>>> Aditya Toshniwal >>>>>>>>> Software Engineer | EnterpriseDB Software Solutions | Pune >>>>>>>>> "Don't Complain about Heat, Plant a tree" >>>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> -- >>>>>>>> *Akshay Joshi* >>>>>>>> >>>>>>>> *Sr. Software Architect * >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> *Phone: +91 20-3058-9517Mobile: +91 976-788-8246* >>>>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>>>> -- >>>>>>> Thanks and Regards, >>>>>>> Aditya Toshniwal >>>>>>> Software Engineer | EnterpriseDB Software Solutions | Pune >>>>>>> "Don't Complain about Heat, Plant a tree" >>>>>>> >>>>>> >>>>>> >>>>>> >>>>>> -- >>>>>> Thanks and Regards, >>>>>> Aditya Toshniwal >>>>>> Software Engineer | EnterpriseDB Software Solutions | Pune >>>>>> "Don't Complain about Heat, Plant a tree" >>>>>> >>>>> >>>>> >>>>> >>>>> -- >>>>> Dave Page >>>>> Blog: http://pgsnake.blogspot.com >>>>> Twitter: @pgsnake >>>>> >>>>> EnterpriseDB UK: http://www.enterprisedb.com >>>>> The Enterprise PostgreSQL Company >>>>> >>>> >>>> >>>> >>>> -- >>>> Thanks and Regards, >>>> Aditya Toshniwal >>>> Software Engineer | EnterpriseDB Software Solutions | Pune >>>> "Don't Complain about Heat, Plant a tree" >>>> >>> >>> >>> >>> -- >>> Thanks and Regards, >>> Aditya Toshniwal >>> Software Engineer | EnterpriseDB Software Solutions | Pune >>> "Don't Complain about Heat, Plant a tree" >>> >> >> >> >> -- >> Dave Page >> Blog: http://pgsnake.blogspot.com >> Twitter: @pgsnake >> >> EnterpriseDB UK: http://www.enterprisedb.com >> The Enterprise PostgreSQL Company >> > > > > -- > Thanks and Regards, > Aditya Toshniwal > Software Engineer | EnterpriseDB Software Solutions | Pune > "Don't Complain about Heat, Plant a tree" > -- Dave Page Blog: http://pgsnake.blogspot.com Twitter: @pgsnake EnterpriseDB UK: http://www.enterprisedb.com The Enterprise PostgreSQL Company ^ permalink raw reply [nested|flat] 14+ messages in thread
* Re: [pgAdmin4][RM3294] User need to reset the layout to see the changed preferences parameters @ 2018-07-24 13:11 Aditya Toshniwal <[email protected]> parent: Dave Page <[email protected]> 0 siblings, 1 reply; 14+ messages in thread From: Aditya Toshniwal @ 2018-07-24 13:11 UTC (permalink / raw) To: Dave Page <[email protected]>; +Cc: Akshay Joshi <[email protected]>; pgadmin-hackers Hi, Attached is the updated patch. On Tue, Jul 24, 2018 at 4:32 PM, Dave Page <[email protected]> wrote: > Hi > > On Tue, Jul 24, 2018 at 11:39 AM, Aditya Toshniwal <aditya.toshniwal@ > enterprisedb.com> wrote: > >> Hi Hackers, >> >> Attached is the second part of the changes for making preferences >> realtime. The patch includes dashboard and debugger modules. >> > > All my dashboard graphs now seem to be straight lines. I'm guessing > there's a bug somewhere, as I've never seen one PG server sustain it's I/O > levels so perfectly, let alone the three I tested with :-) > Fixed. :P > > >> I would also request to create RMs for javascript test cases for >> dashboard and debugger modules as currently there is no setup for the test >> cases of these two modules. >> > > Please do. As well as that I'd also like to see a Python test to ensure > that the invocation SQL for various different types of function/procedure > is correct. We've messed that up a few times over the years. > > Thanks. > > The changes are on the JS side and so patch does not have any test cases >> included. >> > >> Kindly review. >> >> >> On Thu, Jul 5, 2018 at 4:09 PM, Dave Page <[email protected]> wrote: >> >>> Thanks - patch applied! >>> >>> On Wed, Jul 4, 2018 at 10:19 AM, Aditya Toshniwal < >>> [email protected]> wrote: >>> >>>> Hi Hackers, >>>> >>>> Attached is the updated patch for the RM. Change of the flags like auto >>>> commit, explain->verbose, etc. will reflect in all other open sql editors. >>>> Kindly review. >>>> >>>> On Fri, Jun 29, 2018 at 10:39 PM, Aditya Toshniwal < >>>> [email protected]> wrote: >>>> >>>>> Hi Dave, >>>>> >>>>> On Fri, Jun 29, 2018 at 9:30 PM, Dave Page <[email protected]> wrote: >>>>> >>>>>> Hi >>>>>> >>>>>> On Fri, Jun 29, 2018 at 3:14 PM, Aditya Toshniwal < >>>>>> [email protected]> wrote: >>>>>> >>>>>>> Hi Hackers, >>>>>>> >>>>>>> Attached is the updated patch. >>>>>>> >>>>>> >>>>>> This seems to work for the most part, however I saw what seemed like >>>>>> odd behaviour. If I have 2 query tool windows open; >>>>>> >>>>>> - Changing a preference from the Preferences dialogue updates both >>>>>> query tools. >>>>>> >>>>>> - Changing a preference from a Query Tool updates the Preferences >>>>>> dialogue. >>>>>> >>>>>> - Changing a preference from a Query Tool does *not* update the other >>>>>> Query Tool. >>>>>> >>>>>> The last point seems odd to me, though it also kinda makes sense to >>>>>> not have one query tool affect the other. The problem with that is that it >>>>>> could get quite confusing when they get out of sync. I think it would be >>>>>> better for a change in one Query Tool to update the other(s). >>>>>> >>>>>> What do you think? Was this behaviour intentional? >>>>>> >>>>> >>>>> No this was not intentional. It should reflect in other query tools >>>>> as well because changing the flags like Auto Commit changes the preferences >>>>> config and is not local to a Query tool. I missed the fact that some >>>>> preferences can be changed from other than preference dialog. >>>>> >>>>> Will send the updated patch with the fix. >>>>> >>>>>> >>>>>> (FYI, in case this was a one-off bug, I was testing using "Auto >>>>>> Commit?") >>>>>> >>>>>> >>>>>>> >>>>>>> On Fri, Jun 29, 2018 at 4:46 PM, Aditya Toshniwal < >>>>>>> [email protected]> wrote: >>>>>>> >>>>>>>> Hi Akshay, >>>>>>>> >>>>>>>> On Fri, Jun 29, 2018 at 3:42 PM, Akshay Joshi < >>>>>>>> [email protected]> wrote: >>>>>>>> >>>>>>>>> Hi Aditya >>>>>>>>> >>>>>>>>> I have applied your patch and run pgAdmin4. I have found following >>>>>>>>> two issue in the browser: >>>>>>>>> >>>>>>>>> - Found error while open Preferences dialog. Refer >>>>>>>>> Open_Preferences_Dialog.png >>>>>>>>> >>>>>>>>> This error occurs even with the latest pull without changes. >>>>>>>> >>>>>>>> >>>>>>>>> >>>>>>>>> - Set the preferences setting "Open in new browser tab" to >>>>>>>>> True and open the query tool. Refer "Open_In_New_Broswer.png". >>>>>>>>> >>>>>>>>> Will look into this. >>>>>>>> >>>>>>>> >>>>>>>>> I haven't review the code. >>>>>>>>> >>>>>>>>> On Thu, Jun 28, 2018 at 8:04 PM, Aditya Toshniwal < >>>>>>>>> [email protected]> wrote: >>>>>>>>> >>>>>>>>>> Hi Hackers, >>>>>>>>>> >>>>>>>>>> Attached is the patch for making preferences realtime and >>>>>>>>>> applying without reseting the layout. Please note, the patch is only for >>>>>>>>>> one module - SQL Editor and is the first part for the RM. There are lot of >>>>>>>>>> changes to be done to cover all and hence sending in parts. This will not >>>>>>>>>> affect/break existing code. Further patches will cover other modules. >>>>>>>>>> >>>>>>>>>> Highlights of this patch include: >>>>>>>>>> - Changes will affect SQL Editors in Create dialog boxes, SQL tab >>>>>>>>>> of the main screen, Query tool, History entries in the query tool, Query >>>>>>>>>> tool opened in New Tab/Window >>>>>>>>>> - All the components of SQL editor will refer to single source of >>>>>>>>>> preferences which is cached in the Browser object. All other redundant ajax >>>>>>>>>> get preference calls are removed. >>>>>>>>>> - SQL editor will not refer template JS variables anymore, once >>>>>>>>>> all the references are removed the template variables will also be removed. >>>>>>>>>> - Code refactoring wherever possible. >>>>>>>>>> - Covered JS test cases wherever possible. >>>>>>>>>> >>>>>>>>>> Request you to kindly review. >>>>>>>>>> >>>>>>>>>> -- >>>>>>>>>> Thanks and Regards, >>>>>>>>>> Aditya Toshniwal >>>>>>>>>> Software Engineer | EnterpriseDB Software Solutions | Pune >>>>>>>>>> "Don't Complain about Heat, Plant a tree" >>>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> -- >>>>>>>>> *Akshay Joshi* >>>>>>>>> >>>>>>>>> *Sr. Software Architect * >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> *Phone: +91 20-3058-9517Mobile: +91 976-788-8246* >>>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> -- >>>>>>>> Thanks and Regards, >>>>>>>> Aditya Toshniwal >>>>>>>> Software Engineer | EnterpriseDB Software Solutions | Pune >>>>>>>> "Don't Complain about Heat, Plant a tree" >>>>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>>>> -- >>>>>>> Thanks and Regards, >>>>>>> Aditya Toshniwal >>>>>>> Software Engineer | EnterpriseDB Software Solutions | Pune >>>>>>> "Don't Complain about Heat, Plant a tree" >>>>>>> >>>>>> >>>>>> >>>>>> >>>>>> -- >>>>>> Dave Page >>>>>> Blog: http://pgsnake.blogspot.com >>>>>> Twitter: @pgsnake >>>>>> >>>>>> EnterpriseDB UK: http://www.enterprisedb.com >>>>>> The Enterprise PostgreSQL Company >>>>>> >>>>> >>>>> >>>>> >>>>> -- >>>>> Thanks and Regards, >>>>> Aditya Toshniwal >>>>> Software Engineer | EnterpriseDB Software Solutions | Pune >>>>> "Don't Complain about Heat, Plant a tree" >>>>> >>>> >>>> >>>> >>>> -- >>>> Thanks and Regards, >>>> Aditya Toshniwal >>>> Software Engineer | EnterpriseDB Software Solutions | Pune >>>> "Don't Complain about Heat, Plant a tree" >>>> >>> >>> >>> >>> -- >>> Dave Page >>> Blog: http://pgsnake.blogspot.com >>> Twitter: @pgsnake >>> >>> EnterpriseDB UK: http://www.enterprisedb.com >>> The Enterprise PostgreSQL Company >>> >> >> >> >> -- >> Thanks and Regards, >> Aditya Toshniwal >> Software Engineer | EnterpriseDB Software Solutions | Pune >> "Don't Complain about Heat, Plant a tree" >> > > > > -- > Dave Page > Blog: http://pgsnake.blogspot.com > Twitter: @pgsnake > > EnterpriseDB UK: http://www.enterprisedb.com > The Enterprise PostgreSQL Company > -- Thanks and Regards, Aditya Toshniwal Software Engineer | EnterpriseDB Software Solutions | Pune "Don't Complain about Heat, Plant a tree" Attachments: [application/octet-stream] 0002-RM3294.patch (82.6K, 3-0002-RM3294.patch) download | inline diff: diff --git a/web/pgadmin/browser/static/js/panel.js b/web/pgadmin/browser/static/js/panel.js index ab0681a9..5238dcee 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 91162f76..ffd4a7bc 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 2fc7897c..61174f33 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 02c7d439..c411a84a 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 - ) { - - // 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; - } + renderChartLoop: function(container, sid, did, url, options, counter, refresh) { + var data = [], + dataset = []; - // 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( '<div class="alert alert-' + cls + ' pg-panel-message" role="alert">' + msg + '</div>' ); - - // 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); + }, + + // 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] } + // ] - setTimeout(setTimeoutFunc, refresh * 1000); + 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 37ff5b97..26cde01a 100644 --- a/web/pgadmin/dashboard/templates/dashboard/database_dashboard.html +++ b/web/pgadmin/dashboard/templates/dashboard/database_dashboard.html @@ -1,135 +1,110 @@ <div class="dashboard-container"> -{% if settings.show_graphs %} - <div class="row"> - <div class="col-xs-6"> - <div class="obj_properties"> - <legend class="badge">{{ _('Database sessions') }}</legend> + <div id="dashboard-graphs" class="dashboard-hidden"> + <div class="row"> + <div class="col-xs-6"> + <div class="obj_properties"> + <legend class="badge">{{ _('Database sessions') }}</legend> + </div> </div> - </div> - <div class="col-xs-6"> - <div class="obj_properties"> - <legend class="badge">{{ _('Transactions per second') }}</legend> + <div class="col-xs-6"> + <div class="obj_properties"> + <legend class="badge">{{ _('Transactions per second') }}</legend> + </div> </div> </div> - </div> - <div class="row"> - <div class="col-xs-6"> - <div id="graph-sessions" class="graph-container"></div> - </div> - <div class="col-xs-6"> - <div id="graph-tps" class="graph-container"></div> + <div class="row dashboard-row"> + <div class="col-xs-6"> + <div id="graph-sessions" class="graph-container"></div> + </div> + <div class="col-xs-6"> + <div id="graph-tps" class="graph-container"></div> + </div> </div> - </div> - <div class="row dashboard-header-spacer"> - <div class="col-xs-4"> - <div class="obj_properties"> - <legend class="badge">{{ _('Tuples in') }}</legend> + <div class="row"> + <div class="col-xs-4"> + <div class="obj_properties"> + <legend class="badge">{{ _('Tuples in') }}</legend> + </div> </div> - </div> - <div class="col-xs-4"> - <div class="obj_properties"> - <legend class="badge">{{ _('Tuples out') }}</legend> + <div class="col-xs-4"> + <div class="obj_properties"> + <legend class="badge">{{ _('Tuples out') }}</legend> + </div> </div> - </div> - <div class="col-xs-4"> - <div class="obj_properties"> - <legend class="badge">{{ _('Block I/O') }}</legend> + <div class="col-xs-4"> + <div class="obj_properties"> + <legend class="badge">{{ _('Block I/O') }}</legend> + </div> </div> </div> - </div> - <div class="row"> - <div class="col-xs-4"> - <div id="graph-ti" class="graph-container"></div> - </div> - <div class="col-xs-4"> - <div id="graph-to" class="graph-container"></div> - </div> - <div class="col-xs-4"> - <div id="graph-bio" class="graph-container"></div> + <div class="row dashboard-row"> + <div class="col-xs-4"> + <div id="graph-ti" class="graph-container"></div> + </div> + <div class="col-xs-4"> + <div id="graph-to" class="graph-container"></div> + </div> + <div class="col-xs-4"> + <div id="graph-bio" class="graph-container"></div> + </div> </div> </div> -{% endif %} -{% if settings.show_activity %} - {# If we are displaying graphs then only we need space on top #} - {% if settings.show_graphs %} - <div class="row dashboard-header-spacer"> - {% else %} - <div class="row"> - {% endif %} - <div class="col-xs-12"> - <div class="obj_properties"> - <legend class="badge">{{ _('Database activity') }}</legend> + <div id="dashboard-activity" class="dashboard-hidden"> + <div class="row"> + <div class="col-xs-12"> + <div class="obj_properties"> + <legend class="badge">{{ _('Database activity') }}</legend> + </div> </div> </div> - </div> - <div class="row"> - <div class="col-xs-12"> - <div class="dashboard-tab-container"> - <!-- Nav tabs --> - <ul class="nav nav-tabs dashboard-tab-panel" role="tablist"> - <li role="presentation" class="active dashboard-tab"><a href="#tab_panel_database_activity" - aria-controls="tab_database_activity" - role="tab" data-toggle="tab">{{ _('Sessions') }}</a> - </li> - <li role="presentation" class="dashboard-tab"><a href="#tab_panel_database_locks" - aria-controls="tab_database_locks" role="tab" - data-toggle="tab">{{ _('Locks') }}</a></li> - <li role="presentation" class="dashboard-tab"><a href="#tab_panel_database_prepared" - aria-controls="tab_database_prepared" role="tab" - data-toggle="tab">{{ _('Prepared Transactions') }}</a></li> - </ul> + <div class="row dashboard-row"> + <div class="col-xs-12"> + <div class="dashboard-tab-container"> + <!-- Nav tabs --> + <ul class="nav nav-tabs dashboard-tab-panel" role="tablist"> + <li role="presentation" class="active dashboard-tab"><a href="#tab_panel_database_activity" + aria-controls="tab_database_activity" + role="tab" data-toggle="tab">{{ _('Sessions') }}</a> + </li> + <li role="presentation" class="dashboard-tab"><a href="#tab_panel_database_locks" + aria-controls="tab_database_locks" role="tab" + data-toggle="tab">{{ _('Locks') }}</a></li> + <li role="presentation" class="dashboard-tab"><a href="#tab_panel_database_prepared" + aria-controls="tab_database_prepared" role="tab" + data-toggle="tab">{{ _('Prepared Transactions') }}</a></li> + </ul> - <!-- Tab panes --> - <div class="tab-content"> - <div role="tabpanel" class="tab-pane active" id="tab_panel_database_activity"> - <div class="dashboard-tab-btn-group pg-prop-btn-group-above"> - <button id="btn_database_activity_refresh" type="button" class="btn btn-default" title="{{ _('Refresh') }}"> <span class="fa fa-lg fa-refresh"></span></button> - <div id="database_activity_filter"></div> + <!-- Tab panes --> + <div class="tab-content"> + <div role="tabpanel" class="tab-pane active" id="tab_panel_database_activity"> + <div class="dashboard-tab-btn-group pg-prop-btn-group-above"> + <button id="btn_database_activity_refresh" type="button" class="btn btn-default" title="{{ _('Refresh') }}"> <span class="fa fa-lg fa-refresh"></span></button> + <div id="database_activity_filter"></div> + </div> + <div id="database_activity" class="grid-container"></div> </div> - <div id="database_activity" class="grid-container"></div> - </div> - <div role="tabpanel" class="tab-pane" id="tab_panel_database_locks"> - <div class="dashboard-tab-btn-group pg-prop-btn-group-above"> - <button id="btn_database_locks_refresh" type="button" class="btn btn-default" title="{{ _('Refresh') }}"> <span class="fa fa-lg fa-refresh"></span></button> - <div id="database_locks_filter"></div> + <div role="tabpanel" class="tab-pane" id="tab_panel_database_locks"> + <div class="dashboard-tab-btn-group pg-prop-btn-group-above"> + <button id="btn_database_locks_refresh" type="button" class="btn btn-default" title="{{ _('Refresh') }}"> <span class="fa fa-lg fa-refresh"></span></button> + <div id="database_locks_filter"></div> + </div> + <div id="database_locks" class="grid-container"></div> </div> - <div id="database_locks" class="grid-container"></div> - </div> - <div role="tabpanel" class="tab-pane" id="tab_panel_database_prepared"> - <div class="dashboard-tab-btn-group pg-prop-btn-group-above"> - <button id="btn_database_prepared_refresh" type="button" class="btn btn-default" title="{{ _('Refresh') }}"> <span class="fa fa-lg fa-refresh"></span></button> - <div id="database_prepared_filter"></div> + <div role="tabpanel" class="tab-pane" id="tab_panel_database_prepared"> + <div class="dashboard-tab-btn-group pg-prop-btn-group-above"> + <button id="btn_database_prepared_refresh" type="button" class="btn btn-default" title="{{ _('Refresh') }}"> <span class="fa fa-lg fa-refresh"></span></button> + <div id="database_prepared_filter"></div> + </div> + <div id="database_prepared" class="grid-container"></div> </div> - <div id="database_prepared" class="grid-container"></div> </div> </div> </div> </div> </div> -{% endif %} - -{% if not settings.show_graphs and not settings.show_activity %} - <div class="alert alert-info pg-panel-message" role="alert"> + <div id="dashboard-none-show" class="alert alert-info pg-panel-message dashboard-hidden" role="alert"> {{ _('All Dashboard elements are currently disabled.') }} </div> -{% endif %} - </div> - -<script type="text/javascript"> - // Initiate database dashboard - pgAdmin.Dashboard.init_database_dashboard( - {{ sid }}, - {{ did }}, - {{ version }}, - {{ rates.session_stats_refresh }}, - {{ rates.tps_stats_refresh }}, - {{ rates.ti_stats_refresh }}, - {{ rates.to_stats_refresh }}, - {{ rates.bio_stats_refresh }}, - {{ settings.show_graphs|lower }}, - {{ settings.show_activity|lower }} - ); -</script> diff --git a/web/pgadmin/dashboard/templates/dashboard/server_dashboard.html b/web/pgadmin/dashboard/templates/dashboard/server_dashboard.html index b3578253..5a4df66a 100644 --- a/web/pgadmin/dashboard/templates/dashboard/server_dashboard.html +++ b/web/pgadmin/dashboard/templates/dashboard/server_dashboard.html @@ -1,144 +1,120 @@ <div class="dashboard-container"> -{% if settings.show_graphs %} - <div class="row"> - <div class="col-xs-6"> - <div class="obj_properties"> - <legend class="badge">{{ _('Server sessions') }}</legend> + <div id="dashboard-graphs" class="dashboard-hidden"> + <div class="row"> + <div class="col-xs-6"> + <div class="obj_properties"> + <legend class="badge">{{ _('Server sessions') }}</legend> + </div> </div> - </div> - <div class="col-xs-6"> - <div class="obj_properties"> - <legend class="badge">{{ _('Transactions per second') }}</legend> + <div class="col-xs-6"> + <div class="obj_properties"> + <legend class="badge">{{ _('Transactions per second') }}</legend> + </div> </div> </div> - </div> - <div class="row"> - <div class="col-xs-6"> - <div id="graph-sessions" class="graph-container"></div> - </div> - <div class="col-xs-6"> - <div id="graph-tps" class="graph-container"></div> + <div class="row dashboard-row"> + <div class="col-xs-6"> + <div id="graph-sessions" class="graph-container"></div> + </div> + <div class="col-xs-6"> + <div id="graph-tps" class="graph-container"></div> + </div> </div> - </div> - <div class="row dashboard-header-spacer"> - <div class="col-xs-4"> - <div class="obj_properties"> - <legend class="badge">{{ _('Tuples in') }}</legend> + <div class="row"> + <div class="col-xs-4"> + <div class="obj_properties"> + <legend class="badge">{{ _('Tuples in') }}</legend> + </div> </div> - </div> - <div class="col-xs-4"> - <div class="obj_properties"> - <legend class="badge">{{ _('Tuples out') }}</legend> + <div class="col-xs-4"> + <div class="obj_properties"> + <legend class="badge">{{ _('Tuples out') }}</legend> + </div> </div> - </div> - <div class="col-xs-4"> - <div class="obj_properties"> - <legend class="badge">{{ _('Block I/O') }}</legend> + <div class="col-xs-4"> + <div class="obj_properties"> + <legend class="badge">{{ _('Block I/O') }}</legend> + </div> </div> </div> - </div> - <div class="row"> - <div class="col-xs-4"> - <div id="graph-ti" class="graph-container"></div> - </div> - <div class="col-xs-4"> - <div id="graph-to" class="graph-container"></div> - </div> - <div class="col-xs-4"> - <div id="graph-bio" class="graph-container"></div> + <div class="row dashboard-row"> + <div class="col-xs-4"> + <div id="graph-ti" class="graph-container"></div> + </div> + <div class="col-xs-4"> + <div id="graph-to" class="graph-container"></div> + </div> + <div class="col-xs-4"> + <div id="graph-bio" class="graph-container"></div> + </div> </div> </div> -{% endif %} -{% if settings.show_activity %} - {# If we are displaying graphs then only we need space on top #} - {% if settings.show_graphs %} - <div class="row dashboard-header-spacer"> - {% else %} - <div class="row"> - {% endif %} - <div class="col-xs-12"> - <div class="obj_properties"> - <legend class="badge">{{ _('Server activity') }}</legend> + <div id="dashboard-activity" class="dashboard-hidden"> + <div class="row"> + <div class="col-xs-12"> + <div class="obj_properties"> + <legend class="badge">{{ _('Server activity') }}</legend> + </div> </div> </div> - </div> - <div class="row"> - <div class="col-xs-12"> - <div class="dashboard-tab-container"> - <!-- Nav tabs --> - <ul class="nav nav-tabs dashboard-tab-panel" role="tablist"> - <li role="presentation" class="active dashboard-tab"><a href="#tab_panel_server_activity" - aria-controls="tab_server_activity" - role="tab" data-toggle="tab">{{ _('Sessions') }}</a> - </li> - <li role="presentation" class="dashboard-tab"><a href="#tab_panel_server_locks" - aria-controls="tab_server_locks" role="tab" - data-toggle="tab">{{ _('Locks') }}</a></li> - <li role="presentation" class="dashboard-tab"><a href="#tab_panel_server_prepared" - aria-controls="tab_server_prepared" role="tab" - data-toggle="tab">{{ _('Prepared Transactions') }}</a></li> - <li role="presentation" class="dashboard-tab"><a href="#tab_panel_server_config" - aria-controls="tab_server_config" role="tab" - data-toggle="tab">{{ _('Configuration') }}</a></li> - </ul> + <div class="row dashboard-row"> + <div class="col-xs-12"> + <div class="dashboard-tab-container"> + <!-- Nav tabs --> + <ul class="nav nav-tabs dashboard-tab-panel" role="tablist"> + <li role="presentation" class="active dashboard-tab"><a href="#tab_panel_server_activity" + aria-controls="tab_server_activity" + role="tab" data-toggle="tab">{{ _('Sessions') }}</a> + </li> + <li role="presentation" class="dashboard-tab"><a href="#tab_panel_server_locks" + aria-controls="tab_server_locks" role="tab" + data-toggle="tab">{{ _('Locks') }}</a></li> + <li role="presentation" class="dashboard-tab"><a href="#tab_panel_server_prepared" + aria-controls="tab_server_prepared" role="tab" + data-toggle="tab">{{ _('Prepared Transactions') }}</a></li> + <li role="presentation" class="dashboard-tab"><a href="#tab_panel_server_config" + aria-controls="tab_server_config" role="tab" + data-toggle="tab">{{ _('Configuration') }}</a></li> + </ul> - <!-- Tab panes --> - <div class="tab-content"> - <div role="tabpanel" class="tab-pane active" id="tab_panel_server_activity"> - <div class="dashboard-tab-btn-group pg-prop-btn-group-above"> - <button id="btn_server_activity_refresh" type="button" class="btn btn-default" title="{{ _('Refresh') }}"> <span class="fa fa-lg fa-refresh"></span></button> - <div id="server_activity_filter"></div> + <!-- Tab panes --> + <div class="tab-content"> + <div role="tabpanel" class="tab-pane active" id="tab_panel_server_activity"> + <div class="dashboard-tab-btn-group pg-prop-btn-group-above"> + <button id="btn_server_activity_refresh" type="button" class="btn btn-default" title="{{ _('Refresh') }}"> <span class="fa fa-lg fa-refresh"></span></button> + <div id="server_activity_filter"></div> + </div> + <div id="server_activity" class="grid-container"></div> </div> - <div id="server_activity" class="grid-container"></div> - </div> - <div role="tabpanel" class="tab-pane" id="tab_panel_server_locks"> - <div class="dashboard-tab-btn-group pg-prop-btn-group-above"> - <button id="btn_server_locks_refresh" type="button" class="btn btn-default" title="{{ _('Refresh') }}"> <span class="fa fa-lg fa-refresh"></span></button> - <div id="server_locks_filter"></div> + <div role="tabpanel" class="tab-pane" id="tab_panel_server_locks"> + <div class="dashboard-tab-btn-group pg-prop-btn-group-above"> + <button id="btn_server_locks_refresh" type="button" class="btn btn-default" title="{{ _('Refresh') }}"> <span class="fa fa-lg fa-refresh"></span></button> + <div id="server_locks_filter"></div> + </div> + <div id="server_locks" class="grid-container"></div> </div> - <div id="server_locks" class="grid-container"></div> - </div> - <div role="tabpanel" class="tab-pane" id="tab_panel_server_prepared"> - <div class="dashboard-tab-btn-group pg-prop-btn-group-above"> - <button id="btn_server_prepared_refresh" type="button" class="btn btn-default" title="{{ _('Refresh') }}"> <span class="fa fa-lg fa-refresh"></span></button> - <div id="server_prepared_filter"></div> + <div role="tabpanel" class="tab-pane" id="tab_panel_server_prepared"> + <div class="dashboard-tab-btn-group pg-prop-btn-group-above"> + <button id="btn_server_prepared_refresh" type="button" class="btn btn-default" title="{{ _('Refresh') }}"> <span class="fa fa-lg fa-refresh"></span></button> + <div id="server_prepared_filter"></div> + </div> + <div id="server_prepared" class="grid-container"></div> </div> - <div id="server_prepared" class="grid-container"></div> - </div> - <div role="tabpanel" class="tab-pane" id="tab_panel_server_config"> - <div class="dashboard-tab-btn-group pg-prop-btn-group-above"> - <button id="btn_server_config_refresh" type="button" class="btn btn-default" title="{{ _('Refresh') }}"> <span class="fa fa-lg fa-refresh"></span></button> - <div id="server_config_filter"></div> + <div role="tabpanel" class="tab-pane" id="tab_panel_server_config"> + <div class="dashboard-tab-btn-group pg-prop-btn-group-above"> + <button id="btn_server_config_refresh" type="button" class="btn btn-default" title="{{ _('Refresh') }}"> <span class="fa fa-lg fa-refresh"></span></button> + <div id="server_config_filter"></div> + </div> + <div id="server_config" class="grid-container"></div> </div> - <div id="server_config" class="grid-container"></div> </div> </div> </div> </div> </div> -{% endif %} - -{% if not settings.show_graphs and not settings.show_activity %} - <div class="alert alert-info pg-panel-message" role="alert"> - {{ _('Dashboard has been disabled by user.') }} + <div id="dashboard-none-show" class="alert alert-info pg-panel-message dashboard-hidden" role="alert"> + {{ _('All Dashboard elements are currently disabled.') }} </div> -{% endif %} - </div> - -<script type="text/javascript"> - // Initiate server dashboard - pgAdmin.Dashboard.init_server_dashboard( - {{ sid }}, - {{ version }}, - {{ rates.session_stats_refresh }}, - {{ rates.tps_stats_refresh }}, - {{ rates.ti_stats_refresh }}, - {{ rates.to_stats_refresh }}, - {{ rates.bio_stats_refresh }}, - {{ settings.show_graphs|lower }}, - {{ settings.show_activity|lower }} - ); -</script> 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 dd24bddc..00000000 --- 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 232f67fd..667129dd 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 f24942d7..4479f85c 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/<node_type>/<int:sid>/<int:did>/<int:scid>/<int:fid>', 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 d632343e..39caca71 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 bc1aff11..35a6970e 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 58d97a06..08412698 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;} </style> {% endif %} -<div class="dubugger_main_container" tabindex="0"> +<div class="debugger_main_container" tabindex="0"> <nav class="navbar-inverse navbar-fixed-top"> <div id="btn-toolbar" class="btn-toolbar pg-prop-btn-group bg-gray-2 border-gray-3" role="toolbar" aria-label=""> <div class="btn-group" role="group" aria-label=""> - <button type="button" class="btn btn-default btn-step-into" - title="{{ _('Step into') }}{{ _(' (accesskey+{0})'.format(accesskey.step_into)) }}" - accesskey="{{ accesskey.step_into }}" + <button type="button" class="btn btn-default btn-step-into" id="btn-step-into" + title="" + accesskey="" tabindex="0" autofocus="autofocus"> <i class="fa fa-indent"></i> </button> - <button type="button" class="btn btn-default btn-step-over" - title="{{ _('Step over') }}{{ _(' (accesskey+{0})'.format(accesskey.step_over)) }}" - accesskey="{{ accesskey.step_over }}" + <button type="button" class="btn btn-default btn-step-over" id="btn-step-over" + title="" + accesskey="" tabindex="0"> <i class="fa fa-outdent"></i> </button> - <button type="button" class="btn btn-default btn-continue" - title="{{ _('Continue/Start') }}{{ _(' (accesskey+{0})'.format(accesskey.start)) }}" - accesskey="{{ accesskey.start }}" + <button type="button" class="btn btn-default btn-continue" id="btn-continue" + title="" + accesskey="" tabindex="0"> <i class="fa fa-play-circle"></i> </button> </div> <div class="btn-group" role="group" aria-label=""> - <button type="button" class="btn btn-default btn-toggle-breakpoint" - title="{{ _('Toggle breakpoint') }}{{ _(' (accesskey+{0})'.format(accesskey.toggle_breakpoint)) }}" - accesskey="{{ accesskey.toggle_breakpoint }}" + <button type="button" class="btn btn-default btn-toggle-breakpoint" id="btn-toggle-breakpoint" + title="" + accesskey="" tabindex="0"> <i class="fa fa-circle"></i> </button> - <button type="button" class="btn btn-default btn-clear-breakpoint" - title="{{ _('Clear all breakpoints') }}{{ _(' (accesskey+{0})'.format(accesskey.clear_breakpoints)) }}" - accesskey="{{ accesskey.clear_breakpoints }}" + <button type="button" class="btn btn-default btn-clear-breakpoint" id="btn-clear-breakpoint" + title="" + accesskey="" tabindex="0"> <i class="fa fa-ban"></i> </button> </div> <div class="btn-group" role="group" aria-label=""> - <button type="button" class="btn btn-default btn-stop" - accesskey="{{ accesskey.stop }}" - title="{{ _('Stop') }}{{ _(' (accesskey+{0})'.format(accesskey.stop)) }}" + <button type="button" class="btn btn-default btn-stop" id="btn-stop" + accesskey="" + title="" tabindex="0"> <i class="fa fa-stop-circle"></i> </button> ^ permalink raw reply [nested|flat] 14+ messages in thread
* Re: [pgAdmin4][RM3294] User need to reset the layout to see the changed preferences parameters @ 2018-07-24 15:31 Dave Page <[email protected]> parent: Aditya Toshniwal <[email protected]> 0 siblings, 1 reply; 14+ messages in thread From: Dave Page @ 2018-07-24 15:31 UTC (permalink / raw) To: Aditya Toshniwal <[email protected]>; +Cc: Akshay Joshi <[email protected]>; pgadmin-hackers Thanks, applied. On Tue, Jul 24, 2018 at 2:11 PM, Aditya Toshniwal < [email protected]> wrote: > Hi, > > Attached is the updated patch. > > On Tue, Jul 24, 2018 at 4:32 PM, Dave Page <[email protected]> wrote: > >> Hi >> >> On Tue, Jul 24, 2018 at 11:39 AM, Aditya Toshniwal < >> [email protected]> wrote: >> >>> Hi Hackers, >>> >>> Attached is the second part of the changes for making preferences >>> realtime. The patch includes dashboard and debugger modules. >>> >> >> All my dashboard graphs now seem to be straight lines. I'm guessing >> there's a bug somewhere, as I've never seen one PG server sustain it's I/O >> levels so perfectly, let alone the three I tested with :-) >> > Fixed. :P > > >> >> >>> I would also request to create RMs for javascript test cases for >>> dashboard and debugger modules as currently there is no setup for the test >>> cases of these two modules. >>> >> >> Please do. As well as that I'd also like to see a Python test to ensure >> that the invocation SQL for various different types of function/procedure >> is correct. We've messed that up a few times over the years. >> >> Thanks. >> >> The changes are on the JS side and so patch does not have any test cases >>> included. >>> >> >>> Kindly review. >>> >>> >>> On Thu, Jul 5, 2018 at 4:09 PM, Dave Page <[email protected]> wrote: >>> >>>> Thanks - patch applied! >>>> >>>> On Wed, Jul 4, 2018 at 10:19 AM, Aditya Toshniwal < >>>> [email protected]> wrote: >>>> >>>>> Hi Hackers, >>>>> >>>>> Attached is the updated patch for the RM. Change of the flags like >>>>> auto commit, explain->verbose, etc. will reflect in all other open sql >>>>> editors. >>>>> Kindly review. >>>>> >>>>> On Fri, Jun 29, 2018 at 10:39 PM, Aditya Toshniwal < >>>>> [email protected]> wrote: >>>>> >>>>>> Hi Dave, >>>>>> >>>>>> On Fri, Jun 29, 2018 at 9:30 PM, Dave Page <[email protected]> wrote: >>>>>> >>>>>>> Hi >>>>>>> >>>>>>> On Fri, Jun 29, 2018 at 3:14 PM, Aditya Toshniwal < >>>>>>> [email protected]> wrote: >>>>>>> >>>>>>>> Hi Hackers, >>>>>>>> >>>>>>>> Attached is the updated patch. >>>>>>>> >>>>>>> >>>>>>> This seems to work for the most part, however I saw what seemed like >>>>>>> odd behaviour. If I have 2 query tool windows open; >>>>>>> >>>>>>> - Changing a preference from the Preferences dialogue updates both >>>>>>> query tools. >>>>>>> >>>>>>> - Changing a preference from a Query Tool updates the Preferences >>>>>>> dialogue. >>>>>>> >>>>>>> - Changing a preference from a Query Tool does *not* update the >>>>>>> other Query Tool. >>>>>>> >>>>>>> The last point seems odd to me, though it also kinda makes sense to >>>>>>> not have one query tool affect the other. The problem with that is that it >>>>>>> could get quite confusing when they get out of sync. I think it would be >>>>>>> better for a change in one Query Tool to update the other(s). >>>>>>> >>>>>>> What do you think? Was this behaviour intentional? >>>>>>> >>>>>> >>>>>> No this was not intentional. It should reflect in other query tools >>>>>> as well because changing the flags like Auto Commit changes the preferences >>>>>> config and is not local to a Query tool. I missed the fact that some >>>>>> preferences can be changed from other than preference dialog. >>>>>> >>>>>> Will send the updated patch with the fix. >>>>>> >>>>>>> >>>>>>> (FYI, in case this was a one-off bug, I was testing using "Auto >>>>>>> Commit?") >>>>>>> >>>>>>> >>>>>>>> >>>>>>>> On Fri, Jun 29, 2018 at 4:46 PM, Aditya Toshniwal < >>>>>>>> [email protected]> wrote: >>>>>>>> >>>>>>>>> Hi Akshay, >>>>>>>>> >>>>>>>>> On Fri, Jun 29, 2018 at 3:42 PM, Akshay Joshi < >>>>>>>>> [email protected]> wrote: >>>>>>>>> >>>>>>>>>> Hi Aditya >>>>>>>>>> >>>>>>>>>> I have applied your patch and run pgAdmin4. I have found >>>>>>>>>> following two issue in the browser: >>>>>>>>>> >>>>>>>>>> - Found error while open Preferences dialog. Refer >>>>>>>>>> Open_Preferences_Dialog.png >>>>>>>>>> >>>>>>>>>> This error occurs even with the latest pull without changes. >>>>>>>>> >>>>>>>>> >>>>>>>>>> >>>>>>>>>> - Set the preferences setting "Open in new browser tab" to >>>>>>>>>> True and open the query tool. Refer "Open_In_New_Broswer.png". >>>>>>>>>> >>>>>>>>>> Will look into this. >>>>>>>>> >>>>>>>>> >>>>>>>>>> I haven't review the code. >>>>>>>>>> >>>>>>>>>> On Thu, Jun 28, 2018 at 8:04 PM, Aditya Toshniwal < >>>>>>>>>> [email protected]> wrote: >>>>>>>>>> >>>>>>>>>>> Hi Hackers, >>>>>>>>>>> >>>>>>>>>>> Attached is the patch for making preferences realtime and >>>>>>>>>>> applying without reseting the layout. Please note, the patch is only for >>>>>>>>>>> one module - SQL Editor and is the first part for the RM. There are lot of >>>>>>>>>>> changes to be done to cover all and hence sending in parts. This will not >>>>>>>>>>> affect/break existing code. Further patches will cover other modules. >>>>>>>>>>> >>>>>>>>>>> Highlights of this patch include: >>>>>>>>>>> - Changes will affect SQL Editors in Create dialog boxes, SQL >>>>>>>>>>> tab of the main screen, Query tool, History entries in the query tool, >>>>>>>>>>> Query tool opened in New Tab/Window >>>>>>>>>>> - All the components of SQL editor will refer to single source >>>>>>>>>>> of preferences which is cached in the Browser object. All other redundant >>>>>>>>>>> ajax get preference calls are removed. >>>>>>>>>>> - SQL editor will not refer template JS variables anymore, once >>>>>>>>>>> all the references are removed the template variables will also be removed. >>>>>>>>>>> - Code refactoring wherever possible. >>>>>>>>>>> - Covered JS test cases wherever possible. >>>>>>>>>>> >>>>>>>>>>> Request you to kindly review. >>>>>>>>>>> >>>>>>>>>>> -- >>>>>>>>>>> Thanks and Regards, >>>>>>>>>>> Aditya Toshniwal >>>>>>>>>>> Software Engineer | EnterpriseDB Software Solutions | Pune >>>>>>>>>>> "Don't Complain about Heat, Plant a tree" >>>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> -- >>>>>>>>>> *Akshay Joshi* >>>>>>>>>> >>>>>>>>>> *Sr. Software Architect * >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> *Phone: +91 20-3058-9517Mobile: +91 976-788-8246* >>>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> -- >>>>>>>>> Thanks and Regards, >>>>>>>>> Aditya Toshniwal >>>>>>>>> Software Engineer | EnterpriseDB Software Solutions | Pune >>>>>>>>> "Don't Complain about Heat, Plant a tree" >>>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> -- >>>>>>>> Thanks and Regards, >>>>>>>> Aditya Toshniwal >>>>>>>> Software Engineer | EnterpriseDB Software Solutions | Pune >>>>>>>> "Don't Complain about Heat, Plant a tree" >>>>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>>>> -- >>>>>>> Dave Page >>>>>>> Blog: http://pgsnake.blogspot.com >>>>>>> Twitter: @pgsnake >>>>>>> >>>>>>> EnterpriseDB UK: http://www.enterprisedb.com >>>>>>> The Enterprise PostgreSQL Company >>>>>>> >>>>>> >>>>>> >>>>>> >>>>>> -- >>>>>> Thanks and Regards, >>>>>> Aditya Toshniwal >>>>>> Software Engineer | EnterpriseDB Software Solutions | Pune >>>>>> "Don't Complain about Heat, Plant a tree" >>>>>> >>>>> >>>>> >>>>> >>>>> -- >>>>> Thanks and Regards, >>>>> Aditya Toshniwal >>>>> Software Engineer | EnterpriseDB Software Solutions | Pune >>>>> "Don't Complain about Heat, Plant a tree" >>>>> >>>> >>>> >>>> >>>> -- >>>> Dave Page >>>> Blog: http://pgsnake.blogspot.com >>>> Twitter: @pgsnake >>>> >>>> EnterpriseDB UK: http://www.enterprisedb.com >>>> The Enterprise PostgreSQL Company >>>> >>> >>> >>> >>> -- >>> Thanks and Regards, >>> Aditya Toshniwal >>> Software Engineer | EnterpriseDB Software Solutions | Pune >>> "Don't Complain about Heat, Plant a tree" >>> >> >> >> >> -- >> Dave Page >> Blog: http://pgsnake.blogspot.com >> Twitter: @pgsnake >> >> EnterpriseDB UK: http://www.enterprisedb.com >> The Enterprise PostgreSQL Company >> > > > > -- > Thanks and Regards, > Aditya Toshniwal > Software Engineer | EnterpriseDB Software Solutions | Pune > "Don't Complain about Heat, Plant a tree" > -- Dave Page Blog: http://pgsnake.blogspot.com Twitter: @pgsnake EnterpriseDB UK: http://www.enterprisedb.com The Enterprise PostgreSQL Company ^ permalink raw reply [nested|flat] 14+ messages in thread
* Re: [pgAdmin4][RM3294] User need to reset the layout to see the changed preferences parameters @ 2018-07-25 09:32 Aditya Toshniwal <[email protected]> parent: Dave Page <[email protected]> 0 siblings, 0 replies; 14+ messages in thread From: Aditya Toshniwal @ 2018-07-25 09:32 UTC (permalink / raw) To: Dave Page <[email protected]>; +Cc: Akshay Joshi <[email protected]>; pgadmin-hackers Hi Hackers, Attached is the updated patch with few more fixes of existing dashboard. Fixed dashboard reloading even if subnodes under a dashboard or server selected. On Tue, Jul 24, 2018 at 9:01 PM, Dave Page <[email protected]> wrote: > Thanks, applied. > > On Tue, Jul 24, 2018 at 2:11 PM, Aditya Toshniwal <aditya.toshniwal@ > enterprisedb.com> wrote: > >> Hi, >> >> Attached is the updated patch. >> >> On Tue, Jul 24, 2018 at 4:32 PM, Dave Page <[email protected]> wrote: >> >>> Hi >>> >>> On Tue, Jul 24, 2018 at 11:39 AM, Aditya Toshniwal < >>> [email protected]> wrote: >>> >>>> Hi Hackers, >>>> >>>> Attached is the second part of the changes for making preferences >>>> realtime. The patch includes dashboard and debugger modules. >>>> >>> >>> All my dashboard graphs now seem to be straight lines. I'm guessing >>> there's a bug somewhere, as I've never seen one PG server sustain it's I/O >>> levels so perfectly, let alone the three I tested with :-) >>> >> Fixed. :P >> >> >>> >>> >>>> I would also request to create RMs for javascript test cases for >>>> dashboard and debugger modules as currently there is no setup for the test >>>> cases of these two modules. >>>> >>> >>> Please do. As well as that I'd also like to see a Python test to ensure >>> that the invocation SQL for various different types of function/procedure >>> is correct. We've messed that up a few times over the years. >>> >>> Thanks. >>> >>> The changes are on the JS side and so patch does not have any test cases >>>> included. >>>> >>> >>>> Kindly review. >>>> >>>> >>>> On Thu, Jul 5, 2018 at 4:09 PM, Dave Page <[email protected]> wrote: >>>> >>>>> Thanks - patch applied! >>>>> >>>>> On Wed, Jul 4, 2018 at 10:19 AM, Aditya Toshniwal < >>>>> [email protected]> wrote: >>>>> >>>>>> Hi Hackers, >>>>>> >>>>>> Attached is the updated patch for the RM. Change of the flags like >>>>>> auto commit, explain->verbose, etc. will reflect in all other open sql >>>>>> editors. >>>>>> Kindly review. >>>>>> >>>>>> On Fri, Jun 29, 2018 at 10:39 PM, Aditya Toshniwal < >>>>>> [email protected]> wrote: >>>>>> >>>>>>> Hi Dave, >>>>>>> >>>>>>> On Fri, Jun 29, 2018 at 9:30 PM, Dave Page <[email protected]> >>>>>>> wrote: >>>>>>> >>>>>>>> Hi >>>>>>>> >>>>>>>> On Fri, Jun 29, 2018 at 3:14 PM, Aditya Toshniwal < >>>>>>>> [email protected]> wrote: >>>>>>>> >>>>>>>>> Hi Hackers, >>>>>>>>> >>>>>>>>> Attached is the updated patch. >>>>>>>>> >>>>>>>> >>>>>>>> This seems to work for the most part, however I saw what seemed >>>>>>>> like odd behaviour. If I have 2 query tool windows open; >>>>>>>> >>>>>>>> - Changing a preference from the Preferences dialogue updates both >>>>>>>> query tools. >>>>>>>> >>>>>>>> - Changing a preference from a Query Tool updates the Preferences >>>>>>>> dialogue. >>>>>>>> >>>>>>>> - Changing a preference from a Query Tool does *not* update the >>>>>>>> other Query Tool. >>>>>>>> >>>>>>>> The last point seems odd to me, though it also kinda makes sense to >>>>>>>> not have one query tool affect the other. The problem with that is that it >>>>>>>> could get quite confusing when they get out of sync. I think it would be >>>>>>>> better for a change in one Query Tool to update the other(s). >>>>>>>> >>>>>>>> What do you think? Was this behaviour intentional? >>>>>>>> >>>>>>> >>>>>>> No this was not intentional. It should reflect in other query tools >>>>>>> as well because changing the flags like Auto Commit changes the preferences >>>>>>> config and is not local to a Query tool. I missed the fact that some >>>>>>> preferences can be changed from other than preference dialog. >>>>>>> >>>>>>> Will send the updated patch with the fix. >>>>>>> >>>>>>>> >>>>>>>> (FYI, in case this was a one-off bug, I was testing using "Auto >>>>>>>> Commit?") >>>>>>>> >>>>>>>> >>>>>>>>> >>>>>>>>> On Fri, Jun 29, 2018 at 4:46 PM, Aditya Toshniwal < >>>>>>>>> [email protected]> wrote: >>>>>>>>> >>>>>>>>>> Hi Akshay, >>>>>>>>>> >>>>>>>>>> On Fri, Jun 29, 2018 at 3:42 PM, Akshay Joshi < >>>>>>>>>> [email protected]> wrote: >>>>>>>>>> >>>>>>>>>>> Hi Aditya >>>>>>>>>>> >>>>>>>>>>> I have applied your patch and run pgAdmin4. I have found >>>>>>>>>>> following two issue in the browser: >>>>>>>>>>> >>>>>>>>>>> - Found error while open Preferences dialog. Refer >>>>>>>>>>> Open_Preferences_Dialog.png >>>>>>>>>>> >>>>>>>>>>> This error occurs even with the latest pull without changes. >>>>>>>>>> >>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> - Set the preferences setting "Open in new browser tab" to >>>>>>>>>>> True and open the query tool. Refer "Open_In_New_Broswer.png". >>>>>>>>>>> >>>>>>>>>>> Will look into this. >>>>>>>>>> >>>>>>>>>> >>>>>>>>>>> I haven't review the code. >>>>>>>>>>> >>>>>>>>>>> On Thu, Jun 28, 2018 at 8:04 PM, Aditya Toshniwal < >>>>>>>>>>> [email protected]> wrote: >>>>>>>>>>> >>>>>>>>>>>> Hi Hackers, >>>>>>>>>>>> >>>>>>>>>>>> Attached is the patch for making preferences realtime and >>>>>>>>>>>> applying without reseting the layout. Please note, the patch is only for >>>>>>>>>>>> one module - SQL Editor and is the first part for the RM. There are lot of >>>>>>>>>>>> changes to be done to cover all and hence sending in parts. This will not >>>>>>>>>>>> affect/break existing code. Further patches will cover other modules. >>>>>>>>>>>> >>>>>>>>>>>> Highlights of this patch include: >>>>>>>>>>>> - Changes will affect SQL Editors in Create dialog boxes, SQL >>>>>>>>>>>> tab of the main screen, Query tool, History entries in the query tool, >>>>>>>>>>>> Query tool opened in New Tab/Window >>>>>>>>>>>> - All the components of SQL editor will refer to single source >>>>>>>>>>>> of preferences which is cached in the Browser object. All other redundant >>>>>>>>>>>> ajax get preference calls are removed. >>>>>>>>>>>> - SQL editor will not refer template JS variables anymore, >>>>>>>>>>>> once all the references are removed the template variables will also be >>>>>>>>>>>> removed. >>>>>>>>>>>> - Code refactoring wherever possible. >>>>>>>>>>>> - Covered JS test cases wherever possible. >>>>>>>>>>>> >>>>>>>>>>>> Request you to kindly review. >>>>>>>>>>>> >>>>>>>>>>>> -- >>>>>>>>>>>> Thanks and Regards, >>>>>>>>>>>> Aditya Toshniwal >>>>>>>>>>>> Software Engineer | EnterpriseDB Software Solutions | Pune >>>>>>>>>>>> "Don't Complain about Heat, Plant a tree" >>>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> -- >>>>>>>>>>> *Akshay Joshi* >>>>>>>>>>> >>>>>>>>>>> *Sr. Software Architect * >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> *Phone: +91 20-3058-9517Mobile: +91 976-788-8246* >>>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> -- >>>>>>>>>> Thanks and Regards, >>>>>>>>>> Aditya Toshniwal >>>>>>>>>> Software Engineer | EnterpriseDB Software Solutions | Pune >>>>>>>>>> "Don't Complain about Heat, Plant a tree" >>>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> -- >>>>>>>>> Thanks and Regards, >>>>>>>>> Aditya Toshniwal >>>>>>>>> Software Engineer | EnterpriseDB Software Solutions | Pune >>>>>>>>> "Don't Complain about Heat, Plant a tree" >>>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> -- >>>>>>>> Dave Page >>>>>>>> Blog: http://pgsnake.blogspot.com >>>>>>>> Twitter: @pgsnake >>>>>>>> >>>>>>>> EnterpriseDB UK: http://www.enterprisedb.com >>>>>>>> The Enterprise PostgreSQL Company >>>>>>>> >>>>>>> >>>>>>> >>>>>>> >>>>>>> -- >>>>>>> Thanks and Regards, >>>>>>> Aditya Toshniwal >>>>>>> Software Engineer | EnterpriseDB Software Solutions | Pune >>>>>>> "Don't Complain about Heat, Plant a tree" >>>>>>> >>>>>> >>>>>> >>>>>> >>>>>> -- >>>>>> Thanks and Regards, >>>>>> Aditya Toshniwal >>>>>> Software Engineer | EnterpriseDB Software Solutions | Pune >>>>>> "Don't Complain about Heat, Plant a tree" >>>>>> >>>>> >>>>> >>>>> >>>>> -- >>>>> Dave Page >>>>> Blog: http://pgsnake.blogspot.com >>>>> Twitter: @pgsnake >>>>> >>>>> EnterpriseDB UK: http://www.enterprisedb.com >>>>> The Enterprise PostgreSQL Company >>>>> >>>> >>>> >>>> >>>> -- >>>> Thanks and Regards, >>>> Aditya Toshniwal >>>> Software Engineer | EnterpriseDB Software Solutions | Pune >>>> "Don't Complain about Heat, Plant a tree" >>>> >>> >>> >>> >>> -- >>> Dave Page >>> Blog: http://pgsnake.blogspot.com >>> Twitter: @pgsnake >>> >>> EnterpriseDB UK: http://www.enterprisedb.com >>> The Enterprise PostgreSQL Company >>> >> >> >> >> -- >> Thanks and Regards, >> Aditya Toshniwal >> Software Engineer | EnterpriseDB Software Solutions | Pune >> "Don't Complain about Heat, Plant a tree" >> > > > > -- > Dave Page > Blog: http://pgsnake.blogspot.com > Twitter: @pgsnake > > EnterpriseDB UK: http://www.enterprisedb.com > The Enterprise PostgreSQL Company > -- Thanks and Regards, Aditya Toshniwal Software Engineer | EnterpriseDB Software Solutions | Pune "Don't Complain about Heat, Plant a tree" Attachments: [application/octet-stream] 0003-RM3294.patch (8.5K, 3-0003-RM3294.patch) download | inline diff: diff --git a/web/pgadmin/dashboard/static/js/dashboard.js b/web/pgadmin/dashboard/static/js/dashboard.js index b888b6d5..09d885d7 100644 --- a/web/pgadmin/dashboard/static/js/dashboard.js +++ b/web/pgadmin/dashboard/static/js/dashboard.js @@ -249,8 +249,6 @@ 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), @@ -291,6 +289,8 @@ define('pgadmin.dashboard', [ url += self.sid; cancel_query_url += self.sid + '/'; terminate_session_url += self.sid + '/'; + } else { + is_server_dashboard = is_database_dashboard = false; } } @@ -306,8 +306,10 @@ define('pgadmin.dashboard', [ 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(); + /* Clear all the interval functions of previous dashboards */ + self.clearIntervalId(); + $.ajax({ url: url, @@ -325,9 +327,6 @@ define('pgadmin.dashboard', [ }); $(dashboardPanel).data('server_status', true); } - else { - self.init_dashboard(); - } } else { $(div).empty(); $(div).html( @@ -655,10 +654,6 @@ define('pgadmin.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 */ @@ -683,30 +678,7 @@ define('pgadmin.dashboard', [ }, 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 options_line = { - parseFloat: false, - xaxis: { - min: 100, - max: 0, - autoscale: 0, - }, - yaxis: { - autoscale: 1, - }, - legend: { - position: 'nw', - backgroundColor: '#D2E8FF', - }, - shadowSize: 0, - resolution : 5, - }; /* We will use old preferences for selective graph updates on preference change */ if(self.preferences) { @@ -718,60 +690,86 @@ define('pgadmin.dashboard', [ 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(is_server_dashboard || is_database_dashboard) { + /* Common things can come here */ + 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 options_line = { + parseFloat: false, + xaxis: { + min: 100, + max: 0, + autoscale: 0, + }, + yaxis: { + autoscale: 1, + }, + legend: { + position: 'nw', + backgroundColor: '#D2E8FF', + }, + shadowSize: 0, + resolution : 5, + }; + + 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_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, url_for('dashboard.session_stats'), options_line, false, - 'session_stats', 'session_stats_refresh' - ); - pgAdmin.Dashboard.render_chart( - div_tps, url_for('dashboard.tps_stats'), options_line, true, - 'tps_stats','tps_stats_refresh' - ); - pgAdmin.Dashboard.render_chart( - div_ti, url_for('dashboard.ti_stats'), options_line, true, - 'ti_stats', 'ti_stats_refresh' - ); - pgAdmin.Dashboard.render_chart( - div_to, url_for('dashboard.to_stats'), options_line, true, - 'to_stats','to_stats_refresh' - ); - pgAdmin.Dashboard.render_chart( - div_bio, url_for('dashboard.bio_stats'), options_line, true, - 'bio_stats','bio_stats_refresh' - ); - } + if(self.preferences.show_graphs) { + // Render the graphs + pgAdmin.Dashboard.render_chart( + div_sessions, url_for('dashboard.session_stats'), options_line, false, + 'session_stats', 'session_stats_refresh' + ); + pgAdmin.Dashboard.render_chart( + div_tps, url_for('dashboard.tps_stats'), options_line, true, + 'tps_stats','tps_stats_refresh' + ); + pgAdmin.Dashboard.render_chart( + div_ti, url_for('dashboard.ti_stats'), options_line, true, + 'ti_stats', 'ti_stats_refresh' + ); + pgAdmin.Dashboard.render_chart( + div_to, url_for('dashboard.to_stats'), options_line, true, + 'to_stats','to_stats_refresh' + ); + pgAdmin.Dashboard.render_chart( + 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'); + } - if(!self.preferences.show_graphs && !self.preferences.show_activity) { - $('#dashboard-none-show').removeClass('dashboard-hidden'); - } - else { - $('#dashboard-none-show').addClass('dashboard-hidden'); + /* Dashboard specific preferences can be updated in the + * appropriate functions + */ + if(is_server_dashboard) { + self.reflectPreferencesServer(); + } + else if(is_database_dashboard) { + self.reflectPreferencesDatabase(); + } } }, reflectPreferencesServer: function() { @@ -1313,12 +1311,7 @@ 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 ^ permalink raw reply [nested|flat] 14+ messages in thread
end of thread, other threads:[~2018-07-25 09:32 UTC | newest] Thread overview: 14+ messages (download: mbox mbox.gz follow: Atom feed) -- links below jump to the message on this page -- 2018-06-28 14:34 [pgAdmin4][RM3294] User need to reset the layout to see the changed preferences parameters Aditya Toshniwal <[email protected]> 2018-06-29 10:12 ` Akshay Joshi <[email protected]> 2018-06-29 11:16 ` Aditya Toshniwal <[email protected]> 2018-06-29 14:14 ` Aditya Toshniwal <[email protected]> 2018-06-29 16:00 ` Dave Page <[email protected]> 2018-06-29 17:09 ` Aditya Toshniwal <[email protected]> 2018-07-04 09:19 ` Aditya Toshniwal <[email protected]> 2018-07-05 10:39 ` Dave Page <[email protected]> 2018-07-24 10:39 ` Aditya Toshniwal <[email protected]> 2018-07-24 10:43 ` Aditya Toshniwal <[email protected]> 2018-07-24 11:02 ` Dave Page <[email protected]> 2018-07-24 13:11 ` Aditya Toshniwal <[email protected]> 2018-07-24 15:31 ` Dave Page <[email protected]> 2018-07-25 09:32 ` Aditya Toshniwal <[email protected]>
This inbox is served by agora; see mirroring instructions for how to clone and mirror all data and code used for this inbox