pgadmin4/web/pgadmin/browser/server_groups/servers/static/js/variable.js

496 lines
14 KiB
JavaScript
Raw Normal View History

define([
'underscore', 'jquery', 'backbone', 'backform', 'backgrid', 'alertify',
'sources/pgadmin', 'pgadmin.browser.node', 'pgadmin.browser.node.ui'
],
function(_, $, Backbone, Backform, Backgrid, Alertify, pgAdmin, pgNode) {
/*
* cellFunction for variable control.
* This function returns cell class depending on vartype.
*/
var cellFunction = function(model) {
var self = this,
name = model.get("name"),
availVariables = {};
self.collection.each(function(col) {
if (col.get("name") == "name") {
availVariables = col.get('availVariables');
}
});
var variable = name ? availVariables[name]: undefined,
value = model.get("value");
switch(variable && variable.vartype) {
case "bool":
/*
* bool cell and variable cannot be stateless (i.e undefined).
* It should be either true or false.
*/
model.set("value", !!model.get("value"), {silent: true});
return Backgrid.Extension.SwitchCell;
break;
case "enum":
model.set({'value': value}, {silent:true});
var options = [],
enumVals = variable.enumvals;
_.each(enumVals, function(enumVal) {
options.push([enumVal, enumVal]);
});
return Backgrid.Extension.Select2Cell.extend({optionValues: options});
break;
case "integer":
if (!_.isNaN(parseInt(value))) {
model.set({'value': parseInt(value)}, {silent:true});
} else {
model.set({'value': undefined}, {silent:true});
}
return Backgrid.IntegerCell;
break;
case "real":
if (!_.isNaN(parseFloat(value))) {
model.set({'value': parseFloat(value)}, {silent:true});
} else {
model.set({'value': undefined}, {silent:true});
}
return Backgrid.NumberCell.extend({decimals: 0});
break;
case "string":
return Backgrid.StringCell;
break;
default:
model.set({'value': undefined}, {silent:true});
return Backgrid.Cell;
break;
}
model.set({'value': undefined}, {silent:true});
return Backgrid.Cell;
}
/*
* This row will define behaviour or value column cell depending upon
* variable name.
*/
var VariableRow = Backgrid.Row.extend({
modelDuplicateColor: "lightYellow",
modelUniqueColor: "#fff",
initialize: function () {
Backgrid.Row.prototype.initialize.apply(this, arguments);
var self = this;
self.model.on("change:name", function() {
setTimeout(function() {
self.columns.each(function(col) {
if (col.get('name') == 'value') {
var idx = self.columns.indexOf(col),
cf = col.get("cellFunction"),
cell = new (cf.apply(col, [self.model]))({
column: col,
model: self.model
}),
oldCell = self.cells[idx];
oldCell.remove();
self.cells[idx] = cell;
self.render();
}
});
}, 10);
});
self.listenTo(self.model, 'pgadmin-session:model:duplicate', self.modelDuplicate);
self.listenTo(self.model, 'pgadmin-session:model:unique', self.modelUnique);
},
modelDuplicate: function() {
$(this.el).removeClass("new");
this.el.style.backgroundColor = this.modelDuplicateColor;
},
modelUnique: function() {
this.el.style.backgroundColor = this.modelUniqueColor;
}
})
/**
* VariableModel used to represent configuration parameters (variables tab)
* for database objects.
**/
var VariableModel = pgNode.VariableModel = pgNode.Model.extend({
keys: ['name'],
defaults: {
name: undefined,
value: undefined,
role: null,
database: null,
},
schema: [
{
id: 'name', label:'Name', type:'text', cellHeaderClasses: 'width_percent_30',
editable: function(m) {
return (m instanceof Backbone.Collection) ? true : m.isNew();
},
cell: Backgrid.Extension.NodeAjaxOptionsCell.extend({
initialize: function() {
Backgrid.Extension.NodeAjaxOptionsCell.prototype.initialize.apply(this, arguments);
// Immediately process options as we need them before render.
var opVals = _.clone(this.optionValues ||
(_.isFunction(this.column.get('options')) ?
(this.column.get('options'))(this) :
this.column.get('options')));
this.column.set('options', opVals);
}
}),
url: 'vopts',
select2: { allowClear: false },
transform: function(vars, cell) {
var self = this,
res = [],
availVariables = {};
_.each(vars, function(v) {
res.push({
'value': v.name,
'image': undefined,
'label': v.name
});
availVariables[v.name] = v;
});
cell.column.set("availVariables", availVariables);
return res;
}
},
{
id: 'value', label:'Value', type: 'text', editable: true,
cellFunction: cellFunction, cellHeaderClasses: 'width_percent_40'
},
{id: 'database', label:'Database', type: 'text', editable: true,
node: 'database', cell: Backgrid.Extension.NodeListByNameCell
},
{id: 'role', label:'Role', type: 'text', editable: true,
node: 'role', cell: Backgrid.Extension.NodeListByNameCell}
],
toJSON: function() {
var d = Backbone.Model.prototype.toJSON.apply(this);
// Remove not defined values from model values.
// i.e.
// role, database
if (_.isUndefined(d.database) || _.isNull(d.database)) {
delete d.database;
}
if (_.isUndefined(d.role) || _.isNull(d.role)) {
delete d.role;
}
return d;
},
validate: function() {
if (_.isUndefined(this.get('name')) ||
_.isNull(this.get('name')) ||
String(this.get('name')).replace(/^\s+|\s+$/g, '') == '') {
var msg = 'Please select a parameter name.';
this.errorModel.set('name', msg);
return msg;
} else if (_.isUndefined(this.get('value')) ||
_.isNull(this.get('value')) ||
String(this.get('value')).replace(/^\s+|\s+$/g, '') == '') {
var msg = 'Please enter a value for the parameter.';
this.errorModel.set('value', msg);
return msg;
} else {
this.errorModel.unset('name');
this.errorModel.unset('value');
}
return null;
}
});
/**
* Variable Tab Control to set/update configuration values for database object.
*
**/
var VariableCollectionControl = Backform.VariableCollectionControl =
Backform.UniqueColCollectionControl.extend({
hasDatabase: false,
hasRole: false,
initialize: function(opts) {
var self = this,
keys = ['name'];
/*
* Read from field schema whether user wants to use database and role
* fields in Variable control.
*/
self.hasDatabase = opts.field.get('hasDatabase');
self.hasRole = opts.field.get('hasRole');
// Update unique coll field based on above flag status.
if (self.hasDatabase) {
keys.push('database');
} else if (self.hasRole) {
keys.push('role');
}
// Overriding the uniqueCol in the field
if (opts && opts.field) {
if (opts.field instanceof Backform.Field) {
opts.field.set({
model: pgNode.VariableModel.extend({keys:keys})
},
{
silent: true
});
} else {
opts.field.extend({
model: pgNode.VariableModel.extend({keys:keys})
});
}
}
Backform.UniqueColCollectionControl.prototype.initialize.apply(
self, arguments
);
self.availVariables = {};
var node = self.field.get('node').type,
gridCols = ['name', 'value'];
if (self.hasDatabase) {
gridCols.push('database');
}
if (self.hasRole) {
gridCols.push('role');
}
self.gridSchema = Backform.generateGridColumnsFromModel(
self.field.get('node_info'), VariableModel.extend({keys:keys}), 'edit', gridCols, self.field.get('schema_node')
);
// Make sure - we do have the data for variables
self.getVariables();
},
/*
* Get the variable data for this node.
*/
getVariables: function() {
var self = this,
url = this.field.get('url'),
m = self.model;
if (!this.field.get('version_compatible'))
return;
if (url && !m.isNew()) {
var node = self.field.get('node'),
node_data = self.field.get('node_data'),
node_info = self.field.get('node_info'),
full_url = node.generate_url.apply(
node, [
null, url, node_data, true, node_info
]),
data,
isTracking = self.collection.trackChanges;
if (isTracking) {
self.collection.stopSession();
}
m.trigger('pgadmin-view:fetching', m, self.field);
$.ajax({
async: false,
url: full_url,
success: function (res) {
data = res.data;
},
error: function() {
m.trigger('pgadmin-view:fetch:error', m, self.field);
}
});
m.trigger('pgadmin-view:fetched', m, self.field);
if (data && _.isArray(data)) {
self.collection.reset(data, {silent: true});
}
/*
* Make sure - new data will be taken care by the session management
*/
if (isTracking) {
self.collection.startNewSession();
}
}
},
showGridControl: function(data) {
var self = this,
titleTmpl = _.template([
"<div class='subnode-header'>",
"<label class='control-label'><%-label%></label>",
"<button class='btn-sm btn-default add fa fa-plus' <%=canAdd ? '' : 'disabled=\"disabled\"'%>></button>",
"</div>"].join("\n")),
$gridBody =
$("<div class='pgadmin-control-group backgrid form-group col-xs-12 object subnode'></div>").append(
titleTmpl(data)
);
// Clean up existing grid if any (in case of re-render)
if (self.grid) {
self.grid.remove();
}
var gridSchema = _.clone(this.gridSchema);
_.each(gridSchema.columns, function(col) {
if (col.name == 'value') {
col.availVariables = self.availVariables;
}
});
// Insert Delete Cell into Grid
if (data.disabled == false && data.canDelete) {
gridSchema.columns.unshift({
name: "pg-backform-delete", label: "",
cell: Backgrid.Extension.DeleteCell,
editable: false, cell_priority: -1
});
}
// Change format of each of the data
// Because - data coming from the server is in string format
self.collection.each(function(model) {
var name = model.get("name");
if (name in self.availVariables) {
switch(self.availVariables[name].vartype) {
case 'real':
var v = parseFloat(model.get('value'));
model.set('value', (isNaN(v) ? undefined : v), {silent: true});
break;
case 'integer':
var v = parseInt(model.get('value'));
model.set('value', (isNaN(v) ? undefined : v), {silent: true});
break;
default:
break;
}
}
});
// Initialize a new Grid instance
var grid = self.grid = new Backgrid.Grid({
columns: gridSchema.columns,
collection: self.collection,
row: VariableRow,
className: "backgrid table-bordered"
});
self.$grid = grid.render().$el;
$gridBody.append(self.$grid);
// Add button callback
if (!(data.disabled || data.canAdd == false)) {
$gridBody.find('button.add').first().click(function(e) {
e.preventDefault();
var canAddRow = _.isFunction(data.canAddRow) ?
data.canAddRow.apply(self, [self.model]) : true;
if (canAddRow) {
var allowMultipleEmptyRows = !!self.field.get('allowMultipleEmptyRows');
// If allowMultipleEmptyRows is not set or is false then don't allow second new empty row.
// There should be only one empty row.
if (!allowMultipleEmptyRows && self.collection) {
var isEmpty = false;
self.collection.each(function(model) {
var modelValues = [];
_.each(model.attributes, function(val, key) {
modelValues.push(val);
})
if(!_.some(modelValues, _.identity)) {
isEmpty = true;
}
});
if(isEmpty) {
return false;
}
}
$(grid.body.$el.find($("tr.new"))).removeClass("new")
var m = new (data.model) (null, {
silent: true,
handler: self.collection,
top: self.model.top || self.model,
collection: self.collection,
node_info: self.model.node_info
});
self.collection.add(m);
var idx = self.collection.indexOf(m),
newRow = grid.body.rows[idx].$el;
newRow.addClass("new");
$(newRow).pgMakeVisible('backform-tab');
return false;
}
});
}
// Render node grid
return $gridBody;
},
addVariable: function(ev) {
ev.preventDefault();
var self = this,
m = new (self.field.get('model'))(
self.headerData.toJSON(), {
silent: true, top: self.collection.top,
handler: self.collection
}),
coll = self.model.get(self.field.get('name'));
coll.add(m);
var idx = coll.indexOf(m);
// idx may not be always > -1 because our UniqueColCollection may
// remove 'm' if duplicate value found.
if (idx > -1) {
self.$grid.find('.new').removeClass('new');
var newRow = self.grid.body.rows[idx].$el;
newRow.addClass("new");
$(newRow).pgMakeVisible('backform-tab');
}
return false;
}
});
return VariableModel;
});