Hi, Please find the attached path for Privilege control with select2cell for user role section
TODO: Need to add current database logged in user in Granter filed in privilege grid control. -- *Harshal Dhumal* *Software Engineer * EenterpriseDB <http://www.enterprisedb.com>
diff --git a/web/pgadmin/browser/server_groups/servers/__init__.py b/web/pgadmin/browser/server_groups/servers/__init__.py index c38265d..04156ee 100644 --- a/web/pgadmin/browser/server_groups/servers/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/__init__.py @@ -115,7 +115,8 @@ class ServerModule(sg.ServerGroupPluginModule): { 'name': 'pgadmin.browser.server.privilege', 'path': url_for('browser.index') + 'server/static/js/privilege', - 'when': self.node_type + 'when': self.node_type, + 'deps': ['pgadmin.browser.node.ui'] }, { 'name': 'pgadmin.browser.server.variable', diff --git a/web/pgadmin/browser/server_groups/servers/static/js/privilege.js b/web/pgadmin/browser/server_groups/servers/static/js/privilege.js index 2f6f052..651f837 100644 --- a/web/pgadmin/browser/server_groups/servers/static/js/privilege.js +++ b/web/pgadmin/browser/server_groups/servers/static/js/privilege.js @@ -5,7 +5,7 @@ function(_, $, Backbone, Backform, Backgrid, Alertify, pgNode) { // Export global even in AMD case in case this script is loaded with // others that may still expect a global Backform. - return factory(root, _, $, Backbone, Backform, Alertify, pgNode); + return factory(root, _, $, Backbone, Backform, Backgrid, Alertify, pgNode); }); // Next for Node.js or CommonJS. jQuery may not be needed as a module. @@ -14,15 +14,16 @@ $ = root.jQuery || root.$ || root.Zepto || root.ender, Backbone = require('backbone') || root.Backbone, Backform = require('backform') || root.Backform; + Backgrid = require('backgrid') || root.Backgrid; Alertify = require('alertify') || root.Alertify; pgAdmin = require('pgadmin.browser.node') || root.pgAdmin.Browser.Node; factory(root, _, $, Backbone, Backform, Alertify, pgNode); // Finally, as a browser global. } else { - factory(root, root._, (root.jQuery || root.Zepto || root.ender || root.$), root.Backbone, root.Backform, root.pgAdmin.Browser.Node); + factory(root, root._, (root.jQuery || root.Zepto || root.ender || root.$), root.Backbone, root.Backform, root.Backgrid, root.alertify, root.pgAdmin.Browser.Node); } -} (this, function(root, _, $, Backbone, Backform, Alertify, pgNode) { +} (this, function(root, _, $, Backbone, Backform, Backgrid, Alertify, pgNode) { /** * Each Privilege, supporeted by an database object, will be represented @@ -66,15 +67,39 @@ privileges:[], schema: [{ - id: 'grantee', label:'Grantee', type:'text', group: null, cell: 'string', - disabled: true, cellHeaderClasses: 'width_percent_40' + id: 'grantee', label:'Grantee', type:'text', group: null, + editable: true, cellHeaderClasses: 'width_percent_40', + cell: 'node-list-by-name', node: 'role', + disabled : function(column, collection) { + if (column instanceof Backbone.Collection) { + // This has been called during generating the header cell + return false; + } + return !(this.node_info && this.node_info.server.user.name == column.get('grantor')); + }, + transform: function(data) { + var res = + Backgrid.Extension.NodeListByNameCell.prototype.defaults.transform.apply( + this, arguments + ); + res.unshift({label: 'public', value: 'public'}); + return res; + } }, { id: 'privileges', label:'Privileges', type: 'collection', model: PrivilegeModel, group: null, - disabled: false, cell: 'privilege', control: 'text', - cellHeaderClasses: 'width_percent_40' + cell: 'privilege', control: 'text', cellHeaderClasses: 'width_percent_40', + disabled : function(column, collection) { + if (column instanceof Backbone.Collection) { + // This has been called during generating the header cell + return false; + } + return !(this.node_info && this.node_info.server.user.name == column.get('grantor') || + this.attributes.node_info.server.user.name == column.get('grantor')); + } },{ - id: 'grantor', label: 'Granter', type: 'text', disabled: true + id: 'grantor', label: 'Granter', type: 'text', disabled: true, + cell: 'node-list-by-name', node: 'role' }], /* diff --git a/web/pgadmin/browser/static/js/node.ui.js b/web/pgadmin/browser/static/js/node.ui.js index 7642a47..e38adcb 100644 --- a/web/pgadmin/browser/static/js/node.ui.js +++ b/web/pgadmin/browser/static/js/node.ui.js @@ -4,7 +4,6 @@ function($, _, pgAdmin, Backbone, Backform, Alertify, Node) { var pgBrowser = pgAdmin.Browser; - // Store value in DOM as stringified JSON. var StringOrJSONFormatter = function() {}; _.extend(StringOrJSONFormatter.prototype, { @@ -183,7 +182,7 @@ function($, _, pgAdmin, Backbone, Backform, Alertify, Node) { var NodeListByIdControl = Backform.NodeListByIdControl = NodeAjaxOptionsControl.extend({ controlClassName: 'pgadmin-node-select form-control', - defaults: _.extend(NodeAjaxOptionsControl.prototype.defaults, { + defaults: _.extend({}, NodeAjaxOptionsControl.prototype.defaults, { first_empty: true, empty_value: '-- None --', url: 'nodes', @@ -229,7 +228,7 @@ function($, _, pgAdmin, Backbone, Backform, Alertify, Node) { var NodeListByNameControl = Backform.NodeListByNameControl = NodeListByIdControl.extend({ - defaults: _.extend(NodeListByIdControl.prototype.defaults, { + defaults: _.extend({}, NodeListByIdControl.prototype.defaults, { transform: function(rows) { var self = this, node = self.field.get('schema_node'), @@ -288,5 +287,273 @@ function($, _, pgAdmin, Backbone, Backform, Alertify, Node) { }); }; + + /* + * NodeAjaxOptionsCell + * This cell will fetch the options required to render the select + * cell, from the url specific to the pgAdmin.Browser node object. + * + * In order to use this properly, schema require to set the 'url' property, + * which exposes the data for this node. + * + * In case the url is not providing the data in proper format, we can + * specify the 'transform' function too, which will convert the fetched + * data to proper 'label', 'value' format. + */ + var NodeAjaxOptionsCell = Backgrid.Extension.NodeAjaxOptionsCell = Backgrid.Extension.Select2Cell.extend({ + defaults: _.extend({}, Backgrid.Extension.Select2Cell.prototype.defaults, { + url: undefined, + transform: undefined, + url_with_id: false, + select2: { + allowClear: true, + placeholder: 'Select from the list', + width: 'style' + } + }), + template: _.template( + '<option <% if (image) { %> data-image=<%= image %> <% } %> value="<%- value %>" <%= selected ? \'selected="selected"\' : "" %>><%- text %></option>' + ), + initialize: function () { + Backgrid.Extension.Select2Cell.prototype.initialize.apply(this, arguments); + + var col = _.defaults(this.column.toJSON(), this.defaults), + model = this.model, column = this.column, + editable = Backgrid.callByNeed(col.editable, column, model), + optionValues = _.clone(this.optionValues || this.column.get('options')); + + + var self = this, + url = self.column.get('url') || self.defaults.url, + m = self.model.handler || self.model; + + // Hmm - we found the url option. + // That means - we needs to fetch the options from that node. + if (url) { + var node = this.column.get('schema_node'), + node_info = this.column.get('node_info'), + full_url = node.generate_url.apply( + node, [ + null, url, this.column.get('node_data'), + this.column.get('url_with_id') || false, node_info + ]), + cache_level = this.column.get('cache_level') || node.type, + cache_node = this.column.get('cache_node'); + + cache_node = (cache_node && pgAdmin.Browser.Nodes['cache_node']) || node; + + /* + * We needs to check, if we have already cached data for this url. + * If yes - use that, and do not bother about fetching it again, + * and use it. + */ + var data = cache_node.cache(url, node_info, cache_level); + + if (this.column.get('version_compitible') && + (_.isUndefined(data) || _.isNull(data))) { + m.trigger('pgadmin:view:fetching', m, self.column); + $.ajax({ + async: false, + url: full_url, + success: function(res) { + /* + * We will cache this data for short period of time for avoiding + * same calls. + */ + data = cache_node.cache(url, node_info, cache_level, res.data); + }, + error: function() { + m.trigger('pgadmin:view:fetch:error', m, self.column); + } + }); + m.trigger('pgadmin:view:fetched', m, self.column); + } + // To fetch only options from cache, we do not need time from 'at' + // attribute but only options. + // + // It is feasible that the data may not have been fetched. + data = (data && data.data) || []; + + /* + * Transform the data + */ + transform = this.column.get('transform') || self.defaults.transform; + if (transform && _.isFunction(transform)) { + // We will transform the data later, when rendering. + // It will allow us to generate different data based on the + // dependencies. + self.column.set('options', transform.bind(self, data)); + } else { + self.column.set('options', data); + } + } + }, + render: function() { + /* + * Let SelectCell render it, we will do our magic on the + * select control in it. + */ + + var col = _.defaults(this.column.toJSON(), this.defaults), + model = this.model, column = this.column, + editable = Backgrid.callByNeed(col.editable, column, model), + optionValues = _.clone(this.optionValues || + _.isFunction(this.column.get('options')) ? + this.column.get('options').apply(this) : + this.column.get(' options')), + select2_opts = _.defaults({}, col.select2, this.defaults.select2), + evalF = function(f, col, m) { + return (_.isFunction(f) ? !!f.apply(col, [m]) : !!f); + }; + + this.$el.empty(); + + if (!_.isArray(optionValues)) throw new TypeError("optionValues must be an array"); + + /* + * Add empty option as Select2 requires any empty '<option><option>' for + * some of its functionality to work. + */ + optionValues.unshift({'label':null, 'value':null, 'image':null}); + + var optionText = null, + optionValue = null, + model = this.model, + selectedValues = model.get(this.column.get("name")); + + delete this.$select; + + this.$select = $("<select>", {tabIndex: -1}).appendTo(this.$el); + + for (var i = 0; i < optionValues.length; i++) { + var op = optionValues[i]; + + optionText = op['label']; + optionValue = op['value']; + optionImage = op['image']; + + this.$select.append( + this.template({ + text: optionText, + value: optionValue, + image: optionImage, + selected: (selectedValues == optionValue) || + (_.indexOf(selectedValues, optionValue) > -1) + })); + } + // Initialize select2 control. + this.$select.select2( + _.defaults( + {'disabled': !editable}, + col.select2, + this.defaults.select2 + )); + + /* + * If select2 options do not have any disabled property on this cell + * and schema has disabled property then we need to apply it + */ + if(!_.has(select2_opts, 'disabled') && (col && col.disabled)) { + _.extend(select2_opts, { + disabled: evalF(col.disabled, col, this.model) + }); + } + + this.$el.find("select").select2(select2_opts); + + this.delegateEvents(); + + return this; + } + }); + + var NodeListByIdCell = Backgrid.Extension.NodeListByIdCell = NodeAjaxOptionsCell.extend({ + controlClassName: 'pgadmin-node-select backgrid-cell', + defaults: _.extend({}, NodeAjaxOptionsCell.prototype.defaults, { + url: 'nodes', + filter: undefined, + transform: function(rows) { + var self = this, + node = self.column.get('schema_node'), + res = [], + filter = self.column.get('filter') || function() { return true; }; + + filter = filter.bind(self); + + _.each(rows, function(r) { + if (filter(r)) { + var l = (_.isFunction(node['node_label']) ? + (node['node_label']).apply(node, [r, self.model, self]) : + r.label), + image= (_.isFunction(node['node_image']) ? + (node['node_image']).apply( + node, [r, self.model, self] + ) : + (node['node_image'] || ('icon-' + node.type))); + + res.push({ + 'value': r._id, + 'image': image, + 'label': l + }); + } + }); + + return res; + }, + select2: { + placeholder: 'Select from the list', + width: 'style', + templateResult: formatNode, + templateSelection: formatNode + } + }) + }); + + + var NodeListByNameCell = Backgrid.Extension.NodeListByNameCell = NodeAjaxOptionsCell.extend({ + controlClassName: 'pgadmin-node-select backgrid-cell', + defaults: _.extend({}, NodeAjaxOptionsCell.prototype.defaults, { + url: 'nodes', + filter: undefined, + transform: function(rows) { + var self = this, + node = self.column.get('schema_node'), + res = [], + filter = self.column.get('filter') || function() { return true; }; + + filter = filter.bind(self); + + _.each(rows, function(r) { + if (filter(r)) { + var l = (_.isFunction(node['node_label']) ? + (node['node_label']).apply(node, [r, self.model, self]) : + r.label), + image= (_.isFunction(node['node_image']) ? + (node['node_image']).apply( + node, [r, self.model, self] + ) : + (node['node_image'] || ('icon-' + node.type))); + + res.push({ + 'value': r.label, + 'image': image, + 'label': l + }); + } + }); + + return res; + }, + select2: { + placeholder: 'Select from the list', + width: 'style', + templateResult: formatNode, + templateSelection: formatNode + } + }) + }); + + return Backform; }); diff --git a/web/pgadmin/browser/templates/browser/js/node.js b/web/pgadmin/browser/templates/browser/js/node.js index fe999bb..622e9e1 100644 --- a/web/pgadmin/browser/templates/browser/js/node.js +++ b/web/pgadmin/browser/templates/browser/js/node.js @@ -1289,7 +1289,7 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) { } idx = _.indexOf(self.sessAttrs['changed'], obj); if (!'sessChanged' in obj) { - if (idx > 0) { + if (idx >= 0) { return true; } self.sessAttrs['changed'].push(obj); @@ -1301,7 +1301,7 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, Backform) { return true; } - if (idx > 0) { + if (idx >= 0) { (self || self.handler).trigger( 'pgadmin-session:changed', diff --git a/web/pgadmin/static/js/backform.pgadmin.js b/web/pgadmin/static/js/backform.pgadmin.js index 42aaa55..e99c96e 100644 --- a/web/pgadmin/static/js/backform.pgadmin.js +++ b/web/pgadmin/static/js/backform.pgadmin.js @@ -76,6 +76,7 @@ 'uniqueColCollection': ['unique-col-collection', 'unique-col-collection', 'string'], 'switch' : 'switch', 'select2': 'select2', + 'radio' : 'radio' }; var getMappedControl = Backform.getMappedControl = function(type, mode) { @@ -724,7 +725,7 @@ * conflicting with another model value. */ - m.set(uniqueChangedAttr[0], m.previous(uniqueChangedAttr[0]), {silent: true}); + m.set(uniqueChangedAttr[0], m.previous(uniqueChangedAttr[0])); } if (oldModel) { var idx = collection.indexOf(oldModel); @@ -1204,7 +1205,7 @@ ); } - // After validation we need to set that value into model (only if all falgs are true) + // After validation we need to set that value into model (only if all flags are true) if (isValid) { this.stopListening(this.model, "change:" + name, this.render); this.model.set(name, value); diff --git a/web/pgadmin/static/js/backgrid/backgrid.pgadmin.js b/web/pgadmin/static/js/backgrid/backgrid.pgadmin.js index 85f99a6..b9a3f81 100644 --- a/web/pgadmin/static/js/backgrid/backgrid.pgadmin.js +++ b/web/pgadmin/static/js/backgrid/backgrid.pgadmin.js @@ -367,7 +367,7 @@ onSave: function (e) { var model = this.model; var column = this.column; - model.set(column.get("name"), this.$select.val(),{silent:true}); + model.set(column.get("name"), this.$select.val()); } }); return Backgrid;
-- Sent via pgadmin-hackers mailing list (pgadmin-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgadmin-hackers