public inbox for [email protected]
help / color / mirror / Atom feedFrom: Aditya Toshniwal <[email protected]>
To: pgadmin-hackers <[email protected]>
Subject: [pgAdmin][RM2653] Lock layout
Date: Thu, 30 May 2019 15:44:55 +0530
Message-ID: <CAM9w-_n-1EKo44GctmEKy=SFRVK04a6yKGoQnawCq47X1FX=eA@mail.gmail.com> (raw)
Hi Hackers,
Attached is the patch to introduce feature to lock the layout with three
different levels:
1) None - No locking
2) Prevent docking - The docking/undocking of panels will be disabled
3) Full lock - The resizing along with docking/undocking of panels will be
disabled
- This can be changed from new menu under File->Lock layout-><The level> or
from Preferences->Browser->Display->Lock Layout
- JS test cases added.
With this patch I have also changed below:
1) Moved the maintenance dialog button group control to new common control
named RadioModern, which I have re-used in preferences for lock layout
levels.
2) Added main nav bar menu with check feature, the menus which can checked.
3) Ability to add submenus from existing get_own_menuitems in python code
which is not possible currently.
3) Separated all the layout related functions from browser.js to new file
layout.js to help JS testing.
Kindly review.
--
Thanks and Regards,
Aditya Toshniwal
Software Engineer | EnterpriseDB India | Pune
"Don't Complain about Heat, Plant a TREE"
Attachments:
[application/octet-stream] RM2653.patch (33.9K, 3-RM2653.patch)
download | inline diff:
diff --git a/web/package.json b/web/package.json
index c9892f60..f567ee25 100644
--- a/web/package.json
+++ b/web/package.json
@@ -89,7 +89,7 @@
"underscore": "^1.9.1",
"underscore.string": "^3.3.5",
"watchify": "~3.11.1",
- "webcabin-docker": "git+https://github.com/EnterpriseDB/wcDocker/#e191a1063c111d5542ff26a7c163940be180333d",
+ "webcabin-docker": "git+https://github.com/EnterpriseDB/wcDocker/#f3c79e4b9a9e76a8e34736fc33473e65c524050c",
"wkx": "^0.4.6"
},
"scripts": {
diff --git a/web/pgadmin/browser/__init__.py b/web/pgadmin/browser/__init__.py
index 5fd08b5c..508a8077 100644
--- a/web/pgadmin/browser/__init__.py
+++ b/web/pgadmin/browser/__init__.py
@@ -39,6 +39,7 @@ from pgadmin.utils import PgAdminModule
from pgadmin.utils.ajax import make_json_response
from pgadmin.utils.csrf import pgCSRFProtect
from pgadmin.utils.preferences import Preferences
+from pgadmin.utils.menu import MenuItem
from pgadmin.browser.register_browser_preferences import \
register_browser_preferences
from pgadmin.utils.master_password import validate_master_password, \
@@ -215,6 +216,40 @@ class BrowserModule(PgAdminModule):
scripts.extend(module.get_own_javascripts())
return scripts
+ def get_own_menuitems(self):
+ return {
+ 'file_items': [
+ MenuItem(
+ name='mnu_locklayout',
+ module='pgAdmin.Browser',
+ label=gettext('Lock layout'),
+ priority=999,
+ menu_items=[MenuItem(
+ name='mnu_lock_none',
+ module='pgAdmin.Browser',
+ callback='mnu_lock_none',
+ priority=0,
+ label=gettext('None'),
+ checked=True
+ ), MenuItem(
+ name='mnu_lock_docking',
+ module='pgAdmin.Browser',
+ callback='mnu_lock_docking',
+ priority=1,
+ label=gettext('Prevent docking'),
+ checked=False
+ ), MenuItem(
+ name='mnu_lock_full',
+ module='pgAdmin.Browser',
+ callback='mnu_lock_full',
+ priority=2,
+ label=gettext('Full lock'),
+ checked=False
+ )]
+ )
+ ]
+ }
+
def register_preferences(self):
register_browser_preferences(self)
@@ -226,7 +261,8 @@ class BrowserModule(PgAdminModule):
return ['browser.index', 'browser.nodes',
'browser.check_master_password',
'browser.set_master_password',
- 'browser.reset_master_password']
+ 'browser.reset_master_password',
+ 'browser.lock_layout']
blueprint = BrowserModule(MODULE_NAME, __name__)
@@ -815,6 +851,21 @@ def set_master_password():
)
[email protected]("/lock_layout", endpoint="lock_layout", methods=["PUT"])
+def lock_layout():
+ data = None
+
+ if hasattr(request.data, 'decode'):
+ data = request.data.decode('utf-8')
+
+ if data != '':
+ data = json.loads(data)
+
+ blueprint.lock_layout.set(data['value'])
+
+ return make_json_response()
+
+
# Only register route if SECURITY_CHANGEABLE is set to True
# We can't access app context here so cannot
# use app.config['SECURITY_CHANGEABLE']
diff --git a/web/pgadmin/browser/register_browser_preferences.py b/web/pgadmin/browser/register_browser_preferences.py
index c4d86c66..35ae7340 100644
--- a/web/pgadmin/browser/register_browser_preferences.py
+++ b/web/pgadmin/browser/register_browser_preferences.py
@@ -8,6 +8,12 @@
##########################################################################
from flask_babelex import gettext
+LOCK_LAYOUT_LEVEL = {
+ 'PREVENT_DOCKING': 'docking',
+ 'FULL': 'full',
+ 'NONE': 'none'
+}
+
def register_browser_preferences(self):
self.show_system_objects = self.preference.register(
@@ -58,6 +64,20 @@ def register_browser_preferences(self):
)
)
+ self.lock_layout = self.preference.register(
+ 'display', 'lock_layout',
+ gettext('Lock layout'), 'radioModern', LOCK_LAYOUT_LEVEL['NONE'],
+ category_label=gettext('Display'), options=[
+ {'label': gettext('None'), 'value': LOCK_LAYOUT_LEVEL['NONE']},
+ {'label': gettext('Prevent docking'),
+ 'value': LOCK_LAYOUT_LEVEL['PREVENT_DOCKING']},
+ {'label': gettext('Full'), 'value': LOCK_LAYOUT_LEVEL['FULL']},
+ ],
+ help_str=gettext(
+ 'Will change this later... '
+ )
+ )
+
self.table_row_count_threshold = self.preference.register(
'properties', 'table_row_count_threshold',
gettext("Count rows if estimated less than"), 'integer', 2000,
diff --git a/web/pgadmin/browser/static/js/browser.js b/web/pgadmin/browser/static/js/browser.js
index 7fbed5a9..77810dc7 100644
--- a/web/pgadmin/browser/static/js/browser.js
+++ b/web/pgadmin/browser/static/js/browser.js
@@ -15,7 +15,7 @@ define('pgadmin.browser', [
'sources/csrf', 'pgadmin.browser.utils',
'wcdocker', 'jquery.contextmenu', 'jquery.aciplugin', 'jquery.acitree',
'pgadmin.browser.preferences', 'pgadmin.browser.messages',
- 'pgadmin.browser.menu', 'pgadmin.browser.panel',
+ 'pgadmin.browser.menu', 'pgadmin.browser.panel', 'pgadmin.browser.layout',
'pgadmin.browser.error', 'pgadmin.browser.frame',
'pgadmin.browser.node', 'pgadmin.browser.collection',
'sources/codemirror/addon/fold/pgadmin-sqlfoldcode',
@@ -282,22 +282,6 @@ define('pgadmin.browser', [
scripts[n].push({'name': m, 'path': p, loaded: false});
},
masterpass_callback_queue: [],
- // Build the default layout
- buildDefaultLayout: function(docker) {
- var browserPanel = docker.addPanel('browser', wcDocker.DOCK.LEFT);
- var dashboardPanel = docker.addPanel(
- 'dashboard', wcDocker.DOCK.RIGHT, browserPanel);
- docker.addPanel('properties', wcDocker.DOCK.STACKED, dashboardPanel, {
- tabOrientation: wcDocker.TAB.TOP,
- });
- docker.addPanel('sql', wcDocker.DOCK.STACKED, dashboardPanel);
- docker.addPanel(
- 'statistics', wcDocker.DOCK.STACKED, dashboardPanel);
- docker.addPanel(
- 'dependencies', wcDocker.DOCK.STACKED, dashboardPanel);
- docker.addPanel(
- 'dependents', wcDocker.DOCK.STACKED, dashboardPanel);
- },
// Enable/disable menu options
enable_disable_menus: function(item) {
// Mechanism to enable/disable menus depending on the condition.
@@ -354,35 +338,6 @@ define('pgadmin.browser', [
$obj_mnu.append(create_submenu.$el);
}
},
- save_current_layout: function(layout_id, docker) {
- if(docker) {
- var layout = docker.save(),
- settings = { setting: layout_id, value: layout };
- $.ajax({
- type: 'POST',
- url: url_for('settings.store_bulk'),
- data: settings,
- });
- }
- },
- restore_layout: function(docker, layout, defaultLayoutCallback) {
- // Try to restore the layout if there is one
- if (layout != '') {
- try {
- docker.restore(layout);
- }
- catch(err) {
- docker.clear();
- if(defaultLayoutCallback) {
- defaultLayoutCallback(docker);
- }
- }
- } else {
- if(defaultLayoutCallback) {
- defaultLayoutCallback(docker);
- }
- }
- },
init: function() {
var obj=this;
if (obj.initialized) {
@@ -797,8 +752,8 @@ define('pgadmin.browser', [
menus = pgMenu[a];
}
- if (!_.has(menus, m.name)) {
- menus[m.name] = new MenuItem({
+ let get_menuitem_obj = function(m) {
+ return new MenuItem({
name: m.name, label: m.label, module: m.module,
category: m.category, callback: m.callback,
priority: m.priority, data: m.data, url: m.url || '#',
@@ -806,8 +761,21 @@ define('pgadmin.browser', [
enable: (m.enable == '' ? true : (_.isString(m.enable) &&
m.enable.toLowerCase() == 'false') ?
false : m.enable),
- node: m.node,
+ node: m.node, checked: m.checked,
});
+ };
+
+ if (!_.has(menus, m.name)) {
+ menus[m.name] = get_menuitem_obj(m);
+
+ if(m.menu_items) {
+ let sub_menu_items = [];
+
+ for(let i=0; i<m.menu_items.length; i++) {
+ sub_menu_items.push(get_menuitem_obj(m.menu_items[i]));
+ }
+ menus[m.name]['menu_items'] = sub_menu_items;
+ }
}
} else {
console.warn(
diff --git a/web/pgadmin/browser/static/js/layout.js b/web/pgadmin/browser/static/js/layout.js
new file mode 100644
index 00000000..8b5e9913
--- /dev/null
+++ b/web/pgadmin/browser/static/js/layout.js
@@ -0,0 +1,161 @@
+/////////////////////////////////////////////////////////////
+//
+// pgAdmin 4 - PostgreSQL Tools
+//
+// Copyright (C) 2013 - 2019, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+//////////////////////////////////////////////////////////////
+
+import pgAdmin from 'sources/pgadmin';
+import url_for from 'sources/url_for';
+import $ from 'jquery';
+import * as Alertify from 'pgadmin.alertifyjs';
+import gettext from 'sources/gettext';
+import 'wcdocker';
+
+const pgBrowser = pgAdmin.Browser = pgAdmin.Browser || {};
+
+var wcDocker = window.wcDocker;
+
+/* Add cache related methods and properties */
+_.extend(pgBrowser, {
+ lock_layout_levels : {
+ PREVENT_DOCKING: 'docking',
+ FULL: 'full',
+ NONE: 'none',
+ },
+
+ // Build the default layout
+ buildDefaultLayout: function(docker) {
+ var browserPanel = docker.addPanel('browser', wcDocker.DOCK.LEFT);
+ var dashboardPanel = docker.addPanel(
+ 'dashboard', wcDocker.DOCK.RIGHT, browserPanel);
+ docker.addPanel('properties', wcDocker.DOCK.STACKED, dashboardPanel, {
+ tabOrientation: wcDocker.TAB.TOP,
+ });
+ docker.addPanel('sql', wcDocker.DOCK.STACKED, dashboardPanel);
+ docker.addPanel(
+ 'statistics', wcDocker.DOCK.STACKED, dashboardPanel);
+ docker.addPanel(
+ 'dependencies', wcDocker.DOCK.STACKED, dashboardPanel);
+ docker.addPanel(
+ 'dependents', wcDocker.DOCK.STACKED, dashboardPanel);
+ },
+
+ save_current_layout: function(layout_id, docker) {
+ if(docker) {
+ var layout = docker.save(),
+ settings = { setting: layout_id, value: layout };
+ $.ajax({
+ type: 'POST',
+ url: url_for('settings.store_bulk'),
+ data: settings,
+ });
+ }
+ },
+
+ restore_layout: function(docker, layout, defaultLayoutCallback) {
+ // Try to restore the layout if there is one
+ if (layout != '') {
+ try {
+ docker.restore(layout);
+ }
+ catch(err) {
+ docker.clear();
+ if(defaultLayoutCallback) {
+ defaultLayoutCallback(docker);
+ }
+ }
+ } else {
+ if(defaultLayoutCallback) {
+ defaultLayoutCallback(docker);
+ }
+ }
+
+ /* preference available only with top/opener browser. */
+ let browser = window.opener ?
+ window.opener.pgAdmin.Browser : window.top.pgAdmin.Browser;
+
+ /* interval required initially as preference load may take time */
+ let cacheIntervalId = setInterval(()=> {
+ let browserPref = browser.get_preferences_for_module('browser');
+ if(browserPref) {
+ clearInterval(cacheIntervalId);
+
+ browser.reflectLocklayoutChange(docker);
+
+ browser.onPreferencesChange('browser', function() {
+ browser.reflectLocklayoutChange(docker);
+ });
+ }
+ }, 500);
+ },
+
+ reflectLocklayoutChange: function(docker) {
+ let browser = window.opener ?
+ window.opener.pgAdmin.Browser : window.top.pgAdmin.Browser;
+
+ let browserPref = browser.get_preferences_for_module('browser');
+ browser.lock_layout(docker, browserPref.lock_layout);
+ },
+
+ lock_layout: function(docker, op) {
+ let menu_items = this.menus['file']['mnu_locklayout']['menu_items'];
+
+ switch(op) {
+ case this.lock_layout_levels.PREVENT_DOCKING:
+ docker.lockLayout(wcDocker.LOCK_LAYOUT_LEVEL.PREVENT_DOCKING);
+ break;
+ case this.lock_layout_levels.FULL:
+ docker.lockLayout(wcDocker.LOCK_LAYOUT_LEVEL.FULL);
+ break;
+ case this.lock_layout_levels.NONE:
+ docker.lockLayout(wcDocker.LOCK_LAYOUT_LEVEL.NONE);
+ break;
+ }
+
+ _.each(menu_items, function(menu_item) {
+ if(menu_item.name != ('mnu_lock_'+op)) {
+ menu_item.change_checked(false);
+ } else {
+ menu_item.change_checked(true);
+ }
+ });
+ },
+
+ save_lock_layout: function(op) {
+ let browser = window.opener ?
+ window.opener.pgAdmin.Browser : window.top.pgAdmin.Browser;
+
+ $.ajax({
+ url: url_for('browser.lock_layout'),
+ method: 'PUT',
+ contentType: 'application/json',
+ data: JSON.stringify({
+ 'value': op,
+ }),
+ }).done(function() {
+ browser.cache_preferences('browser');
+ }).fail(function(xhr, error) {
+ Alertify.pgNotifier(error, xhr, gettext('Failed to save lock layout setting.'));
+ });
+ },
+
+ mnu_lock_docking: function() {
+ this.lock_layout(this.docker, this.lock_layout_levels.PREVENT_DOCKING);
+ this.save_lock_layout(this.lock_layout_levels.PREVENT_DOCKING);
+ },
+
+ mnu_lock_full: function() {
+ this.lock_layout(this.docker, this.lock_layout_levels.FULL);
+ this.save_lock_layout(this.lock_layout_levels.FULL);
+ },
+
+ mnu_lock_none: function() {
+ this.lock_layout(this.docker, this.lock_layout_levels.NONE);
+ this.save_lock_layout(this.lock_layout_levels.NONE);
+ },
+});
+
+export {pgBrowser};
diff --git a/web/pgadmin/browser/static/js/menu.js b/web/pgadmin/browser/static/js/menu.js
index f8c018dc..e76c9ed2 100644
--- a/web/pgadmin/browser/static/js/menu.js
+++ b/web/pgadmin/browser/static/js/menu.js
@@ -19,6 +19,7 @@ define([
var menu_opts = [
'name', 'label', 'priority', 'module', 'callback', 'data', 'enable',
'category', 'target', 'url' /* Do not show icon in the menus, 'icon' */ , 'node',
+ 'checked', 'menu_items',
],
defaults = {
url: '#',
@@ -55,31 +56,48 @@ define([
* Create the jquery element for the menu-item.
*/
create_el: function(node, item) {
- var url = $('<a></a>', {
- 'id': this.name,
- 'href': this.url,
- 'target': this.target,
- 'data-toggle': 'pg-menu',
- }).data('pgMenu', {
- module: this.module || pgAdmin.Browser,
- cb: this.callback,
- data: this.data,
- }).addClass('dropdown-item');
- this.is_disabled = this.disabled(node, item);
- if (this.icon) {
- url.append($('<i></i>', {
- 'class': this.icon,
- }));
- }
+ if(this.menu_items) {
+ _.each(this.menu_items, function(submenu_item){
+ submenu_item.generate(node, item);
+ });
+ var create_submenu = pgAdmin.Browser.MenuGroup({
+ 'label': this.label,
+ 'id': this.name,
+ }, this.menu_items);
+ this.$el = create_submenu.$el;
+ } else {
+ var url = $('<a></a>', {
+ 'id': this.name,
+ 'href': this.url,
+ 'target': this.target,
+ 'data-toggle': 'pg-menu',
+ }).data('pgMenu', {
+ module: this.module || pgAdmin.Browser,
+ cb: this.callback,
+ data: this.data,
+ }).addClass('dropdown-item');
+
+ this.is_disabled = this.disabled(node, item);
+ if (this.icon) {
+ url.append($('<i></i>', {
+ 'class': this.icon,
+ }));
+ } else if(!_.isUndefined(this.checked)) {
+ url.append($('<i></i>', {
+ 'class': 'fa fa-check '+ (this.checked?'':'visibility-hidden'),
+ }));
+ }
- url.addClass((this.is_disabled ? ' disabled' : ''));
+ url.addClass((this.is_disabled ? ' disabled' : ''));
- var textSpan = $('<span data-test="menu-item-text"></span>').text(' ' + this.label);
+ var textSpan = $('<span data-test="menu-item-text"></span>').text(' ' + this.label);
- url.append(textSpan);
+ url.append(textSpan);
+
+ this.$el = $('<li/>').append(url);
+ }
- this.$el = $('<li/>').append(url);
},
/*
* Updates the enable/disable state of the menu-item based on the current
@@ -154,6 +172,20 @@ define([
return false;
},
+
+ /*
+ * Change the checked value and update the checked icon on the menu
+ */
+ change_checked(isChecked) {
+ if(!_.isUndefined(this.checked)) {
+ this.checked = isChecked;
+ if(this.checked) {
+ this.$el.find('.fa-check').removeClass('visibility-hidden');
+ } else {
+ this.$el.find('.fa-check').addClass('visibility-hidden');
+ }
+ }
+ },
});
/*
diff --git a/web/pgadmin/browser/templates/browser/js/utils.js b/web/pgadmin/browser/templates/browser/js/utils.js
index cefe9ae7..99d795bc 100644
--- a/web/pgadmin/browser/templates/browser/js/utils.js
+++ b/web/pgadmin/browser/templates/browser/js/utils.js
@@ -7,6 +7,32 @@
//
//////////////////////////////////////////////////////////////
+{% macro A_MENU_ITEM(key, item) -%}
+{
+ name: "{{ item.name }}",
+ {% if item.module %}module: {{ item.module }},
+ {% endif %}{% if item.url %}url: "{{ item.url }}",
+ {% endif %}{% if item.target %}target: "{{ item.target }}",
+ {% endif %}{% if item.callback %}callback: "{{ item.callback }}",
+ {% endif %}{% if item.category %}category: "{{ item.category }}",
+ {% endif %}{% if item.icon %}icon: '{{ item.icon }}',
+ {% endif %}{% if item.data %}data: {{ item.data }},
+ {% endif %}label: '{{ item.label }}', applies: ['{{ key.lower() }}'],
+ priority: {{ item.priority }},
+ enable: '{{ item.enable }}',
+ {% if item.checked is defined %}checked: {% if item.checked %}true{% else %}false{% endif %},
+ {% endif %}
+ {% if item.menu_items %}menu_items: {{MENU_ITEMS(key, item.menu_items)}}
+ {% endif %}
+}
+{%- endmacro %}
+
+{% macro MENU_ITEMS(key, items) -%}
+[
+ {% for item in items %}{% if loop.index != 1 %}, {% endif %}
+ {{ A_MENU_ITEM(key, item) }}{% set hasMenus = True %}{% endfor %}
+]
+{%- endmacro %}
define('pgadmin.browser.utils',
['sources/pgadmin'], function(pgAdmin) {
@@ -56,19 +82,7 @@ define('pgadmin.browser.utils',
var self = this;
if (this.counter.total == this.counter.loaded) {
{% for key in ('File', 'Edit', 'Object' 'Tools', 'Management', 'Help') %}
- obj.add_menus([{% for item in current_app.menu_items['%s_items' % key.lower()] %}{% if loop.index != 1 %}, {% endif %}{
- name: "{{ item.name }}",
- {% if item.module %}module: {{ item.module }},
- {% endif %}{% if item.url %}url: "{{ item.url }}",
- {% endif %}{% if item.target %}target: "{{ item.target }}",
- {% endif %}{% if item.callback %}callback: "{{ item.callback }}",
- {% endif %}{% if item.category %}category: "{{ item.category }}",
- {% endif %}{% if item.icon %}icon: '{{ item.icon }}',
- {% endif %}{% if item.data %}data: {{ item.data }},
- {% endif %}label: '{{ item.label }}', applies: ['{{ key.lower() }}'],
- priority: {{ item.priority }},
- enable: '{{ item.enable }}'
- }{% set hasMenus = True %}{% endfor %}]);
+ obj.add_menus({{ MENU_ITEMS(key, current_app.menu_items['%s_items' % key.lower()])}});
{% endfor %}
obj.create_menus();
} else {
diff --git a/web/pgadmin/preferences/__init__.py b/web/pgadmin/preferences/__init__.py
index bbe9693b..44732171 100644
--- a/web/pgadmin/preferences/__init__.py
+++ b/web/pgadmin/preferences/__init__.py
@@ -48,7 +48,7 @@ class PreferencesModule(PgAdminModule):
return {
'file_items': [
MenuItem(name='mnu_preferences',
- priority=999,
+ priority=997,
module="pgAdmin.Preferences",
callback='show',
icon='fa fa-cog',
diff --git a/web/pgadmin/preferences/static/js/preferences.js b/web/pgadmin/preferences/static/js/preferences.js
index 513e3381..b047b13a 100644
--- a/web/pgadmin/preferences/static/js/preferences.js
+++ b/web/pgadmin/preferences/static/js/preferences.js
@@ -271,6 +271,8 @@ define('pgadmin.preferences', [
return 'switch';
case 'keyboardshortcut':
return 'keyboardShortcut';
+ case 'radioModern':
+ return 'radioModern';
default:
if (console && console.warn) {
// Warning for developer only.
diff --git a/web/pgadmin/settings/__init__.py b/web/pgadmin/settings/__init__.py
index fd79634e..b84a5072 100644
--- a/web/pgadmin/settings/__init__.py
+++ b/web/pgadmin/settings/__init__.py
@@ -39,7 +39,7 @@ class SettingsModule(PgAdminModule):
'file_items': [
MenuItem(
name='mnu_resetlayout',
- priority=999,
+ priority=998,
module="pgAdmin.Settings",
callback='show',
icon='fa fa-retweet',
diff --git a/web/pgadmin/static/js/backform.pgadmin.js b/web/pgadmin/static/js/backform.pgadmin.js
index 2a8792b2..b97fc380 100644
--- a/web/pgadmin/static/js/backform.pgadmin.js
+++ b/web/pgadmin/static/js/backform.pgadmin.js
@@ -60,6 +60,7 @@ define([
'select2': 'select2',
'note': 'note',
'color': 'color',
+ 'radioModern': 'radioModern',
};
Backform.getMappedControl = function(type, mode) {
@@ -95,6 +96,17 @@ define([
return type;
};
+ /* Returns raw data as it is */
+ var RawFormatter = Backform.RawFormatter = function() {};
+ _.extend(RawFormatter.prototype, {
+ fromRaw: function(rawData) {
+ return rawData;
+ },
+ toRaw: function(formattedData) {
+ return formattedData;
+ },
+ });
+
var BackformControlInit = Backform.Control.prototype.initialize,
BackformControlRemove = Backform.Control.prototype.remove;
@@ -422,6 +434,48 @@ define([
},
});
+
+ Backform.RadioModernControl = Backform.RadioControl.extend({
+ defaults: {
+ controlLabelClassName: Backform.controlLabelClassName,
+ controlsClassName: Backform.controlsClassName,
+ extraClasses: [],
+ helpMessage: '',
+ name: '',
+ },
+ template: _.template([
+ '<label class="<%=controlLabelClassName%>"><%=label%></label>',
+ '<div class="<%=controlsClassName%> <%=extraClasses.join(\' \')%>">',
+ ' <div class="btn-group pgadmin-controls-radio-none" data-toggle="buttons">',
+ ' <% for (var i=0; i < options.length; i++) { %>',
+ ' <% var option = options[i]; %>',
+ ' <label class="btn btn-primary<% if (option.value == value) { %> active<%}%>" tabindex="0">',
+ ' <input type="radio" name="<%=name%>" autocomplete="off" value=<%-formatter.fromRaw(option.value)%> <% if (option.value == value) { %> checked<%}%> > <%-option.label%>',
+ ' </label>',
+ ' <% } %>',
+ ' </div>',
+ ' <% if (helpMessage && helpMessage.length) { %>',
+ ' <span class="<%=Backform.helpMessageClassName%>"><%=helpMessage%></span>',
+ ' <% } %>',
+ '</div>',
+ ].join('\n')),
+ formatter: RawFormatter,
+ getValueFromDOM: function() {
+ return this.formatter.toRaw(this.$el.find('input[type="radio"]:checked').attr('value'), this.model);
+ },
+ render: function() {
+ Backform.RadioControl.prototype.render.apply(this, arguments);
+ this.$el.find('.btn').on('keyup', (e)=>{
+ switch(e.keyCode) {
+ case 32: /* Spacebar click */
+ $(e.currentTarget).trigger('click');
+ break;
+ }
+ });
+ return this;
+ },
+ });
+
// Requires the Bootstrap Switch to work.
Backform.SwitchControl = Backform.InputControl.extend({
defaults: {
diff --git a/web/pgadmin/static/scss/_bootstrap.overrides.scss b/web/pgadmin/static/scss/_bootstrap.overrides.scss
index ed16ec82..55fc5afa 100644
--- a/web/pgadmin/static/scss/_bootstrap.overrides.scss
+++ b/web/pgadmin/static/scss/_bootstrap.overrides.scss
@@ -310,3 +310,8 @@ td.switch-cell > div.toggle {
.btn.disabled, .btn:disabled, .btn[disabled] {
opacity: $btn-disabled-opacity;
}
+
+.btn-group label.btn.btn-primary.active {
+ background-color: $color-primary-light;
+ color: $color-primary;
+}
diff --git a/web/pgadmin/tools/maintenance/static/js/maintenance.js b/web/pgadmin/tools/maintenance/static/js/maintenance.js
index 2311b506..abe8701e 100644
--- a/web/pgadmin/tools/maintenance/static/js/maintenance.js
+++ b/web/pgadmin/tools/maintenance/static/js/maintenance.js
@@ -51,8 +51,11 @@ define([
id: 'op',
label: gettext('Maintenance operation'),
cell: 'string',
- type: 'text',
+ type: 'radioModern',
+ controlsClassName: 'pgadmin-controls col-12 col-sm-8',
+ controlLabelClassName: 'control-label col-sm-4 col-12',
group: gettext('Options'),
+ value: 'VACUUM',
options: [{
'label': 'VACUUM',
'value': 'VACUUM',
@@ -70,30 +73,6 @@ define([
'value': 'CLUSTER',
},
],
- control: Backform.RadioControl.extend({
- template: _.template([
- '<label class="control-label col-sm-4 col-12"><%=label%></label>',
- '<div class="pgadmin-controls col-12 col-sm-8 btn-group pg-maintenance-op pgadmin-controls-radio-none" data-toggle="buttons">',
- ' <% for (var i=0; i < options.length; i++) { %>',
- ' <% var option = options[i]; %>',
- ' <label class="btn btn-primary<% if (i == 0) { %> active<%}%>" tabindex="0">',
- ' <input type="radio" name="op" id="op" autocomplete="off" value=<%-formatter.fromRaw(option.value)%><% if (i == 0) { %> selected<%}%> > <%-option.label%>',
- ' </label>',
- ' <% } %>',
- '</div>',
- ].join('\n')),
- render: function() {
- Backform.RadioControl.prototype.render.apply(this, arguments);
- this.$el.find('.pg-maintenance-op .btn').on('keyup', (e)=>{
- switch(e.keyCode) {
- case 32: /* Spacebar click */
- $(e.currentTarget).trigger('click');
- break;
- }
- });
- return this;
- },
- }),
},
{
type: 'nested',
diff --git a/web/pgadmin/tools/maintenance/static/scss/_maintenance.scss b/web/pgadmin/tools/maintenance/static/scss/_maintenance.scss
deleted file mode 100644
index 98f8a04c..00000000
--- a/web/pgadmin/tools/maintenance/static/scss/_maintenance.scss
+++ /dev/null
@@ -1,4 +0,0 @@
-.btn-group.pg-maintenance-op label.btn.btn-primary.active {
- background-color: $color-primary-light;
- color: $color-primary;
-}
diff --git a/web/pgadmin/utils/preferences.py b/web/pgadmin/utils/preferences.py
index 656f4463..ec484d2e 100644
--- a/web/pgadmin/utils/preferences.py
+++ b/web/pgadmin/utils/preferences.py
@@ -428,7 +428,7 @@ class Preferences(object):
assert _type is not None, "Type for a preference cannot be none!"
assert _type in (
'boolean', 'integer', 'numeric', 'date', 'datetime',
- 'options', 'multiline', 'switch', 'node', 'text',
+ 'options', 'multiline', 'switch', 'node', 'text', 'radioModern',
'keyboardshortcut'
), "Type cannot be found in the defined list!"
diff --git a/web/regression/javascript/browser/layout_spec.js b/web/regression/javascript/browser/layout_spec.js
new file mode 100644
index 00000000..c1e6709d
--- /dev/null
+++ b/web/regression/javascript/browser/layout_spec.js
@@ -0,0 +1,109 @@
+/////////////////////////////////////////////////////////////
+//
+// pgAdmin 4 - PostgreSQL Tools
+//
+// Copyright (C) 2013 - 2019, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+//////////////////////////////////////////////////////////////
+
+import {pgBrowser} from 'pgadmin.browser.layout';
+import 'wcdocker';
+
+var wcDocker = window.wcDocker;
+
+describe('layout related functions test', function() {
+ let menu_items = null;
+ let dummy_cache = [{
+ id: 2,
+ mid: 1,
+ module:'browser',
+ name:'lock_layout',
+ value: 'none',
+ }];
+
+ beforeEach(function(){
+ pgBrowser.preferences_cache = dummy_cache;
+ pgBrowser.docker = {
+ 'lockLayout': ()=>{},
+ };
+
+ _.extend(pgBrowser,{
+ 'menus': {
+ 'file': {
+ 'mnu_locklayout': {
+ 'menu_items': [
+ {'name': 'mnu_lock_none', change_checked: ()=> {}},
+ {'name': 'mnu_lock_docking', change_checked: ()=> {}},
+ {'name': 'mnu_lock_full', change_checked: ()=> {}},
+ ],
+ },
+ },
+ },
+ });
+
+ menu_items = pgBrowser.menus.file.mnu_locklayout.menu_items;
+ });
+
+ describe('for menu actions', function() {
+ beforeEach(function(){
+ spyOn(pgBrowser, 'lock_layout');
+ spyOn(pgBrowser, 'save_lock_layout');
+ });
+
+ it('mnu_lock_none', function() {
+ pgBrowser.mnu_lock_none();
+ expect(pgBrowser.lock_layout).toHaveBeenCalledWith(pgBrowser.docker, 'none');
+ expect(pgBrowser.save_lock_layout).toHaveBeenCalledWith('none');
+ });
+
+ it('mnu_lock_docking', function() {
+ pgBrowser.mnu_lock_docking();
+ expect(pgBrowser.lock_layout).toHaveBeenCalledWith(pgBrowser.docker, 'docking');
+ expect(pgBrowser.save_lock_layout).toHaveBeenCalledWith('docking');
+ });
+
+ it('mnu_lock_full', function() {
+ pgBrowser.mnu_lock_full();
+ expect(pgBrowser.lock_layout).toHaveBeenCalledWith(pgBrowser.docker, 'full');
+ expect(pgBrowser.save_lock_layout).toHaveBeenCalledWith('full');
+ });
+ });
+
+ describe('lock_layout', function() {
+ let change_checked_test= function(menu_name) {
+ for(let i=0; i<menu_items.length; i++) {
+ if(menu_items[i].name == menu_name) {
+ expect(menu_items[i].change_checked).toHaveBeenCalledWith(true);
+ } else {
+ expect(menu_items[i].change_checked).toHaveBeenCalledWith(false);
+ }
+ }
+ };
+
+ beforeEach(function(){
+ spyOn(pgBrowser.docker, 'lockLayout');
+ for(let i=0; i<menu_items.length; i++) {
+ spyOn(menu_items[i], 'change_checked');
+ }
+ });
+
+ it('none', function() {
+ pgBrowser.lock_layout(pgBrowser.docker, 'none');
+ expect(pgBrowser.docker.lockLayout).toHaveBeenCalledWith(wcDocker.LOCK_LAYOUT_LEVEL.NONE);
+ change_checked_test('mnu_lock_none');
+ });
+
+ it('docking', function() {
+ pgBrowser.lock_layout(pgBrowser.docker, 'docking');
+ expect(pgBrowser.docker.lockLayout).toHaveBeenCalledWith(wcDocker.LOCK_LAYOUT_LEVEL.PREVENT_DOCKING);
+ change_checked_test('mnu_lock_docking');
+ });
+
+ it('full', function() {
+ pgBrowser.lock_layout(pgBrowser.docker, 'full');
+ expect(pgBrowser.docker.lockLayout).toHaveBeenCalledWith(wcDocker.LOCK_LAYOUT_LEVEL.FULL);
+ change_checked_test('mnu_lock_full');
+ });
+ });
+});
diff --git a/web/webpack.shim.js b/web/webpack.shim.js
index 0d86dcc8..8f43b2a3 100644
--- a/web/webpack.shim.js
+++ b/web/webpack.shim.js
@@ -190,6 +190,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.layout': path.join(__dirname, './pgadmin/browser/static/js/layout'),
'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',
diff --git a/web/webpack.test.config.js b/web/webpack.test.config.js
index d19df929..f19d666c 100644
--- a/web/webpack.test.config.js
+++ b/web/webpack.test.config.js
@@ -72,6 +72,7 @@ module.exports = {
alias: {
'top': path.join(__dirname, './pgadmin'),
'jquery': path.join(__dirname, './node_modules/jquery/dist/jquery'),
+ 'wcdocker': path.join(__dirname, './node_modules/webcabin-docker/Build/wcDocker'),
'alertify': path.join(__dirname, './node_modules/alertifyjs/build/alertify'),
'jquery.event.drag': path.join(__dirname, './node_modules/slickgrid/lib/jquery.event.drag-2.3.0'),
'jquery.ui': path.join(__dirname, './node_modules/slickgrid/lib/jquery-ui-1.11.3'),
@@ -100,6 +101,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.layout': path.join(__dirname, './pgadmin/browser/static/js/layout'),
'pgadmin.browser.preferences': path.join(__dirname, './pgadmin/browser/static/js/preferences'),
'bundled_codemirror': path.join(__dirname, './pgadmin/static/bundle/codemirror'),
},
diff --git a/web/yarn.lock b/web/yarn.lock
index ca944d33..6a00fb83 100644
--- a/web/yarn.lock
+++ b/web/yarn.lock
@@ -8508,9 +8508,9 @@ watchpack@^1.5.0:
graceful-fs "^4.1.2"
neo-async "^2.5.0"
-"webcabin-docker@git+https://github.com/EnterpriseDB/wcDocker/#e191a1063c111d5542ff26a7c163940be180333d":
+"webcabin-docker@git+https://github.com/EnterpriseDB/wcDocker/#f3c79e4b9a9e76a8e34736fc33473e65c524050c":
version "2.2.4-dev"
- resolved "git+https://github.com/EnterpriseDB/wcDocker/#e191a1063c111d5542ff26a7c163940be180333d"
+ resolved "git+https://github.com/EnterpriseDB/wcDocker/#f3c79e4b9a9e76a8e34736fc33473e65c524050c"
dependencies:
FileSaver "^0.10.0"
font-awesome "^4.7.0"
view thread (4+ messages) latest in thread
reply
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: [email protected]
Cc: [email protected]
Subject: Re: [pgAdmin][RM2653] Lock layout
In-Reply-To: <CAM9w-_n-1EKo44GctmEKy=SFRVK04a6yKGoQnawCq47X1FX=eA@mail.gmail.com>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox