Fixed all the review comments from Dave.

* Moved the Columns, and Constraint to its repective tabs.
* Ensure all the labels only have a capital letter on the first word
  (except for keywords or acronyms).
* Resolve the typo in string - 'System table'.
* Error messages on fields should not be shown unless the field loses
  focus and has an error.
* "General" section should have a limited subset of information.
* Variables grids should not be on the Security tab.
* Fixes the field labels that imply a question.
* Privileges controls on the Properties lists should be in a "Security"
  group.

Apart from review comments improved few other areas too:
* Used in-place DepsCell functionality for columns in both index, and
  type node.
* Improved the error handling in constraint nodes.
* Added create, alert SQL Help for nodes associated with the table node.
This commit is contained in:
Murtuza Zabuawala 2016-05-24 23:29:32 +05:30 committed by Ashesh Vashi
parent 8c077bc2df
commit af84ba5a4f
15 changed files with 584 additions and 402 deletions

View File

@ -15,33 +15,6 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
});
};
// Switch Cell for Primary Key selection
var SwitchDepCell = Backgrid.BooleanCell.extend({
initialize: function() {
Backgrid.BooleanCell.prototype.initialize.apply(this, arguments);
Backgrid.Extension.DependentCell.prototype.initialize.apply(this, arguments);
},
dependentChanged: function () {
var model = this.model,
column = this.column,
editable = this.column.get("editable"),
input = this.$el.find('input[type=checkbox]').first();
is_editable = _.isFunction(editable) ? !!editable.apply(column, [model]) : !!editable;
if (is_editable) {
this.$el.addClass("editable");
input.prop('disabled', false);
} else {
this.$el.removeClass("editable");
input.prop('disabled', true);
}
this.delegateEvents();
return this;
},
remove: Backgrid.Extension.DependentCell.prototype.remove
});
// This Node model will be used for variable control for column
var VariablesModel = Backform.VariablesModel = pgAdmin.Browser.Node.Model.extend({
defaults: {
@ -84,6 +57,8 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
type: 'column',
label: '{{ _('Column') }}',
hasSQL: true,
sqlAlterHelp: 'sql-altertable.html',
sqlCreateHelp: 'sql-altertable.html',
canDrop: function(itemData, item, data){
if (pgBrowser.Nodes['schema'].canChildDrop.apply(this, [itemData, item, data])) {
var t = pgBrowser.tree, i = item, d = itemData, parents = [];
@ -294,7 +269,9 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
});
flag && setTimeout(function() {
m.set('attlen', null);
if(m.get('attlen')) {
m.set('attlen', null);
}
},10);
return flag;
@ -317,8 +294,10 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
});
flag && setTimeout(function() {
if(m.get('attprecision')) {
m.set('attprecision', null);
},10);
}
},10);
return flag;
}
},{
@ -338,7 +317,9 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
});
if (flag) {
setTimeout(function(){
m.set('collspcname', "");
if(m.get('collspcname') && m.get('collspcname') !== '') {
m.set('collspcname', "");
}
}, 10);
}
return flag;
@ -371,16 +352,20 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
]
},{
id: 'is_pk', label:'{{ _('Primary key?') }}',
type: 'switch', disabled: true, mode: ['properties']
type: 'switch', disabled: true, mode: ['properties'],
group: '{{ _('Definition') }}'
},{
id: 'is_fk', label:'{{ _('Foreign key?') }}',
type: 'switch', disabled: true, mode: ['properties']
type: 'switch', disabled: true, mode: ['properties'],
group: '{{ _('Definition') }}'
},{
id: 'is_inherited', label:'{{ _('Inherited?') }}',
type: 'switch', disabled: true, mode: ['properties']
type: 'switch', disabled: true, mode: ['properties'],
group: '{{ _('Definition') }}'
},{
id: 'tbls_inherited', label:'{{ _('Inherited from table(s)') }}',
type: 'text', disabled: true, mode: ['properties'], deps: ['is_inherited'],
group: '{{ _('Definition') }}',
visible: function(m) {
if (!_.isUndefined(m.get('is_inherited')) && m.get('is_inherited')) {
return true;
@ -389,12 +374,18 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
}
}
},{
id: 'is_sys_column', label:'{{ _('System Column?') }}', cell: 'string',
id: 'is_sys_column', label:'{{ _('System column?') }}', cell: 'string',
type: 'switch', disabled: true, mode: ['properties']
},{
id: 'description', label:'{{ _('Comment') }}', cell: 'string',
type: 'multiline', mode: ['properties', 'create', 'edit'],
disabled: 'inSchema'
},{
id: 'attoptions', label: 'Variables', type: 'collection',
group: '{{ _('Variables') }}', control: 'unique-col-collection',
model: VariablesModel, uniqueCol : ['name'],
mode: ['edit', 'create'], canAdd: true, canEdit: false,
canDelete: true
},{
id: 'attacl', label: 'Privileges', type: 'collection',
group: '{{ _('Security') }}', control: 'unique-col-collection',
@ -402,12 +393,6 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
privileges: ['a','r','w','x']}),
mode: ['edit'], canAdd: true, canDelete: true,
uniqueCol : ['grantee']
},{
id: 'attoptions', label: 'Variables', type: 'collection',
group: '{{ _('Security') }}', control: 'unique-col-collection',
model: VariablesModel, uniqueCol : ['name'],
mode: ['edit', 'create'], canAdd: true, canEdit: false,
canDelete: true
},{
id: 'seclabels', label: '{{ _('Security Labels') }}',
model: pgAdmin.Browser.SecurityModel,
@ -506,7 +491,7 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
var node_info = this.node_info || m.node_info || m.top.node_info;
// disable all fields if column is listed under view or mview
if ('view' in node_info || 'mview' in node_info) {
if (node_info && ('view' in node_info || 'mview' in node_info)) {
if (this && _.has(this, 'name') && (this.name != 'defval')) {
return true;
}

View File

@ -111,7 +111,8 @@ function($, _, S, pgAdmin, pgBrowser, Alertify) {
var name = m.get('name');
if (!(name && name != '')) {
setTimeout(function(){
m.set('comment', null);
if(m.get('comment') && m.get('comment') !== '')
m.set('comment', null);
},10);
return true;
} else {
@ -127,7 +128,7 @@ function($, _, S, pgAdmin, pgBrowser, Alertify) {
!_.isUndefined(m.get('oid'))) || (_.isFunction(m.isNew) && !m.isNew()));
}, editable: false
},{
id: 'connoinherit', label: '{{ _('No Inherit') }}', type:
id: 'connoinherit', label: '{{ _('No Inherit?') }}', type:
'switch', cell: 'boolean', group: '{{ _('Definition') }}', mode:
['properties', 'create', 'edit'], min_version: 90200,
disabled: function(m) {
@ -136,7 +137,7 @@ function($, _, S, pgAdmin, pgBrowser, Alertify) {
!_.isUndefined(m.get('oid'))) || (_.isFunction(m.isNew) && !m.isNew()));
}
},{
id: 'convalidated', label: "{{ _("Don't validate") }}", type: 'switch', cell:
id: 'convalidated', label: "{{ _("Don't validate?") }}", type: 'switch', cell:
'boolean', group: '{{ _('Definition') }}', min_version: 90200,
disabled: function(m) {
if ((_.isFunction(m.isNew) && !m.isNew()) ||

View File

@ -653,7 +653,8 @@ function($, _, S, pgAdmin, pgBrowser, Alertify) {
var name = m.get('name');
if (!(name && name != '')) {
setTimeout(function(){
m.set('comment', null);
if(m.get('comment') && m.get('comment') !== '')
m.set('comment', null);
},10);
return true;
} else {
@ -713,7 +714,7 @@ function($, _, S, pgAdmin, pgBrowser, Alertify) {
id: 'fillfactor', label: '{{ _('Fill factor') }}',
type: 'int', group: '{{ _('Definition') }}', allowNull: true
},{
id: 'condeferrable', label: '{{ _('Deferrable') }}',
id: 'condeferrable', label: '{{ _('Deferrable?') }}',
type: 'switch', group: '{{ _('Definition') }}', deps: ['index'],
disabled: function(m) {
return ((_.has(m, 'handler') &&
@ -721,7 +722,7 @@ function($, _, S, pgAdmin, pgBrowser, Alertify) {
!_.isUndefined(m.get('oid'))) || (_.isFunction(m.isNew) && !m.isNew()));
}
},{
id: 'condeferred', label: '{{ _('Deferred') }}',
id: 'condeferred', label: '{{ _('Deferred?') }}',
type: 'switch', group: '{{ _('Definition') }}',
deps: ['condeferrable'],
disabled: function(m) {
@ -736,7 +737,8 @@ function($, _, S, pgAdmin, pgBrowser, Alertify) {
return false;
} else {
setTimeout(function(){
m.set('condeferred', false);
if(m.get('condeferred'))
m.set('condeferred', false);
},10);
return true;
}

View File

@ -21,9 +21,6 @@ function($, _, S, pgAdmin, pgBrowser, Alertify) {
headerSelectControlTemplate = _.template([
'<div class="<%=Backform.controlsClassName%> <%=extraClasses.join(\' \')%>">',
' <select class="pgadmin-node-select form-control" name="<%=name%>" style="width:100%;" value="<%-value%>" <%=disabled ? "disabled" : ""%> <%=required ? "required" : ""%> >',
' <% if (first_empty) { %>',
' <option value="" <%="" === rawValue ? "selected" : "" %>><%- empty_value %></option>',
' <% } %>',
' <% for (var i=0; i < options.length; i++) { %>',
' <% var option = options[i]; %>',
' <option <% if (option.image) { %> data-image=<%= option.image %> <% } %> value=<%= formatter.fromRaw(option.value) %> <%=option.value === rawValue ? "selected=\'selected\'" : "" %>><%-option.label%></option>',
@ -702,7 +699,8 @@ function($, _, S, pgAdmin, pgBrowser, Alertify) {
var name = m.get('name');
if (!(name && name != '')) {
setTimeout(function(){
m.set('comment', null);
if(m.get('comment') && m.get('comment') !== '')
m.set('comment', null);
},10);
return true;
} else {
@ -710,7 +708,7 @@ function($, _, S, pgAdmin, pgBrowser, Alertify) {
}
}
},{
id: 'condeferrable', label: '{{ _('Deferrable') }}',
id: 'condeferrable', label: '{{ _('Deferrable?') }}',
type: 'switch', group: '{{ _('Definition') }}',
disabled: function(m) {
// If we are in table edit mode then
@ -723,7 +721,7 @@ function($, _, S, pgAdmin, pgBrowser, Alertify) {
return !m.isNew();
}
},{
id: 'condeferred', label: '{{ _('Deferred') }}',
id: 'condeferred', label: '{{ _('Deferred?') }}',
type: 'switch', group: '{{ _('Definition') }}',
deps: ['condeferrable'],
disabled: function(m) {
@ -740,7 +738,8 @@ function($, _, S, pgAdmin, pgBrowser, Alertify) {
return false;
} else {
setTimeout(function(){
m.set('condeferred', false);
if(m.get('condeferred'))
m.set('condeferred', false);
},10);
return true;
}
@ -778,7 +777,7 @@ function($, _, S, pgAdmin, pgBrowser, Alertify) {
return !(m.isNew() || m.get("convalidated"));
}
},{
id: 'autoindex', label: '{{ _('Auto FK index') }}',
id: 'autoindex', label: '{{ _('Auto FK index?') }}',
type: 'switch', group: '{{ _('Definition') }}',
deps: ['name', 'hasindex'],
options: {
@ -809,7 +808,8 @@ function($, _, S, pgAdmin, pgBrowser, Alertify) {
// new constraint which should allowed for Unique
if(_.isUndefined(m.get('oid')) && _.isUndefined(m.handler.get('oid'))) {
setTimeout(function () {
m.set('autoindex', false);
if(m.get('autoindex'))
m.set('autoindex', false);
}, 10);
return true;
} else {

View File

@ -101,7 +101,9 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
var name = m.get('name');
if (!(name && name != '')) {
setTimeout(function(){
m.set('comment', null);
if(m.get('comment') && m.get('comment') !== '') {
m.set('comment', null);
}
},10);
return true;
} else {
@ -207,17 +209,6 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
}),
canDelete: true, canAdd: true,
control: Backform.MultiSelectAjaxControl.extend({
formatter: {
fromRaw: function (rawData, model) {
var res = _.isObject(rawData) ?
rawData : JSON.parse(rawData);
return _.pluck(res, 'column');
},
toRaw: function (formattedData, model) {
return formattedData;
}
},
defaults: _.extend(
{},
Backform.NodeListByNameControl.prototype.defaults,
@ -454,7 +445,7 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
}
}
},{
id: 'condeferrable', label: '{{ _('Deferrable') }}',
id: 'condeferrable', label: '{{ _('Deferrable?') }}',
type: 'switch', group: '{{ _('Definition') }}', deps: ['index'],
disabled: function(m) {
// If we are in table edit mode then
@ -475,13 +466,14 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
return false;
} else {
setTimeout(function(){
m.set('condeferrable', false);
if(m.get('condeferrable'))
m.set('condeferrable', false);
},10);
return true;
}
}
},{
id: 'condeferred', label: '{{ _('Deferred') }}',
id: 'condeferred', label: '{{ _('Deferred?') }}',
type: 'switch', group: '{{ _('Definition') }}',
deps: ['condeferrable'],
disabled: function(m) {
@ -502,7 +494,8 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
return false;
} else {
setTimeout(function(){
m.set('condeferred', false);
if(m.get('condeferred'))
m.set('condeferred', false);
},10);
return true;
}

View File

@ -15,6 +15,34 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
});
};
// Node-Ajax-Cell with Deps
var NodeAjaxOptionsDepsCell = Backgrid.Extension.NodeAjaxOptionsCell.extend({
initialize: function() {
Backgrid.Extension.NodeAjaxOptionsCell.prototype.initialize.apply(this, arguments);
Backgrid.Extension.DependentCell.prototype.initialize.apply(this, arguments);
},
dependentChanged: function () {
var model = this.model,
column = this.column,
editable = this.column.get("editable"),
input = this.$el.find('select').first();
is_editable = _.isFunction(editable) ? !!editable.apply(column, [model]) : !!editable;
if (is_editable) {
this.$el.addClass("editable");
input.prop('disabled', false);
} else {
this.$el.removeClass("editable");
input.prop('disabled', true);
}
this.delegateEvents();
return this;
},
remove: Backgrid.Extension.DependentCell.prototype.remove
});
// Model to create column collection control
var ColumnModel = pgAdmin.Browser.Node.Model.extend({
defaults: {
@ -26,23 +54,38 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
},
schema: [
{
id: 'colname', label:'{{ _('Column') }}', cell: 'string',
type: 'text', disabled: 'inSchema', editable: false,
id: 'colname', label:'{{ _('Column') }}', cell: 'node-list-by-name',
type: 'text', disabled: 'inSchema', editable: true,
control: 'node-list-by-name', node: 'column'
},{
id: 'collspcname', label:'{{ _('Collation') }}', cell: 'string',
type: 'text', disabled: 'inSchema', editable: false,
id: 'collspcname', label:'{{ _('Collation') }}',
cell: NodeAjaxOptionsDepsCell,
type: 'text', disabled: 'inSchema', editable: function(m) {
// Header cell then skip
if (m instanceof Backbone.Collection) {
return false;
}
return !(m.inSchema.apply(this, arguments));
},
control: 'node-ajax-options', url: 'get_collations', node: 'index'
},{
id: 'op_class', label:'{{ _('Operator class') }}', cell: 'string',
type: 'text', disabled: 'checkAccessMethod', editable: false,
id: 'op_class', label:'{{ _('Operator class') }}',
cell: NodeAjaxOptionsDepsCell,
type: 'text', disabled: 'checkAccessMethod',
editable: function(m) {
// Header cell then skip
if (m instanceof Backbone.Collection) {
return false;
}
return !(m.checkAccessMethod.apply(this, arguments));
},
control: 'node-ajax-options', url: 'get_op_class', node: 'index',
deps: ['amname'], transform: function(data) {
deps: ['amname'], transform: function(data, control) {
/* We need to extract data from collection according
* to access method selected by user if not selected
* send btree related op_class options
*/
var amname = this.model.handler.get('amname'),
var amname = control.model.top.get('amname'),
options = data['btree'];
if(_.isUndefined(amname))
@ -56,21 +99,35 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
return options;
}
},{
id: 'sort_order', label:'{{ _('Sort order') }}', cell: 'switch',
type: 'switch', disabled: 'checkAccessMethod', editable: false,
id: 'sort_order', label:'{{ _('Sort order') }}', cell: SwitchDepCell,
type: 'switch', disabled: 'checkAccessMethod',
editable: function(m) {
// Header cell then skip
if (m instanceof Backbone.Collection) {
return false;
}
return !(m.checkAccessMethod.apply(this, arguments));
},
deps: ['amname'],
options: {
'onText': 'DESC', 'offText': 'ASC',
'onColor': 'success', 'offColor': 'default',
'onColor': 'success', 'offColor': 'primary',
'size': 'small'
}
},{
id: 'nulls', label:'{{ _('NULLs') }}', cell: 'switch',
type: 'switch', disabled: 'checkAccessMethod', editable: false,
id: 'nulls', label:'{{ _('NULLs') }}', cell: SwitchDepCell,
type: 'switch', disabled: 'checkAccessMethod',
editable: function(m) {
// Header cell then skip
if (m instanceof Backbone.Collection) {
return true;
}
return !(m.checkAccessMethod.apply(this, arguments));
},
deps: ['amname', 'sort_order'],
options: {
'onText': 'FIRST', 'offText': 'LAST',
'onColor': 'success', 'offColor': 'default',
'onColor': 'success', 'offColor': 'primary',
'size': 'small'
}
}
@ -107,7 +164,7 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
// We will check if we are under schema node and added condition
checkAccessMethod: function(m) {
//Access method is empty or btree then do not disable field
var parent_model = m.handler;
var parent_model = m.top;
if(!m.inSchema.apply(this, [m]) &&
(_.isUndefined(parent_model.get('amname')) ||
_.isNull(parent_model.get('amname')) ||
@ -115,10 +172,8 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
parent_model.get('amname') === 'btree')) {
// We need to set nulls to true if sort_order is set to desc
// nulls first is default for desc
if(m.get('sort_order') == true) {
if(m.get('sort_order') == true && m.previous('sort_order') == false) {
setTimeout(function() { m.set('nulls', true) }, 10);
} else {
setTimeout(function() { m.set('nulls', false) }, 10);
}
return false;
}
@ -130,6 +185,8 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
pgAdmin.Browser.Nodes['index'] = pgAdmin.Browser.Node.extend({
parent_type: ['table', 'view', 'mview'],
collection_type: ['coll-table', 'coll-view'],
sqlAlterHelp: 'sql-alterindex.html',
sqlCreateHelp: 'sql-createindex.html',
type: 'index',
label: '{{ _('Index') }}',
hasSQL: true,
@ -228,7 +285,8 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
})
},{
id: 'cols', label:'{{ _('Columns') }}', cell: 'string',
type: 'text', disabled: 'inSchema', mode: ['properties']
type: 'text', disabled: 'inSchema', mode: ['properties'],
group: '{{ _('Definition') }}'
},{
id: 'fillfactor', label:'{{ _('Fill factor') }}', cell: 'string',
type: 'int', disabled: 'inSchema', mode: ['create', 'edit', 'properties'],
@ -244,15 +302,14 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
},{
id: 'indisvalid', label:'{{ _('Valid?') }}', cell: 'string',
type: 'switch', disabled: true, mode: ['properties'],
group: '{{ _('Definition') }}'
},{
id: 'indisprimary', label:'{{ _('Primary?') }}', cell: 'string',
type: 'switch', disabled: true, mode: ['properties'],
group: '{{ _('Definition') }}'
},{
id: 'is_sys_idx', label:'{{ _('System index?') }}', cell: 'string',
type: 'switch', disabled: true, mode: ['properties'],
type: 'switch', disabled: true, mode: ['properties']
},{
id: 'isconcurrent', label:'{{ _('Concurrent build?') }}', cell: 'string',
type: 'switch', disabled: 'inSchemaWithModelCheck',
@ -262,7 +319,7 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
type: 'text', disabled: 'inSchemaWithModelCheck', mode: ['create', 'edit'],
control: 'sql-field', visible: true, group: '{{ _('Definition') }}'
},{
id: 'columns', label: 'Columns', type: 'collection',
id: 'columns', label: 'Columns', type: 'collection', deps: ['amname'],
group: '{{ _('Definition') }}', model: ColumnModel, mode: ['edit', 'create'],
canAdd: function(m) {
// We will disable it if it's in 'edit' mode
@ -272,14 +329,7 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
return false;
}
},
canEdit: function(m) {
// We will disable it if it's in 'edit' mode
if (m.isNew()) {
return true;
} else {
return false;
}
},
canEdit: false,
canDelete: function(m) {
// We will disable it if it's in 'edit' mode
if (m.isNew()) {
@ -288,7 +338,8 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
return false;
}
},
control: 'unique-col-collection', uniqueCol : ['colname']
control: 'unique-col-collection', uniqueCol : ['colname'],
columns: ['colname', 'op_class', 'sort_order', 'nulls', 'collspcname']
},{
id: 'description', label:'{{ _('Comment') }}', cell: 'string',
type: 'multiline', mode: ['properties', 'create', 'edit'],

View File

@ -16,6 +16,33 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
});
};
// Switch Cell with Deps
var SwitchDepCell = Backgrid.Extension.SwitchCell.extend({
initialize: function() {
Backgrid.Extension.SwitchCell.prototype.initialize.apply(this, arguments);
Backgrid.Extension.DependentCell.prototype.initialize.apply(this, arguments);
},
dependentChanged: function () {
var model = this.model,
column = this.column,
editable = this.column.get("editable"),
input = this.$el.find('input[type=checkbox]').first();
is_editable = _.isFunction(editable) ? !!editable.apply(column, [model]) : !!editable;
if (is_editable) {
this.$el.addClass("editable");
input.prop('disabled', false);
} else {
this.$el.removeClass("editable");
input.prop('disabled', true);
}
this.delegateEvents();
return this;
},
remove: Backgrid.Extension.DependentCell.prototype.remove
});
if (!pgBrowser.Nodes['table']) {
pgAdmin.Browser.Nodes['table'] = pgBrowser.Node.extend({
type: 'table',
@ -385,29 +412,30 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
disabled: 'inSchemaWithModelCheck',
group: '{{ _('Advanced') }}'
},{
id: 'conname', label:'{{ _('Primary Key') }}', cell: 'string',
type: 'text', mode: ['properties'],
id: 'conname', label:'{{ _('Primary key') }}', cell: 'string',
type: 'text', mode: ['properties'], group: '{{ _('Advanced') }}',
disabled: 'inSchema'
},{
id: 'reltuples', label:'{{ _('Rows (estimated)') }}', cell: 'string',
type: 'text', mode: ['properties'],
type: 'text', mode: ['properties'], group: '{{ _('Advanced') }}',
disabled: 'inSchema'
},{
id: 'rows_cnt', label:'{{ _('Rows (counted)') }}', cell: 'string',
type: 'text', mode: ['properties'],
type: 'text', mode: ['properties'], group: '{{ _('Advanced') }}',
disabled: 'inSchema'
},{
id: 'relhassubclass', label:'{{ _('Inherits tables?') }}', cell: 'switch',
type: 'switch', mode: ['properties'],
type: 'switch', mode: ['properties'], group: '{{ _('Advanced') }}',
disabled: 'inSchema'
},{
id: 'is_sys_table', label:'{{ _('System tabel?') }}', cell: 'switch',
id: 'is_sys_table', label:'{{ _('System table?') }}', cell: 'switch',
type: 'switch', mode: ['properties'],
disabled: 'inSchema'
},{
id: 'coll_inherits', label: '{{ _('Inherited from table(s)') }}',
url: 'get_inherits', type: 'array',
url: 'get_inherits', type: 'array', group: '{{ _('Columns') }}',
disabled: 'checkInheritance', deps: ['typname'],
mode: ['create', 'edit'],
select2: { multiple: true, allowClear: true,
placeholder: '{{ _('Select to inherit from...') }}'},
transform: function(data, cell) {
@ -489,194 +517,193 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
return tbl_oid;
}
})
},{
id: 'coll_inherits', label: '{{ _('Inherited from table(s)') }}',
url: 'get_inherits', type: 'text', group: '{{ _('Advanced') }}',
disabled: 'checkInheritance',
mode: ['properties'],
},{
id: 'inherited_tables_cnt', label:'{{ _('Inherited tables count') }}', cell: 'string',
type: 'text', mode: ['properties'],
type: 'text', mode: ['properties'], group: '{{ _('Advanced') }}',
disabled: 'inSchema'
},{
type: 'nested', control: 'fieldset', mode: ['edit', 'create'],
schema:[{
// Here we will create tab control for columns
id: 'columns', label:'{{ _('Columns') }}', type: 'collection',
group: '{{ _('Columns') }}',
model: pgBrowser.Nodes['column'].model,
subnode: pgBrowser.Nodes['column'].model,
mode: ['create', 'edit'],
disabled: 'inSchema',
canAdd: 'check_grid_add_condition',
canEdit: true, canDelete: true,
// For each row edit/delete button enable/disable
canEditRow: 'check_grid_row_edit_delete',
canDeleteRow: 'check_grid_row_edit_delete',
uniqueCol : ['name'],
columns : ['name' , 'cltype', 'is_primary_key', 'inheritedfrom'],
control: Backform.UniqueColCollectionControl.extend({
initialize: function() {
Backform.UniqueColCollectionControl.prototype.initialize.apply(this, arguments);
var self = this,
collection = self.model.get(self.field.get('name'));
// Here we will create tab control for columns
id: 'columns', label:'{{ _('Columns') }}', type: 'collection',
group: '{{ _('Columns') }}',
model: pgBrowser.Nodes['column'].model,
subnode: pgBrowser.Nodes['column'].model,
mode: ['create', 'edit'],
disabled: 'inSchema',
canAdd: 'check_grid_add_condition',
canEdit: true, canDelete: true,
// For each row edit/delete button enable/disable
canEditRow: 'check_grid_row_edit_delete',
canDeleteRow: 'check_grid_row_edit_delete',
uniqueCol : ['name'],
columns : ['name' , 'cltype', 'is_primary_key', 'inheritedfrom'],
control: Backform.UniqueColCollectionControl.extend({
initialize: function() {
Backform.UniqueColCollectionControl.prototype.initialize.apply(this, arguments);
var self = this,
collection = self.model.get(self.field.get('name'));
collection.on("change:is_primary_key", function(m) {
var primary_key_coll = self.model.get('primary_key'),
column_name = m.get('name'),
primary_key;
collection.on("change:is_primary_key", function(m) {
var primary_key_coll = self.model.get('primary_key'),
column_name = m.get('name'),
primary_key;
if(m.get('is_primary_key')) {
// Add column to primary key.
if (primary_key_coll.length < 1) {
primary_key = new (primary_key_coll.model)({}, {
if(m.get('is_primary_key')) {
// Add column to primary key.
if (primary_key_coll.length < 1) {
primary_key = new (primary_key_coll.model)({}, {
top: self.model,
collection: primary_key_coll,
handler: primary_key_coll
});
primary_key_coll.add(primary_key);
} else {
primary_key = primary_key_coll.first();
}
// Do not alter existing primary key columns.
if (_.isUndefined(primary_key.get('oid'))) {
var primary_key_column_coll = primary_key.get('columns'),
primary_key_column_exist = primary_key_column_coll.where({column:column_name});
if (primary_key_column_exist.length == 0) {
var primary_key_column = new (primary_key_column_coll.model)(
{column: column_name}, { silent: true,
top: self.model,
collection: primary_key_coll,
handler: primary_key_coll
});
primary_key_coll.add(primary_key);
} else {
primary_key = primary_key_coll.first();
}
// Do not alter existing primary key columns.
if (_.isUndefined(primary_key.get('oid'))) {
var primary_key_column_coll = primary_key.get('columns'),
primary_key_column_exist = primary_key_column_coll.where({column:column_name});
if (primary_key_column_exist.length == 0) {
var primary_key_column = new (primary_key_column_coll.model)(
{column: column_name}, { silent: true,
top: self.model,
collection: primary_key_coll,
handler: primary_key_coll
});
primary_key_column_coll.add(primary_key_column);
}
primary_key_column_coll.add(primary_key_column);
}
primary_key_column_coll.trigger('pgadmin:multicolumn:updated', primary_key_column_coll);
}
primary_key_column_coll.trigger('pgadmin:multicolumn:updated', primary_key_column_coll);
}
} else {
// remove column from primary key.
if (primary_key_coll.length > 0) {
var primary_key = primary_key_coll.first();
// Do not alter existing primary key columns.
if (!_.isUndefined(primary_key.get('oid'))) {
return;
}
} else {
// remove column from primary key.
if (primary_key_coll.length > 0) {
var primary_key = primary_key_coll.first();
// Do not alter existing primary key columns.
if (!_.isUndefined(primary_key.get('oid'))) {
return;
}
var primary_key_column_coll = primary_key.get('columns'),
removedCols = primary_key_column_coll.where({column:column_name});
if (removedCols.length > 0) {
primary_key_column_coll.remove(removedCols);
_.each(removedCols, function(m) {
m.destroy();
})
if (primary_key_column_coll.length == 0) {
setTimeout(function () {
// There will be only on primary key so remove the first one.
primary_key_coll.remove(primary_key_coll.first());
/* Ideally above line of code should be "primary_key_coll.reset()".
* But our custom DataCollection (extended from Backbone collection in datamodel.js)
* does not respond to reset event, it only supports add, remove, change events.
* And hence no custom event listeners/validators get called for reset event.
*/
}, 10);
}
}
primary_key_column_coll.trigger('pgadmin:multicolumn:updated', primary_key_column_coll);
var primary_key_column_coll = primary_key.get('columns'),
removedCols = primary_key_column_coll.where({column:column_name});
if (removedCols.length > 0) {
primary_key_column_coll.remove(removedCols);
_.each(removedCols, function(m) {
m.destroy();
})
if (primary_key_column_coll.length == 0) {
setTimeout(function () {
// There will be only on primary key so remove the first one.
primary_key_coll.remove(primary_key_coll.first());
/* Ideally above line of code should be "primary_key_coll.reset()".
* But our custom DataCollection (extended from Backbone collection in datamodel.js)
* does not respond to reset event, it only supports add, remove, change events.
* And hence no custom event listeners/validators get called for reset event.
*/
}, 10);
}
}
})
},
remove: function() {
var collection = this.model.get(this.field.get('name'));
if (collection) {
collection.off("change:is_primary_key");
primary_key_column_coll.trigger('pgadmin:multicolumn:updated', primary_key_column_coll);
}
Backform.UniqueColCollectionControl.prototype.remove.apply(this, arguments);
}
}),
allowMultipleEmptyRow: false
}]
},{
type: 'nested', control: 'fieldset',
schema:[{
// Here we will create tab control for constraints
type: 'nested', control: 'tab', group: '{{ _('Constraints') }}',
mode: ['edit', 'create'],
schema: [{
id: 'primary_key', label: '{{ _('Primary Key') }}',
model: pgBrowser.Nodes['primary_key'].model,
subnode: pgBrowser.Nodes['primary_key'].model,
editable: false, type: 'collection',
group: '{{ _('Primary Key') }}', mode: ['edit', 'create'],
canEdit: true, canDelete: true,
control: 'unique-col-collection',
columns : ['name', 'columns'],
canAdd: true,
canAddRow: function(m) {
// User can only add one primary key
var columns = m.get('columns');
})
},
remove: function() {
var collection = this.model.get(this.field.get('name'));
if (collection) {
collection.off("change:is_primary_key");
}
return (m.get('primary_key') &&
m.get('primary_key').length < 1 &&
_.some(columns.pluck('name')));
}
},{
id: 'foreign_key', label: '{{ _('Foreign Key') }}',
model: pgBrowser.Nodes['foreign_key'].model,
subnode: pgBrowser.Nodes['foreign_key'].model,
editable: false, type: 'collection',
group: '{{ _('Foreign Key') }}', mode: ['edit', 'create'],
canEdit: true, canDelete: true,
control: 'unique-col-collection',
canAdd: true,
columns : ['name', 'columns'],
canAddRow: function(m) {
// User can only add if there is at least one column with name.
var columns = m.get('columns');
return _.some(columns.pluck('name'));
}
},{
id: 'check_constraint', label: '{{ _('Check Constraint') }}',
model: pgBrowser.Nodes['check_constraints'].model,
subnode: pgBrowser.Nodes['check_constraints'].model,
editable: false, type: 'collection',
group: '{{ _('Check') }}', mode: ['edit', 'create'],
canEdit: true, canDelete: true,
control: 'unique-col-collection',
canAdd: true,
columns : ['name', 'consrc']
},{
id: 'unique_constraint', label: '{{ _('Unique Constraint') }}',
model: pgBrowser.Nodes['unique_constraint'].model,
subnode: pgBrowser.Nodes['unique_constraint'].model,
editable: false, type: 'collection',
group: '{{ _('Unique') }}', mode: ['edit', 'create'],
canEdit: true, canDelete: true,
control: 'unique-col-collection',
columns : ['name', 'columns'],
canAdd: true,
canAddRow: function(m) {
// User can only add if there is at least one column with name.
var columns = m.get('columns');
return _.some(columns.pluck('name'));
}
},{
id: 'exclude_constraint', label: '{{ _('Exclude Constraint') }}',
model: pgBrowser.Nodes['exclusion_constraint'].model,
subnode: pgBrowser.Nodes['exclusion_constraint'].model,
editable: false, type: 'collection',
group: '{{ _('Exclude') }}', mode: ['edit', 'create'],
canEdit: true, canDelete: true,
control: 'unique-col-collection',
columns : ['name', 'columns', 'constraint'],
canAdd: true,
canAddRow: function(m) {
// User can only add if there is at least one column with name.
var columns = m.get('columns');
return _.some(columns.pluck('name'));
}
}]
}]
Backform.UniqueColCollectionControl.prototype.remove.apply(this, arguments);
}
}),
allowMultipleEmptyRow: false
},{
// Here we will create tab control for constraints
type: 'nested', control: 'tab', group: '{{ _('Constraints') }}',
mode: ['edit', 'create'],
schema: [{
id: 'primary_key', label: '{{ _('Primary key') }}',
model: pgBrowser.Nodes['primary_key'].model,
subnode: pgBrowser.Nodes['primary_key'].model,
editable: false, type: 'collection',
group: '{{ _('Primary Key') }}', mode: ['edit', 'create'],
canEdit: true, canDelete: true,
control: 'unique-col-collection',
columns : ['name', 'columns'],
canAdd: true,
canAddRow: function(m) {
// User can only add one primary key
var columns = m.get('columns');
return (m.get('primary_key') &&
m.get('primary_key').length < 1 &&
_.some(columns.pluck('name')));
}
},{
id: 'foreign_key', label: '{{ _('Foreign key') }}',
model: pgBrowser.Nodes['foreign_key'].model,
subnode: pgBrowser.Nodes['foreign_key'].model,
editable: false, type: 'collection',
group: '{{ _('Foreign Key') }}', mode: ['edit', 'create'],
canEdit: true, canDelete: true,
control: 'unique-col-collection',
canAdd: true,
columns : ['name', 'columns'],
canAddRow: function(m) {
// User can only add if there is at least one column with name.
var columns = m.get('columns');
return _.some(columns.pluck('name'));
}
},{
id: 'check_constraint', label: '{{ _('Check constraint') }}',
model: pgBrowser.Nodes['check_constraints'].model,
subnode: pgBrowser.Nodes['check_constraints'].model,
editable: false, type: 'collection',
group: '{{ _('Check') }}', mode: ['edit', 'create'],
canEdit: true, canDelete: true,
control: 'unique-col-collection',
canAdd: true,
columns : ['name', 'consrc']
},{
id: 'unique_constraint', label: '{{ _('Unique constraint') }}',
model: pgBrowser.Nodes['unique_constraint'].model,
subnode: pgBrowser.Nodes['unique_constraint'].model,
editable: false, type: 'collection',
group: '{{ _('Unique') }}', mode: ['edit', 'create'],
canEdit: true, canDelete: true,
control: 'unique-col-collection',
columns : ['name', 'columns'],
canAdd: true,
canAddRow: function(m) {
// User can only add if there is at least one column with name.
var columns = m.get('columns');
return _.some(columns.pluck('name'));
}
},{
id: 'exclude_constraint', label: '{{ _('Exclude constraint') }}',
model: pgBrowser.Nodes['exclusion_constraint'].model,
subnode: pgBrowser.Nodes['exclusion_constraint'].model,
editable: false, type: 'collection',
group: '{{ _('Exclude') }}', mode: ['edit', 'create'],
canEdit: true, canDelete: true,
control: 'unique-col-collection',
columns : ['name', 'columns', 'constraint'],
canAdd: true,
canAddRow: function(m) {
// User can only add if there is at least one column with name.
var columns = m.get('columns');
return _.some(columns.pluck('name'));
}
}]
},{
type: 'nested', control: 'fieldset', label: '{{ _('Like') }}',
group: '{{ _('Advanced') }}',
@ -686,23 +713,23 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
control: 'node-ajax-options', url: 'get_relations',
disabled: 'inSchemaWithModelCheck', group: '{{ _('Like') }}'
},{
id: 'like_default_value', label:'{{ _('With Default values?') }}', cell: 'switch',
id: 'like_default_value', label:'{{ _('With default values?') }}', cell: 'switch',
type: 'switch', mode: ['create', 'edit'],
disabled: 'inSchemaWithModelCheck', group: '{{ _('Like') }}'
},{
id: 'like_constraints', label:'{{ _('With Constraints?') }}', cell: 'switch',
id: 'like_constraints', label:'{{ _('With constraints?') }}', cell: 'switch',
type: 'switch', mode: ['create', 'edit'],
disabled: 'inSchemaWithModelCheck', group: '{{ _('Like') }}'
},{
id: 'like_indexes', label:'{{ _('With Indexes?') }}', cell: 'switch',
id: 'like_indexes', label:'{{ _('With indexes?') }}', cell: 'switch',
type: 'switch', mode: ['create', 'edit'],
disabled: 'inSchemaWithModelCheck', group: '{{ _('Like') }}'
},{
id: 'like_storage', label:'{{ _('With Storage?') }}', cell: 'switch',
id: 'like_storage', label:'{{ _('With storage?') }}', cell: 'switch',
type: 'switch', mode: ['create', 'edit'],
disabled: 'inSchemaWithModelCheck', group: '{{ _('Like') }}'
},{
id: 'like_comments', label:'{{ _('With Comments?') }}', cell: 'switch',
id: 'like_comments', label:'{{ _('With comments?') }}', cell: 'switch',
type: 'switch', mode: ['create', 'edit'],
disabled: 'inSchemaWithModelCheck', group: '{{ _('Like') }}'
}]
@ -723,17 +750,17 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
mode: ['edit', 'create'], canAdd: true, canDelete: true,
uniqueCol : ['grantee']
},{
id: 'seclabels', label: '{{ _('Security Labels') }}',
id: 'seclabels', label: '{{ _('Security labels') }}',
model: pgAdmin.Browser.SecurityModel, editable: false, type: 'collection',
group: '{{ _('Security') }}', mode: ['edit', 'create'],
min_version: 90100, canAdd: true,
canEdit: false, canDelete: true, control: 'unique-col-collection'
},{
id: 'vacuum_settings_str', label: '{{ _('Storage Settings') }}',
id: 'vacuum_settings_str', label: '{{ _('Storage settings') }}',
type: 'multiline', group: '{{ _('Advanced') }}', mode: ['properties']
}
],
validate: function() {
validate: function(keys) {
var err = {},
changedAttrs = this.changed,
msg = undefined,
@ -743,6 +770,14 @@ function($, _, S, pgAdmin, pgBrowser, alertify) {
this.errorModel.clear();
// If nothing to validate or VacuumSetting keys then
// return from here
if ( keys && (keys.length == 0
|| _.indexOf(keys, 'autovacuum_enabled') != -1
|| _.indexOf(keys, 'toast_autovacuum_enabled') != -1) ) {
return null;
}
if (_.isUndefined(name) || _.isNull(name) ||
String(name).replace(/^\s+|\s+$/g, '') == '') {
msg = '{{ _('Table name can not be empty.') }}';

View File

@ -113,7 +113,7 @@ class TriggerModule(CollectionNodeModule):
"""
Load the module node as a leaf node
"""
return True
return False
@property
def csssnippets(self):

View File

@ -3,6 +3,26 @@ define(
'backform', 'alertify', 'pgadmin.browser.collection'],
function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
var CustomSwitchControl = Backform.CustomSwitchControl = Backform.SwitchControl.extend({
template: _.template([
'<label class="<%=Backform.controlLabelClassName%> custom_switch_label_class"><%=label%></label>',
'<div class="<%=Backform.controlsClassName%> custom_switch_control_class">',
' <div class="checkbox">',
' <label>',
' <input type="checkbox" class="<%=extraClasses.join(\' \')%>"',
' name="<%=name%>" <%=value ? "checked=\'checked\'" : ""%>',
' <%=disabled ? "disabled" : ""%> <%=required ? "required" : ""%> />',
' </label>',
' </div>',
'</div>',
'<% if (helpMessage && helpMessage.length) { %>',
' <span class="<%=Backform.helpMessageClassName%>"><%=helpMessage%></span>',
'<% } %>'
].join("\n")),
className: 'pgadmin-control-group form-group col-xs-6'
});
if (!pgBrowser.Nodes['coll-trigger']) {
var triggers = pgAdmin.Browser.Nodes['coll-trigger'] =
pgAdmin.Browser.Collection.extend({
@ -162,7 +182,8 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
model: pgAdmin.Browser.Node.Model.extend({
defaults: {
name: undefined,
is_row_trigger: true
is_row_trigger: true,
fires: 'BEFORE'
},
schema: [{
id: 'name', label: '{{ _('Name') }}', cell: 'string',
@ -172,14 +193,15 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
type: 'int', disabled: true, mode: ['properties']
},{
id: 'is_enable_trigger', label:'{{ _('Enable trigger?') }}',
type: 'switch', disabled: 'inSchema', mode: ['properties']
type: 'switch', disabled: 'inSchema', mode: ['properties'],
group: '{{ _('Definition') }}'
},{
id: 'is_row_trigger', label:'{{ _('Row trigger') }}',
id: 'is_row_trigger', label:'{{ _('Row trigger?') }}',
type: 'switch', group: '{{ _('Definition') }}',
mode: ['create','edit', 'properties'],
deps: ['is_constraint_trigger'],
disabled: function(m) {
// If contraint trigger is set to True then row trigger will
// If constraint trigger is set to True then row trigger will
// automatically set to True and becomes disable
var is_constraint_trigger = m.get('is_constraint_trigger');
if(!m.inSchemaWithModelCheck.apply(this, [m])) {
@ -192,54 +214,61 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
return false;
}
} else {
// Disbale it
// Disable it
return true;
}
}
},{
id: 'is_constraint_trigger', label:'{{ _('Constraint trigger') }}',
id: 'is_constraint_trigger', label:'{{ _('Constraint trigger?') }}',
type: 'switch', disabled: 'inSchemaWithModelCheck',
mode: ['create','edit', 'properties'],
group: '{{ _('Definition') }}'
},{
id: 'tgdeferrable', label:'{{ _('Deferrable') }}',
id: 'tgdeferrable', label:'{{ _('Deferrable?') }}',
type: 'switch', group: '{{ _('Definition') }}',
mode: ['create','edit', 'properties'],
deps: ['is_constraint_trigger'],
disabled: function(m) {
// If contraint trigger is set to True then only enable it
// If constraint trigger is set to True then only enable it
var is_constraint_trigger = m.get('is_constraint_trigger');
if(!m.inSchemaWithModelCheck.apply(this, [m])) {
if(!_.isUndefined(is_constraint_trigger) &&
is_constraint_trigger === true) {
return false;
} else {
setTimeout(function() { m.set('tgdeferrable', false) }, 10);
// If value is already set then reset it to false
if(m.get('tgdeferrable')) {
setTimeout(function() { m.set('tgdeferrable', false) }, 10);
}
return true;
}
} else {
// Disbale it
// Disable it
return true;
}
}
},{
id: 'tginitdeferred', label:'{{ _('Deferred') }}',
id: 'tginitdeferred', label:'{{ _('Deferred?') }}',
type: 'switch', group: '{{ _('Definition') }}',
mode: ['create','edit', 'properties'],
deps: ['tgdeferrable'],
deps: ['tgdeferrable', 'is_constraint_trigger'],
disabled: function(m) {
// If contraint trigger is set to True then only enable it
var is_constraint_trigger = m.get('tgdeferrable');
// If Deferrable is set to True then only enable it
var tgdeferrable = m.get('tgdeferrable');
if(!m.inSchemaWithModelCheck.apply(this, [m])) {
if(!_.isUndefined(is_constraint_trigger) &&
is_constraint_trigger === true) {
if(!_.isUndefined(tgdeferrable) &&
tgdeferrable) {
return false;
} else {
setTimeout(function() { m.set('tginitdeferred', false) }, 10);
return true;
// If value is already set then reset it to false
if(m.get('tginitdeferred')) {
setTimeout(function() { m.set('tginitdeferred', false) }, 10);
}
// If constraint trigger is set then do not disable
return m.get('is_constraint_trigger') ? false : true;
}
} else {
// Disbale it
// Disable it
return true;
}
}
@ -261,20 +290,20 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
if(server_type === 'ppas' &&
!_.isUndefined(tfunction) &&
tfunction === 'Inline EDB-SPL') {
// Disbale and clear its value
// Disable and clear its value
m.set('tgargs', undefined)
return true;
} else {
return false;
}
} else {
// Disbale it
// Disable it
return true;
}
}
},{
id: 'fires', label:'{{ _('Fires') }}', deps: ['is_constraint_trigger'],
mode: ['create','edit', 'properties'], group: '{{ _('Definition') }}',
mode: ['create','edit', 'properties'], group: '{{ _('Events') }}',
options: function(control) {
var table_options = [
{label: "BEFORE", value: "BEFORE"},
@ -291,18 +320,7 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
}
},
// If create mode then by default open composite type
control: Backform.Select2Control.extend({
render: function(){
// Initialize parent's render method
Backform.Select2Control.prototype.render.apply(this, arguments);
if(this.model.isNew() &&
this.model.get('is_constraint_trigger') !== true ) {
this.model.set({'fires': 'BEFORE'}, {silent: true});
}
return this;
}
}),
select2: { allowClear: false, width: "100%" },
control: 'select2', select2: { allowClear: false, width: "100%" },
disabled: function(m) {
// If contraint trigger is set to True then only enable it
var is_constraint_trigger = m.get('is_constraint_trigger');
@ -315,17 +333,18 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
return false;
}
} else {
// Disbale it
// Disable it
return true;
}
}
},{
type: 'nested', control: 'fieldset', mode: ['create','edit', 'properties'],
label: '{{ _('Events') }}', group: '{{ _('Definition') }}',
label: '{{ _('Events') }}', group: '{{ _('Events') }}',
schema:[{
id: 'evnt_insert', label:'{{ _('INSERT') }}',
type: 'switch', mode: ['create','edit', 'properties'],
group: '{{ _('Events') }}',
control: Backform.CustomSwitchControl,
disabled: function(m) {
return m.inSchemaWithModelCheck.apply(this, [m]);
}
@ -333,6 +352,7 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
id: 'evnt_update', label:'{{ _('UPDATE') }}',
type: 'switch', mode: ['create','edit', 'properties'],
group: '{{ _('Events') }}',
control: Backform.CustomSwitchControl,
disabled: function(m) {
return m.inSchemaWithModelCheck.apply(this, [m]);
}
@ -340,12 +360,14 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
id: 'evnt_delete', label:'{{ _('DELETE') }}',
type: 'switch', mode: ['create','edit', 'properties'],
group: '{{ _('Events') }}',
control: Backform.CustomSwitchControl,
disabled: function(m) {
return m.inSchemaWithModelCheck.apply(this, [m]);
}
},{
id: 'evnt_turncate', label:'{{ _('TRUNCATE') }}',
type: 'switch', group: '{{ _('Events') }}',
control: Backform.CustomSwitchControl,
disabled: function(m) {
var is_constraint_trigger = m.get('is_constraint_trigger'),
is_row_trigger = m.get('is_row_trigger'),
@ -363,7 +385,7 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
return true;
}
} else {
// Disbale it
// Disable it
return true;
}
}
@ -372,11 +394,11 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
id: 'whenclause', label:'{{ _('When') }}',
type: 'text', disabled: 'inSchemaWithModelCheck',
mode: ['create', 'edit', 'properties'],
control: 'sql-field', visible: true, group: '{{ _('Definition') }}'
control: 'sql-field', visible: true, group: '{{ _('Events') }}'
},{
id: 'columns', label: '{{ _('Columns') }}', url: 'nodes',
type: 'collection', control: 'multi-select-ajax',
deps: ['evnt_update'], node: 'column', group: '{{ _('Definition') }}',
deps: ['evnt_update'], node: 'column', group: '{{ _('Events') }}',
model: pgBrowser.Node.Model.extend({
keys: ['column'], defaults: { column: undefined }
}),
@ -384,7 +406,7 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
if(this.node_info && 'catalog' in this.node_info) {
return true;
}
//Disbale in edit mode
//Disable in edit mode
if (!m.isNew()) {
return true;
}
@ -414,7 +436,7 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
return true;
}
} else {
// Disbale it
// Disable it
return true;
}
}
@ -423,17 +445,23 @@ function($, _, S, pgAdmin, pgBrowser, Backform, alertify) {
type: 'switch', disabled: 'inSchemaWithModelCheck', mode: ['properties']
},{
id: 'is_constarint', label:'{{ _('Constraint?') }}', cell: 'string',
type: 'switch', disabled: 'inSchemaWithModelCheck', mode: ['properties']
type: 'switch', disabled: 'inSchemaWithModelCheck', mode: ['properties'],
group: '{{ _('Definition') }}'
},{
id: 'description', label:'{{ _('Comment') }}', cell: 'string',
type: 'multiline', mode: ['properties', 'create', 'edit'],
disabled: 'inSchema'
}],
validate: function() {
validate: function(keys) {
var err = {},
msg = undefined;
this.errorModel.clear();
// If nothing to validate
if (keys && keys.length == 0) {
return null;
}
if(_.isUndefined(this.get('name'))
|| String(this.get('name')).replace(/^\s+|\s+$/g, '') == '') {
msg = '{{ _('Name can not be empty.') }}';

View File

@ -552,7 +552,8 @@ class TypeView(PGChildNodeView, DataTypeReader):
res.append(
{'label': row['typname'], 'value': row['typname'],
'typval': typeval, 'precision': precision,
'length': length, 'min_val': min_val, 'max_val': max_val
'length': length, 'min_val': min_val, 'max_val': max_val,
'is_collatable': row['is_collatable']
}
)

View File

@ -14,6 +14,55 @@ function($, _, S, pgAdmin, pgBrowser, alertify, Backgrid) {
});
};
// Integer Cell for Columns Length and Precision
var IntegerDepCell = Backgrid.IntegerCell.extend({
initialize: function() {
Backgrid.NumberCell.prototype.initialize.apply(this, arguments);
Backgrid.Extension.DependentCell.prototype.initialize.apply(this, arguments);
},
dependentChanged: function () {
this.$el.empty();
var model = this.model;
var column = this.column;
editable = this.column.get("editable");
is_editable = _.isFunction(editable) ? !!editable.apply(column, [model]) : !!editable;
if (is_editable){ this.$el.addClass("editable"); }
else { this.$el.removeClass("editable"); }
this.delegateEvents();
return this;
},
remove: Backgrid.Extension.DependentCell.prototype.remove
});
// Node-Ajax-Cell with Deps
var NodeAjaxOptionsDepsCell = Backgrid.Extension.NodeAjaxOptionsCell.extend({
initialize: function() {
Backgrid.Extension.NodeAjaxOptionsCell.prototype.initialize.apply(this, arguments);
Backgrid.Extension.DependentCell.prototype.initialize.apply(this, arguments);
},
dependentChanged: function () {
var model = this.model,
column = this.column,
editable = this.column.get("editable"),
input = this.$el.find('select').first();
is_editable = _.isFunction(editable) ? !!editable.apply(column, [model]) : !!editable;
if (is_editable) {
this.$el.addClass("editable");
input.prop('disabled', false);
} else {
this.$el.removeClass("editable");
input.prop('disabled', true);
}
this.delegateEvents();
return this;
},
remove: Backgrid.Extension.DependentCell.prototype.remove
});
// Security label model declaration
var SecurityModel = Backform.SecurityModel = pgAdmin.Browser.Node.Model.extend({
defaults: {
@ -64,13 +113,14 @@ function($, _, S, pgAdmin, pgBrowser, alertify, Backgrid) {
subtypes: undefined,
schema: [{
id: 'member_name', label: '{{ _('Member Name') }}',
type: 'text', disabled: false, editable: false
type: 'text', disabled: false, editable: true
},{
id: 'type', label: '{{ _('Type') }}', control: 'node-ajax-options',
type: 'text', url: 'get_types', disabled: false, node: 'type',
editable: false,
transform: function(d){
this.model.type_options = d;
cell: 'node-ajax-options',
editable: true,
transform: function(d, control){
control.model.type_options = d;
return d;
}
},{
@ -78,8 +128,8 @@ function($, _, S, pgAdmin, pgBrowser, alertify, Backgrid) {
// precision and scale. In the UI, we try to follow the docs as
// closely as possible, therefore we use Length/Precision and Scale
id: 'tlength', label: '{{ _('Length/precision') }}', deps: ['type'], type: 'text',
editable: false,
disabled: function(m) {
disabled: false, cell: IntegerDepCell,
editable: function(m) {
// We will store type from selected from combobox
var of_type = m.get('type');
if(m.type_options) {
@ -98,15 +148,15 @@ function($, _, S, pgAdmin, pgBrowser, alertify, Backgrid) {
}
});
}
return !m.get('is_tlength');
return m.get('is_tlength');
}
},{
// Note: There are ambiguities in the PG catalogs and docs between
// precision and scale. In the UI, we try to follow the docs as
// closely as possible, therefore we use Length/Precision and Scale
id: 'precision', label: '{{ _('Scale') }}', deps: ['type'],
type: 'text', editable: false,
disabled: function(m) {
type: 'text', disabled: false, cell: IntegerDepCell,
editable: function(m) {
// We will store type from selected from combobox
var of_type = m.get('type');
if(m.type_options) {
@ -125,11 +175,32 @@ function($, _, S, pgAdmin, pgBrowser, alertify, Backgrid) {
}
});
}
return !m.get('is_precision');
return m.get('is_precision');
}
},{
id: 'collation', label: '{{ _('Collation') }}',
control: 'node-ajax-options', editable: false,
cell: NodeAjaxOptionsDepsCell, deps: ['type'],
control: 'node-ajax-options', editable: function(m) {
var of_type = m.get('type'),
flag = false;
if(m.type_options) {
_.each(m.type_options, function(o) {
if ( of_type == o.value ) {
if(o.is_collatable)
{
flag = true;
}
}
});
}
if (flag) {
setTimeout(function(){
m.set('collspcname', "");
}, 10);
}
return flag;
},
type: 'text', disabled: false, url: 'get_collations', node: 'type'
}],
validate: function() {
@ -323,7 +394,7 @@ function($, _, S, pgAdmin, pgBrowser, alertify, Backgrid) {
model: CompositeModel, editable: true, type: 'collection',
group: '{{ _('Definition') }}', mode: ['edit', 'create'],
control: 'unique-col-collection', uniqueCol : ['member_name'],
canAdd: true, canEdit: true, canDelete: true, disabled: 'inSchema',
canAdd: true, canEdit: false, canDelete: true, disabled: 'inSchema',
deps: ['typtype'], deps: ['typtype'],
visible: function(m) {
return m.get('typtype') === 'c';
@ -358,8 +429,8 @@ function($, _, S, pgAdmin, pgBrowser, alertify, Backgrid) {
select2: { allowClear: true, placeholder: "", width: "100%" },
url: 'get_stypes', type: 'text', mode: ['properties', 'create', 'edit'],
group: '{{ _('Range Type') }}', disabled: 'inSchemaWithModelCheck',
transform: function(d){
this.model.subtypes = d;
transform: function(d, self){
self.model.subtypes = d;
return d;
}
},{

View File

@ -2,7 +2,8 @@ SELECT * FROM
(SELECT format_type(t.oid,NULL) AS typname,
CASE WHEN typelem > 0 THEN typelem ELSE t.oid END AS elemoid,
typlen, typtype, t.oid, nspname,
(SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup
(SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname = t.typname) > 1 AS isdup,
CASE WHEN t.typcollation != 0 THEN TRUE ELSE FALSE END AS is_collatable
FROM pg_type t
JOIN pg_namespace nsp ON typnamespace=nsp.oid
WHERE (NOT (typname = 'unknown' AND nspname = 'pg_catalog')) AND typisdefined AND typtype IN ('b', 'c', 'd', 'e', 'r') AND NOT EXISTS (select 1 from pg_class where relnamespace=typnamespace and relname = typname and relkind != 'c') AND (typname not like '_%' OR NOT EXISTS (select 1 from pg_class where relnamespace=typnamespace and relname = substring(typname from 2)::name and relkind != 'c')) AND nsp.nspname != 'information_schema'

View File

@ -148,24 +148,6 @@ function($, _, S, pgAdmin, alertify, pgBrowser, CodeMirror) {
type: 'text', mode: ['create', 'edit'], group: 'Definition',
control: Backform.SqlFieldControl, extraClasses:['sql_field_width_full']
},
// Add Privilege Control
{
id: 'datacl', label: '{{ _("Privileges") }}',
model: pgAdmin.Browser.Node.PrivilegeRoleModel.extend(
{privileges: ['a', 'r', 'w', 'd', 'D', 'x', 't']}), uniqueCol : ['grantee'],
editable: false, type: 'collection', group: '{{ _("Security") }}',
mode: ['edit', 'create'], canAdd: true, canDelete: true,
control: 'unique-col-collection', priority: 3
},
// Add Security Labels Control
{
id: 'seclabels', label: '{{ _("Security Labels") }}',
model: Backform.SecurityModel, editable: false, type: 'collection',
canEdit: false, group: '{{ _("Security") }}', canDelete: true,
mode: ['edit', 'create'], canAdd: true,
control: 'unique-col-collection', uniqueCol : ['provider']
},
{
id: 'with_data', label: '{{ _("With Data") }}',
group: '{{ _("Storage") }}', mode: ['edit', 'create'],
@ -187,10 +169,28 @@ function($, _, S, pgAdmin, alertify, pgBrowser, CodeMirror) {
},
{
type: 'nested', control: 'tab', id: 'materialization',
label: '{{ _("Materialization") }}', mode: ['edit', 'create'],
group: '{{ _("Storage") }}',
label: '{{ _("Auto vacuum") }}', mode: ['edit', 'create'],
group: '{{ _("Auto vacuum") }}',
schema: Backform.VacuumSettingsSchema
},
// Add Privilege Control
{
id: 'datacl', label: '{{ _("Privileges") }}',
model: pgAdmin.Browser.Node.PrivilegeRoleModel.extend(
{privileges: ['a', 'r', 'w', 'd', 'D', 'x', 't']}), uniqueCol : ['grantee'],
editable: false, type: 'collection', group: '{{ _("Security") }}',
mode: ['edit', 'create'], canAdd: true, canDelete: true,
control: 'unique-col-collection', priority: 3
},
// Add Security Labels Control
{
id: 'seclabels', label: '{{ _("Security Labels") }}',
model: Backform.SecurityModel, editable: false, type: 'collection',
canEdit: false, group: '{{ _("Security") }}', canDelete: true,
mode: ['edit', 'create'], canAdd: true,
control: 'unique-col-collection', uniqueCol : ['provider']
}
],
validate: function(keys) {

View File

@ -9,13 +9,15 @@ define([
* Hmm... this module is already been initialized, we can refer to the old
* object from here.
*/
if (pgAdmin.FileManager)
return pgAdmin.FileManager;
if (pgAdmin.FileManager) {
return pgAdmin.FileManager;
}
pgAdmin.FileManager = {
init: function() {
if (this.initialized)
if (this.initialized) {
return;
}
this.initialized = true;
@ -35,7 +37,7 @@ define([
};
// Function to remove trans id from session
var removeTransId = function() {
var removeTransId = function(trans_id) {
return $.ajax({
type: "GET",
async: false,
@ -68,26 +70,26 @@ define([
});
transId = getTransId(params);
if (transId.readyState == 4)
var t_res;
if (transId.readyState == 4) {
t_res = JSON.parse(transId.responseText);
}
trans_id = t_res.data.fileTransId;
};
// Dialog property
return {
main: function(params) {
// Set title and button name
if (_.isUndefined(params['dialog_title']))
if (_.isUndefined(params['dialog_title'])) {
params['dialog_title'] = 'Storage manager';
}
this.set('title', params['dialog_title']);
if (_.isUndefined(params['btn_primary']))
if (_.isUndefined(params['btn_primary'])) {
params['btn_primary'] = 'Select';
}
this.set('label', params['btn_primary']);
var trans_id;
this.title = params.dialog_title;
params = JSON.stringify(params);
$container.find('.storage_content').remove();
$container.append("<div class='storage_content'></div>");
@ -107,6 +109,8 @@ define([
this.__internal.buttons[0].element.innerHTML = newValue;
}
break;
default:
break;
}
},
setup:function() {
@ -127,9 +131,6 @@ define([
};
},
callback: function(closeEvent) {
if (closeEvent.button.key == 13) {
//closeEvent.cancel = true;
}
if (closeEvent.button.text == "{{ _('Select') }}") {
if($('.fileinfo').data('view') == 'grid') {
sel_file = $('.fileinfo').find('#contents li.selected p span').attr('title');
@ -178,8 +179,10 @@ define([
});
transId = getTransId(configs);
if (transId.readyState == 4)
var t_res;
if (transId.readyState == 4) {
t_res = JSON.parse(transId.responseText);
}
trans_id = t_res.data.fileTransId;
};
@ -187,16 +190,15 @@ define([
return {
main: function(params) {
// Set title and button name
if (_.isUndefined(params['dialog_title']))
if (_.isUndefined(params['dialog_title'])) {
params['dialog_title'] = 'Select file';
}
this.set('title', params['dialog_title']);
if (_.isUndefined(params['btn_primary']))
if (_.isUndefined(params['btn_primary'])) {
params['btn_primary'] = 'Select';
}
this.set('label', params['btn_primary']);
var trans_id;
this.title = params.dialog_title;
params = JSON.stringify(params);
$container.find('.storage_content').remove();
$container.append("<div class='storage_content'></div>");
@ -216,6 +218,8 @@ define([
this.__internal.buttons[0].element.innerHTML = newValue;
}
break;
default:
break;
}
},
setup:function() {
@ -286,24 +290,26 @@ define([
});
transId = getTransId(params);
if (transId.readyState == 4)
var t_res;
if (transId.readyState == 4) {
t_res = JSON.parse(transId.responseText);
}
trans_id = t_res.data.fileTransId;
};
// Dialog property
return {
main: function(params) {
// Set title and button name
if (_.isUndefined(params['dialog_title']))
if (_.isUndefined(params['dialog_title'])) {
params['dialog_title'] = 'Select folder';
}
this.set('title', params['dialog_title']);
if (_.isUndefined(params['btn_primary']))
if (_.isUndefined(params['btn_primary'])) {
params['btn_primary'] = 'Select';
}
this.set('label', params['btn_primary']);
var trans_id;
params = JSON.stringify(params);
$container.find('.storage_content').remove();
$container.append("<div class='storage_content'></div>");
@ -323,6 +329,8 @@ define([
this.__internal.buttons[0].element.innerHTML = newValue;
}
break;
default:
break;
}
},
setup:function() {
@ -392,10 +400,11 @@ define([
});
transId = getTransId(params);
if (transId.readyState == 4)
var t_res;
if (transId.readyState == 4) {
t_res = JSON.parse(transId.responseText);
}
trans_id = t_res.data.fileTransId;
};
// Dialog property
@ -403,11 +412,13 @@ define([
main: function(params) {
var trans_id;
// Set title and button name
if (_.isUndefined(params['dialog_title']))
if (_.isUndefined(params['dialog_title'])) {
params['dialog_title'] = 'Create file';
}
this.set('title', params['dialog_title']);
if (_.isUndefined(params['btn_primary']))
if (_.isUndefined(params['btn_primary'])) {
params['btn_primary'] = 'Create';
}
this.set('label', params['btn_primary']);
params = JSON.stringify(params);
@ -429,6 +440,8 @@ define([
this.__internal.buttons[0].element.innerHTML = newValue;
}
break;
default:
break;
}
},
setup:function() {
@ -455,8 +468,8 @@ define([
$('.replace_file .btn_yes').click(function(self) {
$('.replace_file, .fm_dimmer').hide();
var selected_item = $('.allowed_file_types .create_input input[type="text"]').val(),
newFile = $('.currentpath').val() + selected_item,
newFile = newFile.substr(1);
sel_item = $('.currentpath').val() + selected_item,
newFile = sel_item.substr(1);
pgAdmin.Browser.Events.trigger('pgadmin-storage:finish_btn:create_file', newFile);
$('.file_manager_create_cancel').trigger('click');
});

View File

@ -1269,7 +1269,8 @@ var enab_dis_level_up = function() {
*/
var fm_url = "{{ url_for('file_manager.index') }}get_trans_id",
transId = loadData(fm_url),
t_id = '';
t_res,
t_id;
if (transId.readyState == 4) {
t_res = JSON.parse(transId.responseText);