Clear the node cache, when an node is created/updated to make sure - we

will always have latest data related to that type of node. Also, fixed
the cache_level for different node types.

This commit also contains fixes for the following issue:
* In extension module - use the 'node-list-by-name' instead of using a
  custom 'node-ajax-options' control, and removed redundant template
  schemas from it.
* When we tries to destroy the select2 object from
  Select2Cell/Select2Control while releasing the properties view,
  sometimes select2 can not find the instance related it for some
  unknown reason. Hence - before removing it we will check for manual
  instance existance using $.data('select2').
* When we traverse through the browser tree nodes very quickly, it tries
  to remove the object before it gets created completely, and results
  into an exception.
* Icon in the select2 drop down list was not visible due to some CSS
  issues.

Apart of that, we will generate two new browser events -
'pgadmin-node:created:<NODE-TYPE>', 'pgadmin-node:updated:<NODE-TYPE>'
whenever a new node is created, or an existing node will be updated.
This commit is contained in:
Ashesh Vashi 2016-04-29 15:41:24 +05:30
parent dac514a4ae
commit 32e0a0d4b6
14 changed files with 148 additions and 66 deletions

View File

@ -173,27 +173,20 @@ function($, _, S, pgAdmin, pgBrowser) {
},
{
id: 'owner', label:'{{ _('Owner') }}', control: 'node-list-by-name',
mode: ['properties'], node: 'role', cell: 'string'
mode: ['properties'], node: 'role', cell: 'string',
cache_level: 'server'
},
{
id: 'schema', label: '{{ _('Schema')}}', type: 'text', control: 'node-ajax-options',
mode: ['properties', 'create', 'edit'], group: '{{ _('Definition')}}', deps: ['relocatable'],
url: 'schemas', first_empty: true, disabled: function(m) {
id: 'schema', label: '{{ _('Schema')}}', type: 'text',
control: 'node-list-by-name', group: '{{ _('Definition')}}',
mode: ['properties', 'create', 'edit'], deps: ['relocatable'],
node: 'schema', first_empty: true,
disabled: function(m) {
/*
* enable or disable schema field if model's relocatable
* attribute is True or False
*/
return (m.has('relocatable') ? !m.get('relocatable') : false);
},
transform: function(data) {
var res = [];
if (data && _.isArray(data)) {
_.each(data, function(d) {
res.push({label: d.schema, value: d.schema});
})
}
return res;
}
},
{

View File

@ -1,3 +0,0 @@
{#===================fetch all schemas==========================#}
SELECT nspname As schema FROM pg_namespace
ORDER BY nspname

View File

@ -62,7 +62,7 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
lc_collate: undefined,
description: undefined
},
// Default values!
initialize: function(attrs, args) {
var isNew = (_.size(attrs) === 0);
@ -76,7 +76,7 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
}
pgAdmin.Browser.Node.Model.prototype.initialize.apply(this, arguments);
},
schema: [{
id: 'name', label: '{{ _('Name') }}', cell: 'string',
type: 'text', mode: ['properties', 'create', 'edit'],
@ -87,7 +87,8 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
},{
id: 'owner', label:'{{ _('Owner') }}', cell: 'string',
type: 'text', mode: ['properties', 'create', 'edit'],
disabled: 'inSchema', control: 'node-list-by-name', node: 'role'
disabled: 'inSchema', control: 'node-list-by-name',
node: 'role'
},{
id: 'schema', label:'{{ _('Schema') }}', cell: 'string',
type: 'text', mode: ['create', 'edit'], node: 'schema',

View File

@ -205,10 +205,12 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
id: 'description', label:'{{ _('Comment') }}', cell: 'string',
type: 'multiline'
},{
id: 'basetype', label:'{{ _('Base type') }}', cell: 'string', control: 'node-ajax-options',
type: 'text', mode:['properties', 'create', 'edit'], group: '{{ _('Definition') }}', url: 'get_types',
disabled: function(m) { return !m.isNew(); }, first_empty: true,
transform: function(d){
id: 'basetype', label:'{{ _('Base type') }}', cell: 'string',
control: 'node-ajax-options', type: 'text', url: 'get_types',
mode:['properties', 'create', 'edit'], group: '{{ _('Definition') }}',
cache_level: 'database', cache_node: 'schema', disabled: function(m) {
return !m.isNew();
}, first_empty: true, transform: function(d) {
this.model.type_options = d;
return d;
}
@ -279,8 +281,10 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
'size': 'small'
}
},{
id: 'collname', label:'{{ _('Collation') }}', cell: 'string', control: 'node-ajax-options',
type: 'text', group: '{{ _('Definition') }}', url: 'get_collations', disabled: function(m) {
id: 'collname', label:'{{ _('Collation') }}', cell: 'string',
control: 'node-ajax-options', type: 'text', url: 'get_collations',
group: '{{ _('Definition') }}', cache_level: 'database',
cache_node: 'schema', disabled: function(m) {
return !m.isNew();
}
},{

View File

@ -126,14 +126,15 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
},{
id: 'schema', label: '{{ _('Schema')}}', cell: 'string',
type: 'text', mode: ['create','edit'], node: 'schema',
control: 'node-list-by-id'
cache_node: 'database', control: 'node-list-by-id'
},{
id: 'description', label:'{{ _('Comment') }}', cell: 'string',
type: 'multiline', cellHeaderClasses: 'width_percent_50'
},{
id: 'template', label: '{{ _('Template')}}',type: 'text',
disabled: function(m) { return !m.isNew(); }, url: 'fetch_templates',
group: '{{ _('Definition') }}',control: 'node-ajax-options'
group: '{{ _('Definition') }}', control: 'node-ajax-options',
cache_node: 'database'
},{
id: 'options', label: '{{ _('Option') }}', type: 'collection',
group: '{{ _('Options') }}', control: 'unique-col-collection',
@ -182,4 +183,4 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
}
return pgBrowser.Nodes['coll-fts_dictionary'];
});
});

View File

@ -93,27 +93,33 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
id: 'prsstart', label: '{{ _('Start function')}}',
type: 'text', disabled: function(m) { return !m.isNew(); },
control: 'node-ajax-options', url: 'start_functions',
group: '{{ _('Definition') }}'
group: '{{ _('Definition') }}', cache_level: 'database',
cache_node: 'schema'
},{
id: 'prstoken', label: '{{ _('Get next token function')}}',
type: 'text', disabled: function(m) { return !m.isNew(); },
control: 'node-ajax-options', url: 'token_functions',
group: '{{ _('Definition') }}'
group: '{{ _('Definition') }}', cache_level: 'database',
cache_node: 'schema'
},{
id: 'prsend', label: '{{ _('End function')}}',
type: 'text', disabled: function(m) { return !m.isNew(); },
control: 'node-ajax-options', url: 'end_functions',
group: '{{ _('Definition') }}'
group: '{{ _('Definition') }}', cache_level: 'database',
cache_node: 'schema',
cache_node: 'schema'
},{
id: 'prslextype', label: '{{ _('Lextypes function')}}',
type: 'text', disabled: function(m) { return !m.isNew(); },
control: 'node-ajax-options', url: 'lextype_functions',
group: '{{ _('Definition') }}'
group: '{{ _('Definition') }}', cache_level: 'database',
cache_node: 'schema'
},{
id: 'prsheadline', label: '{{ _('Headline function')}}',
type: 'text', disabled: function(m) { return !m.isNew(); },
control: 'node-ajax-options', url: 'headline_functions',
group: '{{ _('Definition') }}'
group: '{{ _('Definition') }}', cache_level: 'database',
cache_node: 'schema'
}],
/*
@ -192,4 +198,4 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
}
return pgBrowser.Nodes['coll-fts_parser'];
});
});

View File

@ -83,13 +83,16 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
id: 'description', label:'{{ _('Comment') }}', cell: 'string',
type: 'multiline', cellHeaderClasses: 'width_percent_50'
},{
id: 'tmplinit', label: '{{ _('Init function')}}', group: '{{ _('Definition') }}',
type: 'text', disabled: function(m) { return !m.isNew(); },
control: 'node-ajax-options', url: 'get_init'
id: 'tmplinit', label: '{{ _('Init function')}}',
group: '{{ _('Definition') }}', type: 'text', disabled: function(m) {
return !m.isNew();
}, control: 'node-ajax-options', url: 'get_init',
cache_level: 'database', cache_node: 'schema'
},{
id: 'tmpllexize', label: '{{ _('Lexize function')}}', group: '{{ _('Definition') }}',
type: 'text', disabled: function(m) { return !m.isNew(); },
control: 'node-ajax-options', url: 'get_lexize'
control: 'node-ajax-options', url: 'get_lexize', cache_level: 'database',
cache_node: 'schema'
}],
/*
@ -132,4 +135,4 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
}
return pgBrowser.Nodes['coll-fts_template'];
});
});

View File

@ -257,12 +257,12 @@ function($, _, S, pgAdmin, pgBrowser, Alertify) {
id: 'encoding', label: '{{ _('Encoding') }}',
editable: false, type: 'text', group: 'Definition',
disabled: function(m) { return !m.isNew(); }, url: 'get_encodings',
control: 'node-ajax-options'
control: 'node-ajax-options', cache_level: 'server'
},{
id: 'template', label: '{{ _('Template') }}',
editable: false, type: 'text', group: 'Definition',
disabled: function(m) { return !m.isNew(); },
control: 'node-list-by-name', node: 'database'
control: 'node-list-by-name', node: 'database', cache_level: 'server'
},{
id: 'spcname', label: '{{ _('Tablespace') }}',
editable: false, type: 'text', group: 'Definition',
@ -275,12 +275,12 @@ function($, _, S, pgAdmin, pgBrowser, Alertify) {
id: 'datcollate', label: '{{ _('Collation') }}',
editable: false, type: 'text', group: 'Definition',
disabled: function(m) { return !m.isNew(); }, url: 'get_ctypes',
control: 'node-ajax-options'
control: 'node-ajax-options', cache_level: 'server'
},{
id: 'datctype', label: '{{ _('Character Type') }}',
editable: false, type: 'text', group: 'Definition',
disabled: function(m) { return !m.isNew(); }, url: 'get_ctypes',
control: 'node-ajax-options'
control: 'node-ajax-options', cache_level: 'server'
},{
id: 'datconnlimit', label: '{{ _('Connection Limit') }}',
editable: false, type: 'int', group: 'Definition', min: -1

View File

@ -3,7 +3,7 @@ SELECT
has_database_privilege(db.oid, 'CREATE') as cancreate, datdba as owner
FROM
pg_database db
LEFT OUTER JOIN pg_tablespace ta ON db.dattablespace = ta.oid{% if did %}
LEFT OUTER JOIN pg_tablespace ta ON db.dattablespace = ta.oid
WHERE {% if did %}
db.oid = {{ did|qtLiteral }}::OID{% else %}
db.oid > {{ last_system_oid }}::OID

View File

@ -79,22 +79,28 @@ function($, _, pgAdmin, Backbone, Backform, Alertify, Node) {
if (url) {
var node = this.field.get('schema_node'),
node_info = this.field.get('node_info'),
with_id = this.field.get('url_with_id') || false,
full_url = node.generate_url.apply(
node, [
null, url, this.field.get('node_data'),
this.field.get('url_with_id') || false, node_info
null, url, this.field.get('node_data'), with_id, node_info
]),
cache_level = this.field.get('cache_level') || node.type,
cache_level,
cache_node = this.field.get('cache_node');
cache_node = (cache_node && pgAdmin.Browser.Nodes['cache_node']) || node;
if (this.field.has('cache_level')) {
cache_level = this.field.get('cache_level');
} else {
cache_level = cache_node.cache_level(node_info, with_id);
}
/*
* 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);
var data = cache_node.cache(node.type + '#' + url, node_info, cache_level);
if (this.field.get('version_compatible') &&
(_.isUndefined(data) || _.isNull(data))) {
@ -107,7 +113,7 @@ function($, _, pgAdmin, Backbone, Backform, Alertify, Node) {
* 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);
data = cache_node.cache(node.type + '#' + url, node_info, cache_level, res.data);
},
error: function() {
m.trigger('pgadmin:view:fetch:error', m, self.field);
@ -341,22 +347,28 @@ function($, _, pgAdmin, Backbone, Backform, Alertify, Node) {
eventHandler = m.top || m,
node = column.get('schema_node'),
node_info = column.get('node_info'),
with_id = column.get('url_with_id') || false,
full_url = node.generate_url.apply(
node, [
null, url, column.get('node_data'),
column.get('url_with_id') || false, node_info
null, url, column.get('node_data'), with_id, node_info
]),
cache_level = column.get('cache_level') || node.type,
cache_level,
cache_node = column.get('cache_node');
cache_node = (cache_node && pgAdmin.Browser.Nodes['cache_node']) || node;
if (this.field.has('cache_level')) {
cache_level = this.field.get('cache_level');
} else {
cache_level = cache_node.cache_level(node_info, with_id);
}
/*
* 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);
var data = cache_node.cache(node.type + '#' + url, node_info, cache_level);
if (column.get('version_compatible') &&
(_.isUndefined(data) || _.isNull(data))) {
@ -369,7 +381,7 @@ function($, _, pgAdmin, Backbone, Backform, Alertify, Node) {
* 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);
data = cache_node.cache(node.type + '#' + url, node_info, cache_level, res.data);
},
error: function() {
eventHandler.trigger('pgadmin:view:fetch:error', m, column);

View File

@ -903,9 +903,12 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, pgBrowser, Backform) {
// Closing this panel
this.close();
}.bind(panel),
updateTreeItem = function() {
updateTreeItem = function(that) {
var panel = this;
// Clear the cache for this node now.
setTimeout(function() { that.clear_cache.apply(that, item); }, 0);
// Update the item lable (if label is modified.)
if (view.model.tnode) {
var itemData = tree.itemData(item),
@ -925,11 +928,18 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, pgBrowser, Backform) {
tree.deselect(item);
panel.$container.removeAttr('action-mode');
setTimeout(function() { closePanel(); }, 0);
setTimeout(function() { tree.select(item, {focus: true}); }, 10);
pgBrowser.Events.trigger(
'pgadmin-node:updated:' + that.type, item, that
);
},
saveNewNode = function() {
saveNewNode = function(that) {
var panel = this;
// Clear the cache for this node now.
setTimeout(function() { that.clear_cache.apply(that, item); }, 0);
/* TODO:: Create new tree node for this */
if (view.model.tnode && '_id' in view.model.tnode) {
var d = _.extend({}, view.model.tnode),
@ -938,6 +948,9 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, pgBrowser, Backform) {
if (i) {
tree.select(i, {focus: true});
}
pgBrowser.Events.trigger(
'pgadmin-node:created:' + that.type, i, that
);
}, found = false;
delete view.model.tnode;
@ -1092,9 +1105,15 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, pgBrowser, Backform) {
tree.open(item, {
success: function (item, options){
setTimeout(function() {closePanel();}, 0);
pgBrowser.Events.trigger(
'pgadmin-node:created:' + that.type, item, that
);
},
fail: function (item, options){
setTimeout(function() {closePanel();}, 0);
pgBrowser.Events.trigger(
'pgadmin-node:created:' + that.type, item, that
);
},
unanimated: animation
});
@ -1125,7 +1144,7 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, pgBrowser, Backform) {
}
setTimeout(function() {closePanel();}, 0);
}
}.bind(panel),
}.bind(panel, that),
editInNewPanel = function() {
// Open edit in separate panel
setTimeout(function() {
@ -1136,7 +1155,7 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, pgBrowser, Backform) {
}, 0);
},
onCancelFunc = closePanel,
onSaveFunc = updateTreeItem.bind(panel),
onSaveFunc = updateTreeItem.bind(panel, that),
onEdit = editFunc.bind(panel);
if (action) {
@ -1280,12 +1299,45 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, pgBrowser, Backform) {
}
if (_.isUndefined(data)) {
return cached[hash];
var res = cached[hash];
if (!_.isUndefined(res) &&
(res.at - Date.now() > 300000)) {
res = undefined;
}
return res;
}
var res = cached[hash] = {data: data, at: Date(), level: level};
res = cached[hash] = {data: data, at: Date.now(), level: level};
return res;
},
clear_cache: function(item) {
/*
* Reset the cache, when new node is created.
*
* FIXME:
* At the moment, we will clear all the cache for this node. But - we
* would like to clear the cache only this nodes parent, so that - it
* fetches the new data.
*/
this.cached = {};
},
cache_level: function(node_info, with_id) {
if (node_info) {
if (with_id && this.type in node_info) {
return this.type;
}
if (_.isArray(this.parent_type)) {
for (var parent in this.parent_type) {
if (parent in node_info) {
return parent;
}
}
return this.type;
}
return this.parent_type;
}
}
});

View File

@ -947,6 +947,11 @@ ul.nav.nav-tabs {
padding-left: 20px;
}
.select2-results span.wcTabIcon {
padding-left: 20px;
background-position: 0px 2px;
}
.pgadmin-controls.SQL>.CodeMirror {
height: 500px!important;
}

View File

@ -1993,13 +1993,15 @@
// Refresh SQL Field to refresh the control lazily after it renders
setTimeout(function() {
self.refreshTextArea.apply(self);
}, 100);
}, 0);
return self;
},
refreshTextArea: function() {
this.sqlCtrl.refresh();
if (this.sqlCtrl) {
this.sqlCtrl.refresh();
}
},
remove: function() {

View File

@ -450,7 +450,11 @@
this.undelegateEvents();
if (this.$select) {
this.$select.select2('destroy');
if ( this.$select.data('select2')) {
this.$select.select2('destroy');
}
delete this.$select;
this.$select = null;
}
this.$el.empty();
@ -530,7 +534,9 @@
remove: function() {
this.$select.off('change', this.onSave);
this.$select.select2('destroy');
if (this.$select.data('select2')) {
this.$select.select2('destroy');
}
this.$el.empty();
Backgrid.SelectCell.prototype.remove.apply(this, arguments);
}