mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Extract the tests and refactor some of the methods.
Extract some of the ACI Tree functionalities, and decouple it from the main source. Also - create some abstractions from the repeated code around the enable/disable the schema children object create/edit/delete functionalities, and also created the dialog wrappers for backup and restore dialogs. Reviewed by: Khushboo and Ashesh Refactored by: Ashesh
This commit is contained in:
parent
920934759f
commit
7dd6372eeb
@ -1,8 +1,8 @@
|
||||
define('pgadmin.node.collation', [
|
||||
'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
|
||||
'underscore.string', 'sources/pgadmin', 'pgadmin.browser',
|
||||
'pgadmin.browser.collection',
|
||||
], function(gettext, url_for, $, _, S, pgAdmin, pgBrowser) {
|
||||
'pgadmin.node.schema.dir/child', 'pgadmin.browser.collection',
|
||||
], function(gettext, url_for, $, _, S, pgAdmin, pgBrowser, schemaChild) {
|
||||
|
||||
if (!pgBrowser.Nodes['coll-collation']) {
|
||||
pgAdmin.Browser.Nodes['coll-collation'] =
|
||||
@ -15,7 +15,7 @@ define('pgadmin.node.collation', [
|
||||
}
|
||||
|
||||
if (!pgBrowser.Nodes['collation']) {
|
||||
pgAdmin.Browser.Nodes['collation'] = pgBrowser.Node.extend({
|
||||
pgAdmin.Browser.Nodes['collation'] = schemaChild.SchemaChildNode.extend({
|
||||
type: 'collation',
|
||||
sqlAlterHelp: 'sql-altercollation.html',
|
||||
sqlCreateHelp: 'sql-createcollation.html',
|
||||
@ -222,34 +222,6 @@ define('pgadmin.node.collation', [
|
||||
return true;
|
||||
},
|
||||
}),
|
||||
canCreate: function(itemData, item, data) {
|
||||
//If check is false then , we will allow create menu
|
||||
if (data && data.check == false)
|
||||
return true;
|
||||
|
||||
var t = pgBrowser.tree, i = item, d = itemData;
|
||||
// To iterate over tree to check parent node
|
||||
while (i) {
|
||||
// If it is schema then allow user to create collation
|
||||
if (_.indexOf(['schema'], d._type) > -1)
|
||||
return true;
|
||||
|
||||
if ('coll-collation' == d._type) {
|
||||
//Check if we are not child of catalog
|
||||
var prev_i = t.hasParent(i) ? t.parent(i) : null,
|
||||
prev_d = prev_i ? t.itemData(prev_i) : null;
|
||||
if( prev_d._type == 'catalog') {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
i = t.hasParent(i) ? t.parent(i) : null;
|
||||
d = i ? t.itemData(i) : null;
|
||||
}
|
||||
// by default we do not want to allow create menu
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
}
|
||||
|
@ -2,9 +2,10 @@
|
||||
define('pgadmin.node.domain', [
|
||||
'sources/gettext', 'sources/url_for', 'jquery', 'underscore', 'backbone',
|
||||
'sources/pgadmin', 'pgadmin.browser', 'pgadmin.backform', 'pgadmin.backgrid',
|
||||
'pgadmin.browser.collection',
|
||||
'pgadmin.node.schema.dir/child', 'pgadmin.browser.collection',
|
||||
], function(
|
||||
gettext, url_for, $, _, Backbone, pgAdmin, pgBrowser, Backform, Backgrid
|
||||
gettext, url_for, $, _, Backbone, pgAdmin, pgBrowser, Backform, Backgrid,
|
||||
schemaChild
|
||||
) {
|
||||
|
||||
// Define Domain Collection Node
|
||||
@ -79,7 +80,7 @@ define('pgadmin.node.domain', [
|
||||
|
||||
// Domain Node
|
||||
if (!pgBrowser.Nodes['domain']) {
|
||||
pgBrowser.Nodes['domain'] = pgBrowser.Node.extend({
|
||||
pgBrowser.Nodes['domain'] = schemaChild.SchemaChildNode.extend({
|
||||
type: 'domain',
|
||||
sqlAlterHelp: 'sql-alterdomain.html',
|
||||
sqlCreateHelp: 'sql-createdomain.html',
|
||||
@ -88,7 +89,6 @@ define('pgadmin.node.domain', [
|
||||
collection_type: 'coll-domain',
|
||||
hasSQL: true,
|
||||
hasDepends: true,
|
||||
parent_type: ['schema', 'catalog'],
|
||||
Init: function() {
|
||||
// Avoid mulitple registration of menus
|
||||
if (this.initialized)
|
||||
@ -118,8 +118,6 @@ define('pgadmin.node.domain', [
|
||||
]);
|
||||
|
||||
},
|
||||
canDrop: pgBrowser.Nodes['schema'].canChildDrop,
|
||||
canDropCascade: pgBrowser.Nodes['schema'].canChildDrop,
|
||||
// Domain Node Model
|
||||
model: pgBrowser.Node.Model.extend({
|
||||
initialize: function(attrs, args) {
|
||||
@ -296,34 +294,6 @@ define('pgadmin.node.domain', [
|
||||
return errmsg;
|
||||
},
|
||||
}),
|
||||
canCreate: function(itemData, item, data) {
|
||||
//If check is false then , we will allow create menu
|
||||
if (data && data.check == false)
|
||||
return true;
|
||||
|
||||
var t = pgBrowser.tree, i = item, d = itemData;
|
||||
// To iterate over tree to check parent node
|
||||
while (i) {
|
||||
// If it is schema then allow user to create domain
|
||||
if (_.indexOf(['schema'], d._type) > -1)
|
||||
return true;
|
||||
|
||||
if ('coll-domain' == d._type) {
|
||||
//Check if we are not child of catalog
|
||||
var prev_i = t.hasParent(i) ? t.parent(i) : null,
|
||||
prev_d = prev_i ? t.itemData(prev_i) : null;
|
||||
if( prev_d._type == 'catalog') {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
i = t.hasParent(i) ? t.parent(i) : null;
|
||||
d = i ? t.itemData(i) : null;
|
||||
}
|
||||
// by default we do not want to allow create menu
|
||||
return true;
|
||||
},
|
||||
isDisabled: function(m){
|
||||
if (!m.isNew()) {
|
||||
var server = this.node_info.server;
|
||||
|
@ -2,9 +2,10 @@
|
||||
define('pgadmin.node.foreign_table', [
|
||||
'sources/gettext', 'sources/url_for', 'jquery', 'underscore', 'backbone',
|
||||
'sources/pgadmin', 'pgadmin.browser', 'pgadmin.backform', 'pgadmin.backgrid',
|
||||
'pgadmin.browser.collection',
|
||||
'pgadmin.node.schema.dir/child', 'pgadmin.browser.collection',
|
||||
], function(
|
||||
gettext, url_for, $, _, Backbone, pgAdmin, pgBrowser, Backform, Backgrid
|
||||
gettext, url_for, $, _, Backbone, pgAdmin, pgBrowser, Backform, Backgrid,
|
||||
schemaChild
|
||||
) {
|
||||
|
||||
if (!pgBrowser.Nodes['coll-foreign_table']) {
|
||||
@ -469,7 +470,7 @@ define('pgadmin.node.foreign_table', [
|
||||
|
||||
|
||||
if (!pgBrowser.Nodes['foreign_table']) {
|
||||
pgBrowser.Nodes['foreign_table'] = pgBrowser.Node.extend({
|
||||
pgBrowser.Nodes['foreign_table'] = schemaChild.SchemaChildNode.extend({
|
||||
type: 'foreign_table',
|
||||
sqlAlterHelp: 'sql-alterforeigntable.html',
|
||||
sqlCreateHelp: 'sql-createforeigntable.html',
|
||||
@ -509,8 +510,6 @@ define('pgadmin.node.foreign_table', [
|
||||
]);
|
||||
|
||||
},
|
||||
canDrop: pgBrowser.Nodes['schema'].canChildDrop,
|
||||
canDropCascade: pgBrowser.Nodes['schema'].canChildDrop,
|
||||
model: pgBrowser.Node.Model.extend({
|
||||
initialize: function(attrs, args) {
|
||||
var isNew = (_.size(attrs) === 0);
|
||||
@ -659,34 +658,6 @@ define('pgadmin.node.foreign_table', [
|
||||
return errmsg;
|
||||
},
|
||||
}),
|
||||
canCreate: function(itemData, item, data) {
|
||||
//If check is false then , we will allow create menu
|
||||
if (data && data.check == false)
|
||||
return true;
|
||||
|
||||
var t = pgBrowser.tree, i = item, d = itemData;
|
||||
// To iterate over tree to check parent node
|
||||
while (i) {
|
||||
// If it is schema then allow user to create foreign table
|
||||
if (_.indexOf(['schema'], d._type) > -1)
|
||||
return true;
|
||||
|
||||
if ('coll-foreign_table' == d._type) {
|
||||
//Check if we are not child of catalog
|
||||
var prev_i = t.hasParent(i) ? t.parent(i) : null,
|
||||
prev_d = prev_i ? t.itemData(prev_i) : null;
|
||||
if( prev_d._type == 'catalog') {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
i = t.hasParent(i) ? t.parent(i) : null;
|
||||
d = i ? t.itemData(i) : null;
|
||||
}
|
||||
// by default we do not want to allow create menu
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
define('pgadmin.node.fts_configuration', [
|
||||
'sources/gettext', 'sources/url_for', 'jquery', 'underscore', 'backbone',
|
||||
'sources/pgadmin', 'pgadmin.browser', 'pgadmin.backform', 'pgadmin.backgrid',
|
||||
'pgadmin.browser.collection',
|
||||
'pgadmin.node.schema.dir/child', 'pgadmin.browser.collection',
|
||||
], function(
|
||||
gettext, url_for, $, _, Backbone, pgAdmin, pgBrowser, Backform, Backgrid
|
||||
gettext, url_for, $, _, Backbone, pgAdmin, pgBrowser, Backform, Backgrid,
|
||||
schemaChild
|
||||
) {
|
||||
|
||||
// Model for tokens control
|
||||
@ -410,14 +411,11 @@ define('pgadmin.node.fts_configuration', [
|
||||
|
||||
// Extend the node class for FTS Configuration
|
||||
if (!pgBrowser.Nodes['fts_configuration']) {
|
||||
pgAdmin.Browser.Nodes['fts_configuration'] = pgAdmin.Browser.Node.extend({
|
||||
parent_type: ['schema', 'catalog'],
|
||||
pgAdmin.Browser.Nodes['fts_configuration'] = schemaChild.SchemaChildNode.extend({
|
||||
type: 'fts_configuration',
|
||||
sqlAlterHelp: 'sql-altertsconfig.html',
|
||||
sqlCreateHelp: 'sql-createtsconfig.html',
|
||||
dialogHelp: url_for('help.static', {'filename': 'fts_configuration_dialog.html'}),
|
||||
canDrop: true,
|
||||
canDropCascade: true,
|
||||
label: gettext('FTS Configuration'),
|
||||
hasSQL: true,
|
||||
hasDepends: true,
|
||||
@ -577,34 +575,6 @@ define('pgadmin.node.fts_configuration', [
|
||||
return null;
|
||||
},
|
||||
}),
|
||||
canCreate: function(itemData, item, data) {
|
||||
//If check is false then , we will allow create menu
|
||||
if (data && data.check == false)
|
||||
return true;
|
||||
|
||||
var t = pgBrowser.tree, i = item, d = itemData;
|
||||
// To iterate over tree to check parent node
|
||||
while (i) {
|
||||
// If it is schema then allow user to create fts configuration
|
||||
if (_.indexOf(['schema'], d._type) > -1)
|
||||
return true;
|
||||
|
||||
if ('coll-fts_configuration' == d._type) {
|
||||
//Check if we are not child of catalog
|
||||
var prev_i = t.hasParent(i) ? t.parent(i) : null,
|
||||
prev_d = prev_i ? t.itemData(prev_i) : null;
|
||||
if( prev_d._type == 'catalog') {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
i = t.hasParent(i) ? t.parent(i) : null;
|
||||
d = i ? t.itemData(i) : null;
|
||||
}
|
||||
// by default we do not want to allow create menu
|
||||
return true;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,10 @@
|
||||
define('pgadmin.node.fts_dictionary', [
|
||||
'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
|
||||
'underscore.string', 'sources/pgadmin', 'pgadmin.browser', 'pgadmin.backform',
|
||||
'pgadmin.browser.collection',
|
||||
], function(gettext, url_for, $, _, S, pgAdmin, pgBrowser, Backform) {
|
||||
'pgadmin.node.schema.dir/child', 'pgadmin.browser.collection',
|
||||
], function(
|
||||
gettext, url_for, $, _, S, pgAdmin, pgBrowser, Backform, schemaChild
|
||||
) {
|
||||
|
||||
// Extend the browser's node model class to create a option/value pair
|
||||
var OptionLabelModel = pgAdmin.Browser.Node.Model.extend({
|
||||
@ -55,14 +57,11 @@ define('pgadmin.node.fts_dictionary', [
|
||||
|
||||
// Extend the node class for FTS Dictionary
|
||||
if (!pgBrowser.Nodes['fts_dictionary']) {
|
||||
pgAdmin.Browser.Nodes['fts_dictionary'] = pgAdmin.Browser.Node.extend({
|
||||
parent_type: ['schema', 'catalog'],
|
||||
pgAdmin.Browser.Nodes['fts_dictionary'] = schemaChild.SchemaChildNode.extend({
|
||||
type: 'fts_dictionary',
|
||||
sqlAlterHelp: 'sql-altertsdictionary.html',
|
||||
sqlCreateHelp: 'sql-createtsdictionary.html',
|
||||
dialogHelp: url_for('help.static', {'filename': 'fts_dictionary_dialog.html'}),
|
||||
canDrop: true,
|
||||
canDropCascade: true,
|
||||
label: gettext('FTS Dictionary'),
|
||||
hasSQL: true,
|
||||
hasDepends: true,
|
||||
@ -186,34 +185,6 @@ define('pgadmin.node.fts_dictionary', [
|
||||
return null;
|
||||
},
|
||||
}),
|
||||
canCreate: function(itemData, item, data) {
|
||||
//If check is false then , we will allow create menu
|
||||
if (data && data.check == false)
|
||||
return true;
|
||||
|
||||
var t = pgBrowser.tree, i = item, d = itemData;
|
||||
// To iterate over tree to check parent node
|
||||
while (i) {
|
||||
// If it is schema then allow user to create fts dictionary
|
||||
if (_.indexOf(['schema'], d._type) > -1)
|
||||
return true;
|
||||
|
||||
if ('coll-fts_dictionary' == d._type) {
|
||||
//Check if we are not child of catalog
|
||||
var prev_i = t.hasParent(i) ? t.parent(i) : null,
|
||||
prev_d = prev_i ? t.itemData(prev_i) : null;
|
||||
if( prev_d._type == 'catalog') {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
i = t.hasParent(i) ? t.parent(i) : null;
|
||||
d = i ? t.itemData(i) : null;
|
||||
}
|
||||
// by default we do not want to allow create menu
|
||||
return true;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
define('pgadmin.node.fts_parser', [
|
||||
'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
|
||||
'sources/pgadmin', 'pgadmin.browser', 'pgadmin.browser.collection',
|
||||
], function(gettext, url_for, $, _, pgAdmin, pgBrowser) {
|
||||
'sources/pgadmin', 'pgadmin.browser', 'pgadmin.node.schema.dir/child',
|
||||
'pgadmin.browser.collection',
|
||||
], function(gettext, url_for, $, _, pgAdmin, pgBrowser, schemaChild) {
|
||||
|
||||
// Extend the collection class for fts parser
|
||||
if (!pgBrowser.Nodes['coll-fts_parser']) {
|
||||
@ -16,14 +17,11 @@ define('pgadmin.node.fts_parser', [
|
||||
|
||||
// Extend the node class for fts parser
|
||||
if (!pgBrowser.Nodes['fts_parser']) {
|
||||
pgAdmin.Browser.Nodes['fts_parser'] = pgAdmin.Browser.Node.extend({
|
||||
parent_type: ['schema', 'catalog'],
|
||||
pgAdmin.Browser.Nodes['fts_parser'] = schemaChild.SchemaChildNode.extend({
|
||||
type: 'fts_parser',
|
||||
sqlAlterHelp: 'sql-altertsparser.html',
|
||||
sqlCreateHelp: 'sql-createtsparser.html',
|
||||
dialogHelp: url_for('help.static', {'filename': 'fts_parser_dialog.html'}),
|
||||
canDrop: true,
|
||||
canDropCascade: true,
|
||||
label: gettext('FTS Parser'),
|
||||
hasSQL: true,
|
||||
hasDepends: true,
|
||||
@ -199,34 +197,6 @@ define('pgadmin.node.fts_parser', [
|
||||
return null;
|
||||
},
|
||||
}),
|
||||
canCreate: function(itemData, item, data) {
|
||||
//If check is false then , we will allow create menu
|
||||
if (data && data.check == false)
|
||||
return true;
|
||||
|
||||
var t = pgBrowser.tree, i = item, d = itemData;
|
||||
// To iterate over tree to check parent node
|
||||
while (i) {
|
||||
// If it is schema then allow user to create fts parser
|
||||
if (_.indexOf(['schema'], d._type) > -1)
|
||||
return true;
|
||||
|
||||
if ('coll-fts_parser' == d._type) {
|
||||
//Check if we are not child of catalog
|
||||
var prev_i = t.hasParent(i) ? t.parent(i) : null,
|
||||
prev_d = prev_i ? t.itemData(prev_i) : null;
|
||||
if( prev_d._type == 'catalog') {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
i = t.hasParent(i) ? t.parent(i) : null;
|
||||
d = i ? t.itemData(i) : null;
|
||||
}
|
||||
// by default we do not want to allow create menu
|
||||
return true;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
define('pgadmin.node.fts_template', [
|
||||
'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
|
||||
'sources/pgadmin', 'pgadmin.browser', 'pgadmin.browser.collection',
|
||||
], function(gettext, url_for, $, _, pgAdmin, pgBrowser) {
|
||||
'sources/pgadmin', 'pgadmin.browser', 'pgadmin.node.schema.dir/child',
|
||||
'pgadmin.browser.collection',
|
||||
], function(gettext, url_for, $, _, pgAdmin, pgBrowser, schemaChild) {
|
||||
|
||||
// Extend the collection class for fts template
|
||||
if (!pgBrowser.Nodes['coll-fts_template']) {
|
||||
@ -16,14 +17,11 @@ define('pgadmin.node.fts_template', [
|
||||
|
||||
// Extend the node class for fts template
|
||||
if (!pgBrowser.Nodes['fts_template']) {
|
||||
pgAdmin.Browser.Nodes['fts_template'] = pgAdmin.Browser.Node.extend({
|
||||
parent_type: ['schema', 'catalog'],
|
||||
pgAdmin.Browser.Nodes['fts_template'] = schemaChild.SchemaChildNode.extend({
|
||||
type: 'fts_template',
|
||||
sqlAlterHelp: 'sql-altertstemplate.html',
|
||||
sqlCreateHelp: 'sql-createtstemplate.html',
|
||||
dialogHelp: url_for('help.static', {'filename': 'fts_template_dialog.html'}),
|
||||
canDrop: true,
|
||||
canDropCascade: true,
|
||||
label: gettext('FTS Template'),
|
||||
hasSQL: true,
|
||||
hasDepends: true,
|
||||
@ -139,34 +137,6 @@ define('pgadmin.node.fts_template', [
|
||||
return null;
|
||||
},
|
||||
}),
|
||||
canCreate: function(itemData, item, data) {
|
||||
//If check is false then , we will allow create menu
|
||||
if (data && data.check == false)
|
||||
return true;
|
||||
|
||||
var t = pgBrowser.tree, i = item, d = itemData;
|
||||
// To iterate over tree to check parent node
|
||||
while (i) {
|
||||
// If it is schema then allow user to create fts fts_template
|
||||
if (_.indexOf(['schema'], d._type) > -1)
|
||||
return true;
|
||||
|
||||
if ('coll-fts_template' == d._type) {
|
||||
//Check if we are not child of catalog
|
||||
var prev_i = t.hasParent(i) ? t.parent(i) : null,
|
||||
prev_d = prev_i ? t.itemData(prev_i) : null;
|
||||
if( prev_d._type == 'catalog') {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
i = t.hasParent(i) ? t.parent(i) : null;
|
||||
d = i ? t.itemData(i) : null;
|
||||
}
|
||||
// by default we do not want to allow create menu
|
||||
return true;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -2,8 +2,11 @@
|
||||
define('pgadmin.node.function', [
|
||||
'sources/gettext', 'sources/url_for', 'jquery', 'underscore', 'backbone',
|
||||
'sources/pgadmin', 'pgadmin.browser', 'pgadmin.backform',
|
||||
'pgadmin.browser.collection', 'pgadmin.browser.server.privilege',
|
||||
], function(gettext, url_for, $, _, Backbone, pgAdmin, pgBrowser, Backform) {
|
||||
'pgadmin.node.schema.dir/child', 'pgadmin.browser.collection',
|
||||
'pgadmin.browser.server.privilege',
|
||||
], function(
|
||||
gettext, url_for, $, _, Backbone, pgAdmin, pgBrowser, Backform, schemaChild
|
||||
) {
|
||||
|
||||
if (!pgBrowser.Nodes['coll-function']) {
|
||||
pgBrowser.Nodes['coll-function'] =
|
||||
@ -83,7 +86,8 @@ define('pgadmin.node.function', [
|
||||
});
|
||||
|
||||
if (!pgBrowser.Nodes['function']) {
|
||||
pgBrowser.Nodes['function'] = pgBrowser.Node.extend({
|
||||
|
||||
pgBrowser.Nodes['function'] = schemaChild.SchemaChildNode.extend({
|
||||
type: 'function',
|
||||
sqlAlterHelp: 'sql-alterfunction.html',
|
||||
sqlCreateHelp: 'sql-createfunction.html',
|
||||
@ -96,7 +100,6 @@ define('pgadmin.node.function', [
|
||||
return treeInformation.server.server_type !== 'gpdb';
|
||||
},
|
||||
hasScriptTypes: ['create', 'select'],
|
||||
parent_type: ['schema', 'catalog'],
|
||||
Init: function() {
|
||||
/* Avoid mulitple registration of menus */
|
||||
if (this.initialized)
|
||||
@ -126,8 +129,6 @@ define('pgadmin.node.function', [
|
||||
]);
|
||||
|
||||
},
|
||||
canDrop: pgBrowser.Nodes['schema'].canChildDrop,
|
||||
canDropCascade: pgBrowser.Nodes['schema'].canChildDrop,
|
||||
model: pgBrowser.Node.Model.extend({
|
||||
initialize: function(attrs, args) {
|
||||
var isNew = (_.size(attrs) === 0);
|
||||
@ -438,34 +439,6 @@ define('pgadmin.node.function', [
|
||||
return true;
|
||||
},
|
||||
}),
|
||||
canCreate: function(itemData, item, data) {
|
||||
//If check is false then , we will allow create menu
|
||||
if (data && data.check == false)
|
||||
return true;
|
||||
|
||||
var t = pgBrowser.tree, i = item, d = itemData;
|
||||
// To iterate over tree to check parent node
|
||||
while (i) {
|
||||
// If it is schema then allow user to create Function
|
||||
if (_.indexOf(['schema'], d._type) > -1)
|
||||
return true;
|
||||
|
||||
if ('coll-function' == d._type) {
|
||||
//Check if we are not child of catalog
|
||||
var prev_i = t.hasParent(i) ? t.parent(i) : null,
|
||||
prev_d = prev_i ? t.itemData(prev_i) : null;
|
||||
if( prev_d._type == 'catalog') {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
i = t.hasParent(i) ? t.parent(i) : null;
|
||||
d = i ? t.itemData(i) : null;
|
||||
}
|
||||
// by default we do not want to allow create menu
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
}
|
||||
|
@ -2,8 +2,11 @@
|
||||
define('pgadmin.node.trigger_function', [
|
||||
'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
|
||||
'sources/pgadmin', 'pgadmin.browser', 'pgadmin.backform',
|
||||
'pgadmin.browser.collection', 'pgadmin.browser.server.privilege',
|
||||
], function(gettext, url_for, $, _, pgAdmin, pgBrowser, Backform) {
|
||||
'pgadmin.node.schema.dir/child', 'pgadmin.browser.collection',
|
||||
'pgadmin.browser.server.privilege',
|
||||
], function(
|
||||
gettext, url_for, $, _, pgAdmin, pgBrowser, Backform, schemaChild
|
||||
) {
|
||||
|
||||
if (!pgBrowser.Nodes['coll-trigger_function']) {
|
||||
pgBrowser.Nodes['coll-trigger_function'] =
|
||||
@ -17,7 +20,7 @@ define('pgadmin.node.trigger_function', [
|
||||
}
|
||||
|
||||
if (!pgBrowser.Nodes['trigger_function']) {
|
||||
pgBrowser.Nodes['trigger_function'] = pgBrowser.Node.extend({
|
||||
pgBrowser.Nodes['trigger_function'] = schemaChild.SchemaChildNode.extend({
|
||||
type: 'trigger_function',
|
||||
sqlAlterHelp: 'plpgsql-trigger.html',
|
||||
sqlCreateHelp: 'plpgsql-trigger.html',
|
||||
@ -27,7 +30,6 @@ define('pgadmin.node.trigger_function', [
|
||||
hasSQL: true,
|
||||
hasDepends: true,
|
||||
hasStatistics: true,
|
||||
parent_type: ['schema', 'catalog'],
|
||||
Init: function() {
|
||||
/* Avoid mulitple registration of menus */
|
||||
if (this.initialized)
|
||||
@ -57,8 +59,6 @@ define('pgadmin.node.trigger_function', [
|
||||
]);
|
||||
|
||||
},
|
||||
canDrop: pgBrowser.Nodes['schema'].canChildDrop,
|
||||
canDropCascade: pgBrowser.Nodes['schema'].canChildDrop,
|
||||
model: pgBrowser.Node.Model.extend({
|
||||
initialize: function(attrs, args) {
|
||||
var isNew = (_.size(attrs) === 0);
|
||||
@ -357,34 +357,6 @@ define('pgadmin.node.trigger_function', [
|
||||
return !(this.node_info && 'catalog' in this.node_info);
|
||||
},
|
||||
}),
|
||||
canCreate: function(itemData, item, data) {
|
||||
//If check is false then , we will allow create menu
|
||||
if (data && data.check == false)
|
||||
return true;
|
||||
|
||||
var t = pgBrowser.tree, i = item, d = itemData;
|
||||
// To iterate over tree to check parent node
|
||||
while (i) {
|
||||
// If it is schema then allow user to create Function
|
||||
if (_.indexOf(['schema'], d._type) > -1)
|
||||
return true;
|
||||
|
||||
if ('coll-trigger_function' == d._type) {
|
||||
//Check if we are not child of catalog
|
||||
var prev_i = t.hasParent(i) ? t.parent(i) : null,
|
||||
prev_d = prev_i ? t.itemData(prev_i) : null;
|
||||
if( prev_d._type == 'catalog') {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
i = t.hasParent(i) ? t.parent(i) : null;
|
||||
d = i ? t.itemData(i) : null;
|
||||
}
|
||||
// by default we do not want to allow create menu
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
define('pgadmin.node.sequence', [
|
||||
'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
|
||||
'underscore.string', 'sources/pgadmin', 'pgadmin.browser', 'pgadmin.backform',
|
||||
'pgadmin.browser.collection',
|
||||
], function(gettext, url_for, $, _, S, pgAdmin, pgBrowser, Backform) {
|
||||
'pgadmin.node.schema.dir/child', 'pgadmin.browser.collection',
|
||||
], function(
|
||||
gettext, url_for, $, _, S, pgAdmin, pgBrowser, Backform, schemaChild
|
||||
) {
|
||||
|
||||
// Extend the browser's collection class for sequence collection
|
||||
if (!pgBrowser.Nodes['coll-sequence']) {
|
||||
@ -18,7 +20,7 @@ define('pgadmin.node.sequence', [
|
||||
|
||||
// Extend the browser's node class for sequence node
|
||||
if (!pgBrowser.Nodes['sequence']) {
|
||||
pgBrowser.Nodes['sequence'] = pgBrowser.Node.extend({
|
||||
pgBrowser.Nodes['sequence'] = schemaChild.SchemaChildNode.extend({
|
||||
type: 'sequence',
|
||||
sqlAlterHelp: 'sql-altersequence.html',
|
||||
sqlCreateHelp: 'sql-createsequence.html',
|
||||
@ -28,7 +30,6 @@ define('pgadmin.node.sequence', [
|
||||
hasSQL: true,
|
||||
hasDepends: true,
|
||||
hasStatistics: true,
|
||||
parent_type: ['schema', 'catalog'],
|
||||
Init: function() {
|
||||
/* Avoid mulitple registration of menus */
|
||||
if (this.initialized)
|
||||
@ -58,36 +59,6 @@ define('pgadmin.node.sequence', [
|
||||
]);
|
||||
|
||||
},
|
||||
canDrop: pgBrowser.Nodes['schema'].canChildDrop,
|
||||
canDropCascade: pgBrowser.Nodes['schema'].canChildDrop,
|
||||
canCreate: function(itemData, item, data) {
|
||||
//If check is false then , we will allow create menu
|
||||
if (data && data.check == false)
|
||||
return true;
|
||||
|
||||
var t = pgBrowser.tree, i = item, d = itemData;
|
||||
// To iterate over tree to check parent node
|
||||
while (i) {
|
||||
// If it is schema then allow user to create collation
|
||||
if (_.indexOf(['schema'], d._type) > -1)
|
||||
return true;
|
||||
|
||||
if ('coll-sequence' == d._type) {
|
||||
//Check if we are not child of catalog
|
||||
var prev_i = t.hasParent(i) ? t.parent(i) : null,
|
||||
prev_d = prev_i ? t.itemData(prev_i) : null;
|
||||
if( prev_d._type == 'catalog') {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
i = t.hasParent(i) ? t.parent(i) : null;
|
||||
d = i ? t.itemData(i) : null;
|
||||
}
|
||||
// by default we want to allow create menu
|
||||
return true;
|
||||
},
|
||||
// Define the model for sequence node.
|
||||
model: pgBrowser.Node.Model.extend({
|
||||
defaults: {
|
||||
|
@ -0,0 +1,22 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
/////////////////////////////////////////////////////////////
|
||||
|
||||
import * as Node from 'pgbrowser/node';
|
||||
import {
|
||||
isTreeItemOfChildOfSchema, childCreateMenuEnabled,
|
||||
} from './schema_child_tree_node';
|
||||
|
||||
let SchemaChildNode = Node.extend({
|
||||
parent_type: ['schema', 'catalog'],
|
||||
canDrop: isTreeItemOfChildOfSchema,
|
||||
canDropCascade: isTreeItemOfChildOfSchema,
|
||||
canCreate: childCreateMenuEnabled,
|
||||
}, false);
|
||||
|
||||
export {SchemaChildNode};
|
@ -425,54 +425,10 @@ define('pgadmin.node.schema', [
|
||||
return null;
|
||||
},
|
||||
}),
|
||||
// This function will checks whether we can allow user to
|
||||
// drop object or not based on location within schema & catalog
|
||||
canChildDrop: function(itemData, item) {
|
||||
var t = pgBrowser.tree, i = item, d = itemData;
|
||||
// To iterate over tree to check parent node
|
||||
while (i) {
|
||||
// If it is schema then allow user to create collation
|
||||
if (_.indexOf(['schema'], d._type) > -1)
|
||||
return true;
|
||||
|
||||
//Check if we are not child of catalog
|
||||
var prev_i = t.hasParent(i) ? t.parent(i) : null,
|
||||
prev_d = prev_i ? t.itemData(prev_i) : null;
|
||||
if(prev_d && prev_d._type == 'catalog') {
|
||||
return false;
|
||||
}
|
||||
i = t.hasParent(i) ? t.parent(i) : null;
|
||||
d = i ? t.itemData(i) : null;
|
||||
}
|
||||
// by default we do not want to allow create menu
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
pgBrowser.tableChildTreeNodeHierarchy = function(i) {
|
||||
var idx = 0,
|
||||
res = {},
|
||||
t = pgBrowser.tree;
|
||||
|
||||
do {
|
||||
var d = t.itemData(i);
|
||||
if (
|
||||
d._type in pgBrowser.Nodes && pgBrowser.Nodes[d._type].hasId
|
||||
) {
|
||||
if (d._type === 'partition' || d._type === 'table') {
|
||||
if (!('table' in res)) {
|
||||
res['table'] = _.extend({}, d, {'priority': idx});
|
||||
idx -= 1;
|
||||
}
|
||||
} else {
|
||||
res[d._type] = _.extend({}, d, {'priority': idx});
|
||||
idx -= 1;
|
||||
}
|
||||
}
|
||||
i = t.hasParent(i) ? t.parent(i) : null;
|
||||
} while (i);
|
||||
|
||||
return res;
|
||||
return this.getTreeNodeHierarchy(i);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,41 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
/////////////////////////////////////////////////////////////
|
||||
|
||||
import * as pgBrowser from 'pgbrowser/browser';
|
||||
|
||||
export function childCreateMenuEnabled(itemData, item, data) {
|
||||
// If check is false then , we will allow create menu
|
||||
if (data && data.check === false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
let node = pgBrowser.treeMenu.findNodeByDomElement(item);
|
||||
|
||||
if (node)
|
||||
return node.anyFamilyMember(
|
||||
(node) => (node.getData()._type === 'schema')
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isTreeItemOfChildOfSchema(itemData, item) {
|
||||
let node = pgBrowser.treeMenu.findNodeByDomElement(item);
|
||||
|
||||
if (node)
|
||||
return isTreeNodeOfSchemaChild(node);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isTreeNodeOfSchemaChild(node) {
|
||||
return node.anyParent(
|
||||
(parentNode) => (parentNode.getData()._type === 'schema')
|
||||
);
|
||||
}
|
@ -88,7 +88,6 @@ define('pgadmin.node.column', [
|
||||
|
||||
if (!pgBrowser.Nodes['column']) {
|
||||
pgBrowser.Nodes['column'] = pgBrowser.Node.extend({
|
||||
getTreeNodeHierarchy: pgBrowser.tableChildTreeNodeHierarchy,
|
||||
parent_type: ['table', 'view', 'mview'],
|
||||
collection_type: ['coll-table', 'coll-view', 'coll-mview'],
|
||||
type: 'column',
|
||||
@ -97,27 +96,24 @@ define('pgadmin.node.column', [
|
||||
sqlAlterHelp: 'sql-altertable.html',
|
||||
sqlCreateHelp: 'sql-altertable.html',
|
||||
dialogHelp: url_for('help.static', {'filename': 'column_dialog.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 = [];
|
||||
// To iterate over tree to check parent node
|
||||
while (i) {
|
||||
parents.push(d._type);
|
||||
i = t.hasParent(i) ? t.parent(i) : null;
|
||||
d = i ? t.itemData(i) : null;
|
||||
}
|
||||
canDrop: function(itemData, item){
|
||||
let node = pgBrowser.treeMenu.findNodeByDomElement(item);
|
||||
|
||||
// Check if menu is allowed ?
|
||||
if(_.indexOf(parents, 'catalog') > -1 ||
|
||||
_.indexOf(parents, 'view') > -1 ||
|
||||
_.indexOf(parents, 'mview') > -1) {
|
||||
return false;
|
||||
} else if(_.indexOf(parents, 'table') > -1) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (!node)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only a column of a table can be droped, and only when it is not of
|
||||
// catalog.
|
||||
return node.anyParent(
|
||||
(parentNode) => (
|
||||
parentNode.getData()._type === 'table' &&
|
||||
!parentNode.anyParent(
|
||||
(grandParentNode) => (
|
||||
grandParentNode.getData()._type === 'catalog'
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
},
|
||||
hasDepends: true,
|
||||
hasStatistics: true,
|
||||
|
@ -8,7 +8,6 @@ define('pgadmin.node.check_constraint', [
|
||||
// Check Constraint Node
|
||||
if (!pgBrowser.Nodes['check_constraint']) {
|
||||
pgAdmin.Browser.Nodes['check_constraint'] = pgBrowser.Node.extend({
|
||||
getTreeNodeHierarchy: pgBrowser.tableChildTreeNodeHierarchy,
|
||||
type: 'check_constraint',
|
||||
label: gettext('Check'),
|
||||
collection_type: 'coll-constraints',
|
||||
|
@ -605,7 +605,6 @@ define('pgadmin.node.exclusion_constraint', [
|
||||
// Extend the browser's node class for exclusion constraint node
|
||||
if (!pgBrowser.Nodes['exclusion_constraint']) {
|
||||
pgAdmin.Browser.Nodes['exclusion_constraint'] = pgBrowser.Node.extend({
|
||||
getTreeNodeHierarchy: pgBrowser.tableChildTreeNodeHierarchy,
|
||||
type: 'exclusion_constraint',
|
||||
label: gettext('Exclusion constraint'),
|
||||
collection_type: 'coll-constraints',
|
||||
|
@ -603,7 +603,6 @@ define('pgadmin.node.foreign_key', [
|
||||
// Extend the browser's node class for foreign key node
|
||||
if (!pgBrowser.Nodes['foreign_key']) {
|
||||
pgAdmin.Browser.Nodes['foreign_key'] = pgBrowser.Node.extend({
|
||||
getTreeNodeHierarchy: pgBrowser.tableChildTreeNodeHierarchy,
|
||||
type: 'foreign_key',
|
||||
label: gettext('Foreign key'),
|
||||
collection_type: 'coll-constraints',
|
||||
|
@ -20,7 +20,6 @@ define('pgadmin.node.primary_key', [
|
||||
parent_type: ['table','partition'],
|
||||
canDrop: true,
|
||||
canDropCascade: true,
|
||||
getTreeNodeHierarchy: pgBrowser.tableChildTreeNodeHierarchy,
|
||||
Init: function() {
|
||||
/* Avoid multiple registration of menus */
|
||||
if (this.initialized)
|
||||
|
@ -20,7 +20,6 @@ define('pgadmin.node.unique_constraint', [
|
||||
parent_type: ['table','partition'],
|
||||
canDrop: true,
|
||||
canDropCascade: true,
|
||||
getTreeNodeHierarchy: pgBrowser.tableChildTreeNodeHierarchy,
|
||||
Init: function() {
|
||||
/* Avoid multiple registration of menus */
|
||||
if (this.initialized)
|
||||
|
@ -12,14 +12,12 @@ define('pgadmin.node.constraints', [
|
||||
node: 'constraints',
|
||||
label: gettext('Constraints'),
|
||||
type: 'coll-constraints',
|
||||
getTreeNodeHierarchy: pgBrowser.tableChildTreeNodeHierarchy,
|
||||
columns: ['name', 'comment'],
|
||||
});
|
||||
}
|
||||
|
||||
if (!pgBrowser.Nodes['constraints']) {
|
||||
pgAdmin.Browser.Nodes['constraints'] = pgBrowser.Node.extend({
|
||||
getTreeNodeHierarchy: pgBrowser.tableChildTreeNodeHierarchy,
|
||||
type: 'constraints',
|
||||
label: gettext('Constraints'),
|
||||
collection_type: 'coll-constraints',
|
||||
|
@ -1,10 +1,12 @@
|
||||
define('pgadmin.node.index', [
|
||||
'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
|
||||
'backbone', 'sources/pgadmin', 'pgadmin.browser', 'pgadmin.alertifyjs',
|
||||
'pgadmin.backform', 'pgadmin.backgrid', 'pgadmin.browser.collection',
|
||||
'pgadmin.backform', 'pgadmin.backgrid',
|
||||
'pgadmin.node.schema.dir/schema_child_tree_node',
|
||||
'pgadmin.browser.collection',
|
||||
], function(
|
||||
gettext, url_for, $, _, Backbone, pgAdmin, pgBrowser, Alertify, Backform,
|
||||
Backgrid
|
||||
Backgrid, SchemaChildTreeNode
|
||||
) {
|
||||
|
||||
if (!pgBrowser.Nodes['coll-index']) {
|
||||
@ -13,7 +15,6 @@ define('pgadmin.node.index', [
|
||||
node: 'index',
|
||||
label: gettext('Indexes'),
|
||||
type: 'coll-index',
|
||||
getTreeNodeHierarchy: pgBrowser.tableChildTreeNodeHierarchy,
|
||||
sqlAlterHelp: 'sql-alterindex.html',
|
||||
sqlCreateHelp: 'sql-createindex.html',
|
||||
dialogHelp: url_for('help.static', {'filename': 'index_dialog.html'}),
|
||||
@ -215,7 +216,6 @@ define('pgadmin.node.index', [
|
||||
|
||||
if (!pgBrowser.Nodes['index']) {
|
||||
pgAdmin.Browser.Nodes['index'] = pgBrowser.Node.extend({
|
||||
getTreeNodeHierarchy: pgBrowser.tableChildTreeNodeHierarchy,
|
||||
parent_type: ['table', 'view', 'mview', 'partition'],
|
||||
collection_type: ['coll-table', 'coll-view'],
|
||||
sqlAlterHelp: 'sql-alterindex.html',
|
||||
@ -266,8 +266,8 @@ define('pgadmin.node.index', [
|
||||
},
|
||||
]);
|
||||
},
|
||||
canDrop: pgBrowser.Nodes['schema'].canChildDrop,
|
||||
canDropCascade: pgBrowser.Nodes['schema'].canChildDrop,
|
||||
canDrop: SchemaChildTreeNode.isTreeItemOfChildOfSchema,
|
||||
canDropCascade: SchemaChildTreeNode.isTreeItemOfChildOfSchema,
|
||||
model: pgAdmin.Browser.Node.Model.extend({
|
||||
idAttribute: 'oid',
|
||||
|
||||
|
@ -2,10 +2,12 @@ define([
|
||||
'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
|
||||
'underscore.string', 'sources/pgadmin', 'pgadmin.browser',
|
||||
'pgadmin.alertifyjs', 'pgadmin.backform', 'pgadmin.backgrid',
|
||||
'pgadmin.node.schema.dir/schema_child_tree_node',
|
||||
'pgadmin.browser.collection', 'pgadmin.browser.table.partition.utils',
|
||||
],
|
||||
function(
|
||||
gettext, url_for, $, _, S, pgAdmin, pgBrowser, Alertify, Backform, Backgrid
|
||||
gettext, url_for, $, _, S, pgAdmin, pgBrowser, Alertify, Backform, Backgrid,
|
||||
SchemaChildTreeNode
|
||||
) {
|
||||
|
||||
if (!pgBrowser.Nodes['coll-partition']) {
|
||||
@ -13,7 +15,6 @@ function(
|
||||
pgAdmin.Browser.Collection.extend({
|
||||
node: 'partition',
|
||||
label: gettext('Partitions'),
|
||||
getTreeNodeHierarchy: pgBrowser.tableChildTreeNodeHierarchy,
|
||||
type: 'coll-partition',
|
||||
columns: [
|
||||
'name', 'schema', 'partition_value', 'is_partitioned', 'description',
|
||||
@ -80,36 +81,6 @@ function(
|
||||
},
|
||||
]);
|
||||
},
|
||||
getTreeNodeHierarchy: function(i) {
|
||||
var idx = 0,
|
||||
res = {},
|
||||
t = pgBrowser.tree;
|
||||
|
||||
do {
|
||||
var d = t.itemData(i);
|
||||
if (
|
||||
d._type in pgBrowser.Nodes && pgBrowser.Nodes[d._type].hasId
|
||||
) {
|
||||
if (d._type == 'partition' && 'partition' in res) {
|
||||
if (!('table' in res)) {
|
||||
res['table'] = _.extend({}, d, {'priority': idx});
|
||||
idx -= 1;
|
||||
}
|
||||
} else if (d._type == 'table') {
|
||||
if (!('table' in res)) {
|
||||
res['table'] = _.extend({}, d, {'priority': idx});
|
||||
idx -= 1;
|
||||
}
|
||||
} else {
|
||||
res[d._type] = _.extend({}, d, {'priority': idx});
|
||||
idx -= 1;
|
||||
}
|
||||
}
|
||||
i = t.hasParent(i) ? t.parent(i) : null;
|
||||
} while (i);
|
||||
|
||||
return res;
|
||||
},
|
||||
generate_url: function(item, type, d, with_id, info) {
|
||||
if (_.indexOf([
|
||||
'stats', 'statistics', 'dependency', 'dependent', 'reset',
|
||||
@ -133,8 +104,8 @@ function(
|
||||
encodeURIComponent(info['partition']._id)
|
||||
).value();
|
||||
},
|
||||
canDrop: pgBrowser.Nodes['schema'].canChildDrop,
|
||||
canDropCascade: pgBrowser.Nodes['schema'].canChildDrop,
|
||||
canDrop: SchemaChildTreeNode.isTreeItemOfChildOfSchema,
|
||||
canDropCascade: SchemaChildTreeNode.isTreeItemOfChildOfSchema,
|
||||
callbacks: {
|
||||
/* Enable trigger(s) on table */
|
||||
enable_triggers_on_table: function(args) {
|
||||
@ -1189,34 +1160,7 @@ function(
|
||||
return data;
|
||||
},
|
||||
}),
|
||||
canCreate: function(itemData, item, data) {
|
||||
//If check is false then , we will allow create menu
|
||||
if (data && data.check == false)
|
||||
return true;
|
||||
|
||||
var t = pgBrowser.tree, i = item, d = itemData;
|
||||
// To iterate over tree to check parent node
|
||||
while (i) {
|
||||
// If it is schema then allow user to create table
|
||||
if (_.indexOf(['schema'], d._type) > -1)
|
||||
return true;
|
||||
|
||||
if ('coll-table' == d._type) {
|
||||
//Check if we are not child of catalog
|
||||
var prev_i = t.hasParent(i) ? t.parent(i) : null;
|
||||
var prev_d = prev_i ? t.itemData(prev_i) : null;
|
||||
if( prev_d._type == 'catalog') {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
i = t.hasParent(i) ? t.parent(i) : null;
|
||||
d = i ? t.itemData(i) : null;
|
||||
}
|
||||
// by default we do not want to allow create menu
|
||||
return true;
|
||||
},
|
||||
canCreate: SchemaChildTreeNode.isTreeItemOfChildOfSchema,
|
||||
// Check to whether table has disable trigger(s)
|
||||
canCreate_with_trigger_enable: function(itemData, item, data) {
|
||||
if(this.canCreate.apply(this, [itemData, item, data])) {
|
||||
|
@ -16,7 +16,6 @@ define('pgadmin.node.rule', [
|
||||
node: 'rule',
|
||||
label: gettext('Rules'),
|
||||
type: 'coll-rule',
|
||||
getTreeNodeHierarchy: pgBrowser.tableChildTreeNodeHierarchy,
|
||||
columns: ['name', 'owner', 'comment'],
|
||||
});
|
||||
}
|
||||
@ -35,7 +34,6 @@ define('pgadmin.node.rule', [
|
||||
*/
|
||||
if (!pgBrowser.Nodes['rule']) {
|
||||
pgAdmin.Browser.Nodes['rule'] = pgBrowser.Node.extend({
|
||||
getTreeNodeHierarchy: pgBrowser.tableChildTreeNodeHierarchy,
|
||||
parent_type: ['table','view', 'partition'],
|
||||
type: 'rule',
|
||||
sqlAlterHelp: 'sql-alterrule.html',
|
||||
|
@ -0,0 +1,52 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import axios from 'axios';
|
||||
|
||||
export function disableTriggers(tree, alertify, generateUrl, args) {
|
||||
return setTriggers(tree, alertify, generateUrl, args, {enable: 'false' });
|
||||
}
|
||||
export function enableTriggers(tree, alertify, generateUrl, args) {
|
||||
return setTriggers(tree, alertify, generateUrl, args, {enable: 'true' });
|
||||
}
|
||||
|
||||
function setTriggers(tree, alertify, generateUrl, args, params) {
|
||||
const treeNode = retrieveTreeNode(args, tree);
|
||||
|
||||
if (!treeNode || treeNode.getData() === null || treeNode.getData() === undefined)
|
||||
return false;
|
||||
|
||||
axios.put(
|
||||
generateUrl(treeNode.getHtmlIdentifier(), 'set_trigger', treeNode.getData(), true),
|
||||
params
|
||||
)
|
||||
.then((res) => {
|
||||
if (res.data.success === 1) {
|
||||
alertify.success(res.data.info);
|
||||
treeNode.reload(tree);
|
||||
}
|
||||
})
|
||||
.catch((xhr) => {
|
||||
try {
|
||||
const err = xhr.response.data;
|
||||
if (err.success === 0) {
|
||||
alertify.error(err.errormsg);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn(e.stack || e);
|
||||
}
|
||||
treeNode.unload(tree);
|
||||
});
|
||||
}
|
||||
|
||||
function retrieveTreeNode(args, tree) {
|
||||
const input = args || {};
|
||||
const domElementIdentifier = input.item || tree.selected();
|
||||
return tree.findNodeByDomElement(domElementIdentifier);
|
||||
}
|
@ -1,13 +1,16 @@
|
||||
define('pgadmin.node.table', [
|
||||
'pgadmin.tables.js/enable_disable_triggers',
|
||||
'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
|
||||
'underscore.string', 'sources/pgadmin', 'pgadmin.browser',
|
||||
'pgadmin.alertifyjs', 'pgadmin.backform', 'pgadmin.backgrid',
|
||||
'pgadmin.tables.js/show_advanced_tab',
|
||||
'pgadmin.browser.collection', 'pgadmin.node.column',
|
||||
'pgadmin.node.constraints', 'pgadmin.browser.table.partition.utils',
|
||||
'pgadmin.node.schema.dir/child', 'pgadmin.browser.collection',
|
||||
'pgadmin.node.column', 'pgadmin.node.constraints',
|
||||
'pgadmin.browser.table.partition.utils',
|
||||
], function(
|
||||
tableFunctions,
|
||||
gettext, url_for, $, _, S, pgAdmin, pgBrowser, Alertify, Backform, Backgrid,
|
||||
ShowAdvancedTab
|
||||
ShowAdvancedTab, SchemaChild
|
||||
) {
|
||||
|
||||
if (!pgBrowser.Nodes['coll-table']) {
|
||||
@ -25,8 +28,7 @@ define('pgadmin.node.table', [
|
||||
}
|
||||
|
||||
if (!pgBrowser.Nodes['table']) {
|
||||
pgBrowser.Nodes['table'] = pgBrowser.Node.extend({
|
||||
getTreeNodeHierarchy: pgBrowser.tableChildTreeNodeHierarchy,
|
||||
pgBrowser.Nodes['table'] = SchemaChild.SchemaChildNode.extend({
|
||||
type: 'table',
|
||||
label: gettext('Table'),
|
||||
collection_type: 'coll-table',
|
||||
@ -39,7 +41,6 @@ define('pgadmin.node.table', [
|
||||
sqlAlterHelp: 'sql-altertable.html',
|
||||
sqlCreateHelp: 'sql-createtable.html',
|
||||
dialogHelp: url_for('help.static', {'filename': 'table_dialog.html'}),
|
||||
parent_type: ['schema', 'catalog'],
|
||||
hasScriptTypes: ['create', 'select', 'insert', 'update', 'delete'],
|
||||
height: '95%',
|
||||
width: '85%',
|
||||
@ -113,51 +114,24 @@ define('pgadmin.node.table', [
|
||||
this.handle_cache, this
|
||||
);
|
||||
},
|
||||
canDrop: pgBrowser.Nodes['schema'].canChildDrop,
|
||||
canDropCascade: pgBrowser.Nodes['schema'].canChildDrop,
|
||||
callbacks: {
|
||||
/* Enable trigger(s) on table */
|
||||
enable_triggers_on_table: function(args) {
|
||||
var params = {'enable': true };
|
||||
this.callbacks.set_triggers.apply(this, [args, params]);
|
||||
tableFunctions.enableTriggers(
|
||||
pgBrowser.treeMenu,
|
||||
Alertify,
|
||||
this.generate_url.bind(this),
|
||||
args
|
||||
);
|
||||
},
|
||||
/* Disable trigger(s) on table */
|
||||
disable_triggers_on_table: function(args) {
|
||||
var params = {'enable': false };
|
||||
this.callbacks.set_triggers.apply(this, [args, params]);
|
||||
},
|
||||
set_triggers: function(args, params) {
|
||||
// This function will send request to enable or
|
||||
// disable triggers on table level
|
||||
var input = args || {},
|
||||
obj = this,
|
||||
t = pgBrowser.tree,
|
||||
i = input.item || t.selected(),
|
||||
d = i && i.length == 1 ? t.itemData(i) : undefined;
|
||||
if (!d)
|
||||
return false;
|
||||
|
||||
$.ajax({
|
||||
url: obj.generate_url(i, 'set_trigger' , d, true),
|
||||
type:'PUT',
|
||||
data: params,
|
||||
dataType: 'json',
|
||||
success: function(res) {
|
||||
if (res.success == 1) {
|
||||
Alertify.success(res.info);
|
||||
t.unload(i);
|
||||
t.setInode(i);
|
||||
t.deselect(i);
|
||||
setTimeout(function() {
|
||||
t.select(i);
|
||||
}, 10);
|
||||
}
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
Alertify.pgRespErrorNotify(xhr, error);
|
||||
t.unload(i);
|
||||
},
|
||||
});
|
||||
tableFunctions.disableTriggers(
|
||||
pgBrowser.treeMenu,
|
||||
Alertify,
|
||||
this.generate_url.bind(this),
|
||||
args
|
||||
);
|
||||
},
|
||||
/* Truncate table */
|
||||
truncate_table: function(args) {
|
||||
@ -1299,55 +1273,15 @@ define('pgadmin.node.table', [
|
||||
return data;
|
||||
},
|
||||
}),
|
||||
canCreate: function(itemData, item, data) {
|
||||
//If check is false then , we will allow create menu
|
||||
if (data && data.check == false)
|
||||
return true;
|
||||
|
||||
var t = pgBrowser.tree, i = item, d = itemData;
|
||||
// To iterate over tree to check parent node
|
||||
while (i) {
|
||||
// If it is schema then allow user to create table
|
||||
if (_.indexOf(['schema'], d._type) > -1)
|
||||
return true;
|
||||
|
||||
if ('coll-table' == d._type) {
|
||||
//Check if we are not child of catalog
|
||||
var prev_i = t.hasParent(i) ? t.parent(i) : null,
|
||||
prev_d = prev_i ? t.itemData(prev_i) : null;
|
||||
if( prev_d._type == 'catalog') {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
i = t.hasParent(i) ? t.parent(i) : null;
|
||||
d = i ? t.itemData(i) : null;
|
||||
}
|
||||
// by default we do not want to allow create menu
|
||||
return true;
|
||||
},
|
||||
// Check to whether table has disable trigger(s)
|
||||
canCreate_with_trigger_enable: function(itemData, item, data) {
|
||||
if(this.canCreate.apply(this, [itemData, item, data])) {
|
||||
// We are here means we can create menu, now let's check condition
|
||||
if(itemData.tigger_count > 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return itemData.tigger_count > 0 &&
|
||||
this.canCreate.apply(this, [itemData, item, data]);
|
||||
},
|
||||
// Check to whether table has enable trigger(s)
|
||||
canCreate_with_trigger_disable: function(itemData, item, data) {
|
||||
if(this.canCreate.apply(this, [itemData, item, data])) {
|
||||
// We are here means we can create menu, now let's check condition
|
||||
if(itemData.tigger_count > 0 && itemData.has_enable_triggers > 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return itemData.tigger_count > 0 && itemData.has_enable_triggers > 0 &&
|
||||
this.canCreate.apply(this, [itemData, item, data]);
|
||||
},
|
||||
onTableUpdated: function(_node, _oldNodeData, _newNodeData) {
|
||||
var key, childIDs;
|
||||
|
@ -1,8 +1,13 @@
|
||||
define('pgadmin.node.trigger', [
|
||||
'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
|
||||
'underscore.string', 'sources/pgadmin', 'pgadmin.browser', 'backform', 'pgadmin.alertifyjs',
|
||||
'underscore.string', 'sources/pgadmin', 'pgadmin.browser',
|
||||
'pgadmin.backform', 'pgadmin.alertifyjs',
|
||||
'pgadmin.node.schema.dir/schema_child_tree_node',
|
||||
'pgadmin.browser.collection',
|
||||
], function(gettext, url_for, $, _, S, pgAdmin, pgBrowser, Backform, alertify) {
|
||||
], function(
|
||||
gettext, url_for, $, _, S, pgAdmin, pgBrowser, Backform, alertify,
|
||||
SchemaChildTreeNode
|
||||
) {
|
||||
|
||||
Backform.CustomSwitchControl = Backform.SwitchControl.extend({
|
||||
template: _.template([
|
||||
@ -29,14 +34,12 @@ define('pgadmin.node.trigger', [
|
||||
node: 'trigger',
|
||||
label: gettext('Triggers'),
|
||||
type: 'coll-trigger',
|
||||
getTreeNodeHierarchy: pgBrowser.tableChildTreeNodeHierarchy,
|
||||
columns: ['name', 'description'],
|
||||
});
|
||||
}
|
||||
|
||||
if (!pgBrowser.Nodes['trigger']) {
|
||||
pgAdmin.Browser.Nodes['trigger'] = pgBrowser.Node.extend({
|
||||
getTreeNodeHierarchy: pgBrowser.tableChildTreeNodeHierarchy,
|
||||
parent_type: ['table', 'view', 'partition'],
|
||||
collection_type: ['coll-table', 'coll-view'],
|
||||
type: 'trigger',
|
||||
@ -175,8 +178,8 @@ define('pgadmin.node.trigger', [
|
||||
});
|
||||
},
|
||||
},
|
||||
canDrop: pgBrowser.Nodes['schema'].canChildDrop,
|
||||
canDropCascade: pgBrowser.Nodes['schema'].canChildDrop,
|
||||
canDrop: SchemaChildTreeNode.isTreeItemOfChildOfSchema,
|
||||
canDropCascade: SchemaChildTreeNode.isTreeItemOfChildOfSchema,
|
||||
model: pgAdmin.Browser.Node.Model.extend({
|
||||
defaults: {
|
||||
name: undefined,
|
||||
@ -618,50 +621,16 @@ define('pgadmin.node.trigger', [
|
||||
return flag;
|
||||
},
|
||||
}),
|
||||
// Below function will enable right click menu for creating column
|
||||
canCreate: function(itemData, item, data) {
|
||||
// If check is false then , we will allow create menu
|
||||
if (data && data.check == false)
|
||||
return true;
|
||||
|
||||
var t = pgBrowser.tree, i = item, d = itemData, parents = [];
|
||||
// To iterate over tree to check parent node
|
||||
while (i) {
|
||||
// If it is schema then allow user to c reate table
|
||||
if (_.indexOf(['schema'], d._type) > -1)
|
||||
return true;
|
||||
parents.push(d._type);
|
||||
i = t.hasParent(i) ? t.parent(i) : null;
|
||||
d = i ? t.itemData(i) : null;
|
||||
}
|
||||
// If node is under catalog then do not allow 'create' menu
|
||||
if (_.indexOf(parents, 'catalog') > -1) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
canCreate: SchemaChildTreeNode.isTreeItemOfChildOfSchema,
|
||||
// Check to whether trigger is disable ?
|
||||
canCreate_with_trigger_enable: function(itemData, item, data) {
|
||||
if(this.canCreate.apply(this, [itemData, item, data])) {
|
||||
// We are here means we can create menu, now let's check condition
|
||||
if(itemData.icon === 'icon-trigger-bad') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return itemData.icon === 'icon-trigger-bad' &&
|
||||
this.canCreate.apply(this, [itemData, item, data]);
|
||||
},
|
||||
// Check to whether trigger is enable ?
|
||||
canCreate_with_trigger_disable: function(itemData, item, data) {
|
||||
if(this.canCreate.apply(this, [itemData, item, data])) {
|
||||
// We are here means we can create menu, now let's check condition
|
||||
if(itemData.icon === 'icon-trigger') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return itemData.icon === 'icon-trigger' &&
|
||||
this.canCreate.apply(this, [itemData, item, data]);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
@ -1,8 +1,12 @@
|
||||
define('pgadmin.node.type', [
|
||||
'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
|
||||
'sources/pgadmin', 'pgadmin.browser', 'pgadmin.backform',
|
||||
'pgadmin.backgrid', 'pgadmin.browser.collection',
|
||||
], function(gettext, url_for, $, _, pgAdmin, pgBrowser, Backform, Backgrid) {
|
||||
'pgadmin.backgrid', 'pgadmin.node.schema.dir/child',
|
||||
'pgadmin.browser.collection',
|
||||
], function(
|
||||
gettext, url_for, $, _, pgAdmin, pgBrowser, Backform, Backgrid,
|
||||
schemaChild
|
||||
) {
|
||||
|
||||
if (!pgBrowser.Nodes['coll-type']) {
|
||||
pgBrowser.Nodes['coll-type'] =
|
||||
@ -245,7 +249,7 @@ define('pgadmin.node.type', [
|
||||
});
|
||||
|
||||
if (!pgBrowser.Nodes['type']) {
|
||||
pgBrowser.Nodes['type'] = pgBrowser.Node.extend({
|
||||
pgBrowser.Nodes['type'] = schemaChild.SchemaChildNode.extend({
|
||||
type: 'type',
|
||||
sqlAlterHelp: 'sql-altertype.html',
|
||||
sqlCreateHelp: 'sql-createtype.html',
|
||||
@ -254,7 +258,6 @@ define('pgadmin.node.type', [
|
||||
collection_type: 'coll-type',
|
||||
hasSQL: true,
|
||||
hasDepends: true,
|
||||
parent_type: ['schema', 'catalog'],
|
||||
Init: function() {
|
||||
/* Avoid multiple registration of menus */
|
||||
if (this.initialized)
|
||||
@ -284,8 +287,6 @@ define('pgadmin.node.type', [
|
||||
]);
|
||||
|
||||
},
|
||||
canDrop: pgBrowser.Nodes['schema'].canChildDrop,
|
||||
canDropCascade: pgBrowser.Nodes['schema'].canChildDrop,
|
||||
ext_funcs: undefined,
|
||||
model: pgBrowser.Node.Model.extend({
|
||||
defaults: {
|
||||
@ -911,34 +912,6 @@ define('pgadmin.node.type', [
|
||||
return result;
|
||||
},
|
||||
}),
|
||||
canCreate: function(itemData, item, data) {
|
||||
//If check is false then , we will allow create menu
|
||||
if (data && data.check == false)
|
||||
return true;
|
||||
|
||||
var t = pgBrowser.tree, i = item, d = itemData;
|
||||
// To iterate over tree to check parent node
|
||||
while (i) {
|
||||
// If it is schema then allow user to create table
|
||||
if (_.indexOf(['schema'], d._type) > -1)
|
||||
return true;
|
||||
|
||||
if ('coll-type' == d._type) {
|
||||
//Check if we are not child of catalog
|
||||
var prev_i = t.hasParent(i) ? t.parent(i) : null,
|
||||
prev_d = prev_i ? t.itemData(prev_i) : null;
|
||||
if( prev_d._type == 'catalog') {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
i = t.hasParent(i) ? t.parent(i) : null;
|
||||
d = i ? t.itemData(i) : null;
|
||||
}
|
||||
// by default we do not want to allow create menu
|
||||
return true;
|
||||
},
|
||||
});
|
||||
}
|
||||
return pgBrowser.Nodes['type'];
|
||||
|
@ -1,8 +1,12 @@
|
||||
define('pgadmin.node.mview', [
|
||||
'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
|
||||
'sources/pgadmin', 'pgadmin.alertifyjs', 'pgadmin.browser',
|
||||
'pgadmin.backform', 'pgadmin.browser.server.privilege',
|
||||
], function(gettext, url_for, $, _, pgAdmin, Alertify, pgBrowser, Backform) {
|
||||
'pgadmin.backform', 'pgadmin.node.schema.dir/child',
|
||||
'pgadmin.browser.server.privilege',
|
||||
], function(
|
||||
gettext, url_for, $, _, pgAdmin, Alertify, pgBrowser, Backform,
|
||||
schemaChild
|
||||
) {
|
||||
|
||||
/**
|
||||
Create and add a view collection into nodes
|
||||
@ -33,19 +37,16 @@ define('pgadmin.node.mview', [
|
||||
view option in the context menu
|
||||
*/
|
||||
if (!pgBrowser.Nodes['mview']) {
|
||||
pgBrowser.Nodes['mview'] = pgBrowser.Node.extend({
|
||||
parent_type: ['schema', 'catalog'],
|
||||
pgBrowser.Nodes['mview'] = schemaChild.SchemaChildNode.extend({
|
||||
type: 'mview',
|
||||
sqlAlterHelp: 'sql-altermaterializedview.html',
|
||||
sqlCreateHelp: 'sql-creatematerializedview.html',
|
||||
dialogHelp: url_for('help.static', {'filename': 'materialized_view_dialog.html'}),
|
||||
label: gettext('Materialized View'),
|
||||
hasSQL: true,
|
||||
hasSQL: true,
|
||||
hasDepends: true,
|
||||
hasScriptTypes: ['create', 'select'],
|
||||
collection_type: 'coll-mview',
|
||||
canDrop: pgBrowser.Nodes['schema'].canChildDrop,
|
||||
canDropCascade: pgBrowser.Nodes['schema'].canChildDrop,
|
||||
Init: function() {
|
||||
|
||||
// Avoid mulitple registration of menus
|
||||
@ -236,43 +237,6 @@ define('pgadmin.node.mview', [
|
||||
|
||||
}),
|
||||
|
||||
/**
|
||||
Show or hide create view menu option on parent node
|
||||
and hide for system view in catalogs.
|
||||
*/
|
||||
canCreate: function(itemData, item, data) {
|
||||
|
||||
// If check is false then, we will allow create menu
|
||||
if (data && data.check === false)
|
||||
return true;
|
||||
|
||||
var t = pgBrowser.tree, i = item, d = itemData;
|
||||
|
||||
// To iterate over tree to check parent node
|
||||
while (i) {
|
||||
|
||||
// If it is schema then allow user to create view
|
||||
if (_.indexOf(['schema'], d._type) > -1)
|
||||
return true;
|
||||
|
||||
if ('coll-mview' == d._type) {
|
||||
|
||||
// Check if we are not child of view
|
||||
var prev_i = t.hasParent(i) ? t.parent(i) : null,
|
||||
prev_d = prev_i ? t.itemData(prev_i) : null;
|
||||
if( prev_d._type == 'catalog') {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
i = t.hasParent(i) ? t.parent(i) : null;
|
||||
d = i ? t.itemData(i) : null;
|
||||
}
|
||||
|
||||
// by default we do not want to allow create menu
|
||||
return true;
|
||||
},
|
||||
refresh_mview: function(args) {
|
||||
var input = args || {},
|
||||
obj = this,
|
||||
|
@ -1,9 +1,12 @@
|
||||
define('pgadmin.node.view', [
|
||||
'sources/gettext',
|
||||
'sources/url_for', 'jquery', 'underscore', 'sources/pgadmin',
|
||||
'pgadmin.browser', 'pgadmin.backform', 'pgadmin.browser.server.privilege',
|
||||
'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
|
||||
'sources/pgadmin', 'pgadmin.browser', 'pgadmin.backform',
|
||||
'pgadmin.node.schema.dir/child', 'pgadmin.browser.server.privilege',
|
||||
'pgadmin.node.rule',
|
||||
], function(gettext, url_for, $, _, pgAdmin, pgBrowser, Backform) {
|
||||
], function(
|
||||
gettext, url_for, $, _, pgAdmin, pgBrowser, Backform, schemaChild
|
||||
) {
|
||||
|
||||
|
||||
/**
|
||||
Create and add a view collection into nodes
|
||||
@ -28,14 +31,9 @@ define('pgadmin.node.view', [
|
||||
under which this node to display
|
||||
@param {variable} type - Type of Node
|
||||
@param {variable} hasSQL - To show SQL tab
|
||||
@param {variable} canDrop - Adds drop view option
|
||||
in the context menu
|
||||
@param {variable} canDropCascade - Adds drop Cascade
|
||||
view option in the context menu
|
||||
*/
|
||||
if (!pgBrowser.Nodes['view']) {
|
||||
pgBrowser.Nodes['view'] = pgBrowser.Node.extend({
|
||||
parent_type: ['schema', 'catalog'],
|
||||
pgBrowser.Nodes['view'] = schemaChild.SchemaChildNode.extend({
|
||||
type: 'view',
|
||||
sqlAlterHelp: 'sql-alterview.html',
|
||||
sqlCreateHelp: 'sql-createview.html',
|
||||
@ -45,8 +43,6 @@ define('pgadmin.node.view', [
|
||||
hasDepends: true,
|
||||
hasScriptTypes: ['create', 'select', 'insert'],
|
||||
collection_type: 'coll-view',
|
||||
canDrop: pgBrowser.Nodes['schema'].canChildDrop,
|
||||
canDropCascade: pgBrowser.Nodes['schema'].canChildDrop,
|
||||
Init: function() {
|
||||
|
||||
// Avoid mulitple registration of menus
|
||||
@ -197,45 +193,6 @@ define('pgadmin.node.view', [
|
||||
return false;
|
||||
},
|
||||
}),
|
||||
|
||||
/**
|
||||
Show or hide create view menu option on parent node
|
||||
and hide for system view in catalogs.
|
||||
*/
|
||||
canCreate: function(itemData, item, data) {
|
||||
|
||||
// If check is false then, we will allow create menu
|
||||
if (data && data.check == false)
|
||||
return true;
|
||||
|
||||
var t = pgBrowser.tree, i = item, d = itemData;
|
||||
|
||||
// To iterate over tree to check parent node
|
||||
while (i) {
|
||||
|
||||
// If it is schema then allow user to create view
|
||||
if (_.indexOf(['schema'], d._type) > -1)
|
||||
return true;
|
||||
|
||||
if ('coll-view' == d._type) {
|
||||
|
||||
// Check if we are not child of view
|
||||
var prev_i = t.hasParent(i) ? t.parent(i) : null,
|
||||
prev_d = prev_i ? t.itemData(prev_i) : null;
|
||||
if( prev_d._type == 'catalog') {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
i = t.hasParent(i) ? t.parent(i) : null;
|
||||
d = i ? t.itemData(i) : null;
|
||||
}
|
||||
|
||||
// by default we do not want to allow create menu
|
||||
return true;
|
||||
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -115,17 +115,17 @@ define([
|
||||
// Fetch Data
|
||||
collection.fetch({
|
||||
reset: true,
|
||||
error: function(xhr, error, message) {
|
||||
error: function(model, error, xhr) {
|
||||
pgBrowser.Events.trigger(
|
||||
'pgadmin:collection:retrieval:error', 'properties', xhr, error,
|
||||
message, item, that
|
||||
error.message, item, that
|
||||
);
|
||||
if (!Alertify.pgHandleItemError(
|
||||
xhr, error, message, {item: item, info: info}
|
||||
xhr, error, error.message, {item: item, info: info}
|
||||
)) {
|
||||
Alertify.pgNotifier(error, xhr, S(
|
||||
gettext('Error retrieving properties - %s.')
|
||||
).sprintf(message || that.label).value(), function() {
|
||||
).sprintf(error.message || that.label).value(), function() {
|
||||
console.warn(arguments);
|
||||
});
|
||||
}
|
||||
|
@ -1,9 +1,13 @@
|
||||
define('pgadmin.browser.node', [
|
||||
'sources/tree/pgadmin_tree_node',
|
||||
'sources/gettext', 'jquery', 'underscore', 'underscore.string', 'sources/pgadmin',
|
||||
'pgadmin.browser.menu', 'backbone', 'pgadmin.alertifyjs', 'pgadmin.browser.datamodel',
|
||||
'backform', 'sources/browser/generate_url', 'sources/utils', 'pgadmin.browser.utils',
|
||||
'pgadmin.backform',
|
||||
], function(gettext, $, _, S, pgAdmin, Menu, Backbone, Alertify, pgBrowser, Backform, generateUrl, commonUtils) {
|
||||
], function(
|
||||
pgadminTreeNode,
|
||||
gettext, $, _, S, pgAdmin, Menu, Backbone, Alertify, pgBrowser, Backform, generateUrl, commonUtils
|
||||
) {
|
||||
|
||||
var wcDocker = window.wcDocker,
|
||||
keyCode = {
|
||||
@ -28,7 +32,7 @@ define('pgadmin.browser.node', [
|
||||
//
|
||||
// It is unlikely - we will instantiate an object for this class.
|
||||
// (Inspired by Backbone.extend function)
|
||||
pgBrowser.Node.extend = function(props) {
|
||||
pgBrowser.Node.extend = function(props, initialize) {
|
||||
var parent = this;
|
||||
var child;
|
||||
|
||||
@ -44,6 +48,10 @@ define('pgadmin.browser.node', [
|
||||
// Make sure - a child have all the callbacks of the parent.
|
||||
child.callbacks = _.extend({}, parent.callbacks, props.callbacks);
|
||||
|
||||
// Let's not bind the callbacks, or initialize the child.
|
||||
if (initialize === false)
|
||||
return child;
|
||||
|
||||
var bindToChild = function(cb) {
|
||||
if (typeof(child.callbacks[cb]) == 'function') {
|
||||
child.callbacks[cb] = child.callbacks[cb].bind(child);
|
||||
@ -1566,7 +1574,6 @@ define('pgadmin.browser.node', [
|
||||
* depends, statistics
|
||||
*/
|
||||
generate_url: function(item, type, d, with_id, info) {
|
||||
|
||||
var opURL = {
|
||||
'create': 'obj',
|
||||
'drop': 'obj',
|
||||
@ -1608,24 +1615,7 @@ define('pgadmin.browser.node', [
|
||||
Collection: pgBrowser.DataCollection,
|
||||
// Base class for Node Data Model
|
||||
Model: pgBrowser.DataModel,
|
||||
getTreeNodeHierarchy: function(i) {
|
||||
var idx = 0,
|
||||
res = {},
|
||||
t = pgBrowser.tree,
|
||||
d;
|
||||
do {
|
||||
d = t.itemData(i);
|
||||
if (d._type in pgBrowser.Nodes && pgBrowser.Nodes[d._type].hasId) {
|
||||
res[d._type] = _.extend({}, d, {
|
||||
'priority': idx,
|
||||
});
|
||||
idx -= 1;
|
||||
}
|
||||
i = t.hasParent(i) ? t.parent(i) : null;
|
||||
} while (i);
|
||||
|
||||
return res;
|
||||
},
|
||||
getTreeNodeHierarchy: pgadminTreeNode.getTreeNodeHierarchyFromIdentifier.bind(pgBrowser),
|
||||
cache: function(url, node_info, level, data) {
|
||||
var cached = this.cached = this.cached || {},
|
||||
hash = url,
|
||||
|
150
web/pgadmin/static/js/alertify/dialog.js
Normal file
150
web/pgadmin/static/js/alertify/dialog.js
Normal file
@ -0,0 +1,150 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import gettext from '../gettext';
|
||||
import {sprintf} from 'sprintf-js';
|
||||
import {DialogFactory} from './dialog_factory';
|
||||
import Backform from '../backform.pgadmin';
|
||||
import {getTreeNodeHierarchyFromIdentifier} from '../tree/pgadmin_tree_node';
|
||||
|
||||
/**
|
||||
* This class can be extended to create new dialog boxes.
|
||||
* Examples of this can be found in:
|
||||
* `web/pgadmin/static/js/backup/backup_dialog.js`
|
||||
*
|
||||
* Do not forget to add the new Dialog type to the `DialogFactory`
|
||||
*/
|
||||
export class Dialog {
|
||||
constructor(errorAlertTitle,
|
||||
dialogContainerSelector,
|
||||
pgBrowser, $, alertify, DialogModel,
|
||||
backform = Backform) {
|
||||
this.errorAlertTitle = errorAlertTitle;
|
||||
this.alertify = alertify;
|
||||
this.pgBrowser = pgBrowser;
|
||||
this.jquery = $;
|
||||
this.dialogModel = DialogModel;
|
||||
this.backform = backform;
|
||||
this.dialogContainerSelector = dialogContainerSelector;
|
||||
}
|
||||
|
||||
retrieveAncestorOfTypeServer(item) {
|
||||
let serverInformation = null;
|
||||
let aciTreeItem = item || this.pgBrowser.treeMenu.selected();
|
||||
let treeNode = this.pgBrowser.treeMenu.findNodeByDomElement(aciTreeItem);
|
||||
|
||||
if (treeNode) {
|
||||
let nodeData;
|
||||
let databaseNode = treeNode.ancestorNode(
|
||||
(node) => {
|
||||
nodeData = node.getData();
|
||||
return (nodeData._type === 'database');
|
||||
}
|
||||
);
|
||||
let isServerNode = (node) => {
|
||||
nodeData = node.getData();
|
||||
return nodeData._type === 'server';
|
||||
};
|
||||
|
||||
if (databaseNode !== null) {
|
||||
if (nodeData._label.indexOf('=') >= 0) {
|
||||
this.alertify.alert(
|
||||
gettext(this.errorAlertTitle),
|
||||
gettext(
|
||||
'Databases with = symbols in the name cannot be backed up or restored using this utility.'
|
||||
)
|
||||
);
|
||||
} else {
|
||||
if (databaseNode.hasParent(isServerNode))
|
||||
serverInformation = nodeData;
|
||||
}
|
||||
} else {
|
||||
if (treeNode.anyFamilyMember(isServerNode))
|
||||
serverInformation = nodeData;
|
||||
}
|
||||
}
|
||||
|
||||
if (serverInformation === null) {
|
||||
this.alertify.alert(
|
||||
gettext(this.errorAlertTitle),
|
||||
gettext('Please select server or child node from the browser tree.')
|
||||
);
|
||||
}
|
||||
|
||||
return serverInformation;
|
||||
}
|
||||
|
||||
hasBinariesConfiguration(serverInformation) {
|
||||
const module = 'paths';
|
||||
let preference_name = 'pg_bin_dir';
|
||||
let msg = gettext('Please configure the PostgreSQL Binary Path in the Preferences dialog.');
|
||||
|
||||
if ((serverInformation.type && serverInformation.type === 'ppas') ||
|
||||
serverInformation.server_type === 'ppas') {
|
||||
preference_name = 'ppas_bin_dir';
|
||||
msg = gettext('Please configure the EDB Advanced Server Binary Path in the Preferences dialog.');
|
||||
}
|
||||
const preference = this.pgBrowser.get_preference(module, preference_name);
|
||||
|
||||
if (preference) {
|
||||
if (!preference.value) {
|
||||
this.alertify.alert(gettext('Configuration required'), msg);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
this.alertify.alert(
|
||||
gettext(this.errorAlertTitle),
|
||||
sprintf(gettext('Failed to load preference %s of module %s'), preference_name, module)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
dialogName() {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
createOrGetDialog(dialogTitle, typeOfDialog) {
|
||||
const dialogName = this.dialogName(typeOfDialog);
|
||||
|
||||
if (!this.alertify[dialogName]) {
|
||||
const self = this;
|
||||
this.alertify.dialog(dialogName, function factory() {
|
||||
return self.dialogFactory(dialogTitle, typeOfDialog);
|
||||
});
|
||||
}
|
||||
return this.alertify[dialogName];
|
||||
}
|
||||
|
||||
dialogFactory(dialogTitle, typeOfDialog) {
|
||||
const factory = new DialogFactory(
|
||||
this.pgBrowser,
|
||||
this.jquery,
|
||||
this.alertify,
|
||||
this.dialogModel,
|
||||
this.backform,
|
||||
this.dialogContainerSelector);
|
||||
return factory.create(dialogTitle, typeOfDialog);
|
||||
}
|
||||
|
||||
canExecuteOnCurrentDatabase(aciTreeItem) {
|
||||
const treeInfo = getTreeNodeHierarchyFromIdentifier.apply(this.pgBrowser, [aciTreeItem]);
|
||||
|
||||
if (treeInfo.database && treeInfo.database._label.indexOf('=') >= 0) {
|
||||
this.alertify.alert(
|
||||
gettext(this.errorAlertTitle),
|
||||
gettext('Databases with = symbols in the name cannot be backed up or restored using this utility.')
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
52
web/pgadmin/static/js/alertify/dialog_factory.js
Normal file
52
web/pgadmin/static/js/alertify/dialog_factory.js
Normal file
@ -0,0 +1,52 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import * as BackupDialog from '../../../tools/backup/static/js/backup_dialog_wrapper';
|
||||
import {RestoreDialogWrapper} from '../../../tools/restore/static/js/restore_dialog_wrapper';
|
||||
|
||||
export class DialogFactory {
|
||||
constructor(pgBrowser, $,
|
||||
alertify, DialogModel,
|
||||
backform, dialogContainerSelector) {
|
||||
this.pgBrowser = pgBrowser;
|
||||
this.jquery = $;
|
||||
this.alertify = alertify;
|
||||
this.dialogModel = DialogModel;
|
||||
this.backform = backform;
|
||||
this.dialogContainerSelector = dialogContainerSelector;
|
||||
}
|
||||
|
||||
create(dialogTitle, typeOfDialog) {
|
||||
if (typeOfDialog === 'restore') {
|
||||
return this.createRestoreDialog(dialogTitle, typeOfDialog);
|
||||
} else {
|
||||
return this.createBackupDialog(dialogTitle, typeOfDialog);
|
||||
}
|
||||
}
|
||||
|
||||
createRestoreDialog(dialogTitle, typeOfDialog) {
|
||||
return new RestoreDialogWrapper(
|
||||
this.dialogContainerSelector, dialogTitle, typeOfDialog,
|
||||
this.jquery,
|
||||
this.pgBrowser,
|
||||
this.alertify,
|
||||
this.dialogModel,
|
||||
this.backform);
|
||||
}
|
||||
|
||||
createBackupDialog(dialogTitle, typeOfDialog) {
|
||||
return new BackupDialog.BackupDialogWrapper(
|
||||
this.dialogContainerSelector, dialogTitle, typeOfDialog,
|
||||
this.jquery,
|
||||
this.pgBrowser,
|
||||
this.alertify,
|
||||
this.dialogModel,
|
||||
this.backform);
|
||||
}
|
||||
}
|
57
web/pgadmin/static/js/alertify/dialog_wrapper.js
Normal file
57
web/pgadmin/static/js/alertify/dialog_wrapper.js
Normal file
@ -0,0 +1,57 @@
|
||||
import * as commonUtils from '../utils';
|
||||
|
||||
export class DialogWrapper {
|
||||
constructor(
|
||||
dialogContainerSelector, dialogTitle, jquery, pgBrowser,
|
||||
alertify, dialogModel, backform) {
|
||||
this.hooks = {
|
||||
onclose: function () {
|
||||
if (this.view) {
|
||||
this.view.remove({
|
||||
data: true,
|
||||
internal: true,
|
||||
silent: true,
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
this.dialogContainerSelector = dialogContainerSelector;
|
||||
this.dialogTitle = dialogTitle;
|
||||
this.jquery = jquery;
|
||||
this.pgBrowser = pgBrowser;
|
||||
this.alertify = alertify;
|
||||
this.dialogModel = dialogModel;
|
||||
this.backform = backform;
|
||||
}
|
||||
|
||||
build() {
|
||||
this.alertify.pgDialogBuild.apply(this);
|
||||
}
|
||||
|
||||
wasHelpButtonPressed(e) {
|
||||
return e.button.element.name === 'dialog_help'
|
||||
|| e.button.element.name === 'object_help';
|
||||
}
|
||||
|
||||
getSelectedNodeData(selectedTreeNode) {
|
||||
if (!this.isNodeSelected(selectedTreeNode)) {
|
||||
return undefined;
|
||||
}
|
||||
const treeNodeData = selectedTreeNode.getData();
|
||||
if (treeNodeData) {
|
||||
return treeNodeData;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
focusOnDialog(dialog) {
|
||||
dialog.$el.attr('tabindex', -1);
|
||||
this.pgBrowser.keyboardNavigation.getDialogTabNavigator(dialog);
|
||||
const container = dialog.$el.find('.tab-content:first > .tab-pane.active:first');
|
||||
commonUtils.findAndSetFocus(container);
|
||||
}
|
||||
|
||||
isNodeSelected(selectedTreeNode) {
|
||||
return selectedTreeNode;
|
||||
}
|
||||
}
|
37
web/pgadmin/static/js/nodes/supported_database_node.js
Normal file
37
web/pgadmin/static/js/nodes/supported_database_node.js
Normal file
@ -0,0 +1,37 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import {isValidTreeNodeData} from 'sources/tree/tree';
|
||||
|
||||
function checkAllowConnIfDatabaseNode(treeNodeData) {
|
||||
return (treeNodeData._type === 'database' && treeNodeData.allowConn)
|
||||
|| treeNodeData._type !== 'database';
|
||||
}
|
||||
|
||||
function ancestorWithTypeCatalog(treeNode) {
|
||||
return treeNode.anyFamilyMember((node) => {
|
||||
return node.getData()._type === 'catalog';
|
||||
});
|
||||
}
|
||||
|
||||
export function enabled(tree, supportedNodes, treeNodeData, domTreeNode) {
|
||||
if (!isValidTreeNodeData(treeNodeData))
|
||||
return false;
|
||||
|
||||
let treeNode = tree.findNodeByDomElement(domTreeNode);
|
||||
if (!treeNode) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return checkAllowConnIfDatabaseNode(treeNodeData) &&
|
||||
_.indexOf(supportedNodes, treeNodeData._type) !== -1 &&
|
||||
!ancestorWithTypeCatalog(treeNode);
|
||||
}
|
||||
|
||||
|
72
web/pgadmin/static/js/tree/pgadmin_tree_node.js
Normal file
72
web/pgadmin/static/js/tree/pgadmin_tree_node.js
Normal file
@ -0,0 +1,72 @@
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* This method received pgBrowser and new TreeNode object
|
||||
*
|
||||
* This method retrieves all the data that exists in the tree node and in
|
||||
* `pgBrowser.Nodes` for all the parent node of the provided node.
|
||||
*
|
||||
* The 2 condition to get the information from pgBrowser.Nodes are:
|
||||
* 1 - the variable _type of the tree node
|
||||
* 2 - the presence of hasId in the pgBrowser.Nodes for the specific node
|
||||
*
|
||||
* Number 2 is used to ignore coll-* nodes as they do not add any useful
|
||||
* information
|
||||
*/
|
||||
export function getTreeNodeHierarchyFromElement(pgBrowser, treeNode) {
|
||||
return getTreeNodeHierarchy.call(pgBrowser, treeNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method received an ACI Tree JQuery node
|
||||
*
|
||||
* NOTE: this function need to be called on pgBrowser instance.
|
||||
* getTreeNodeHierarchyFromIdentifier.apply(pgBrowser, [aciTreeNodeIdentifier])
|
||||
*
|
||||
* This method retrieves all the data that exists in the tree node and in
|
||||
* `pgBrowser.Nodes` for all the parent node of the provided node.
|
||||
*
|
||||
* The 2 condition to get the information from pgBrowser.Nodes are:
|
||||
* 1 - the variable _type of the tree node
|
||||
* 2 - the presence of hasId in the pgBrowser.Nodes for the specific node
|
||||
*
|
||||
* Number 2 is used to ignore coll-* nodes as they do not add any useful
|
||||
* information
|
||||
*/
|
||||
export function getTreeNodeHierarchyFromIdentifier(aciTreeNodeIdentifier) {
|
||||
let identifier = this.treeMenu.translateTreeNodeIdFromACITree(aciTreeNodeIdentifier);
|
||||
let currentNode = this.treeMenu.findNode(identifier);
|
||||
return getTreeNodeHierarchy.call(this, currentNode);
|
||||
}
|
||||
|
||||
export function getTreeNodeHierarchy(currentNode) {
|
||||
let idx = 0;
|
||||
let result = {};
|
||||
|
||||
do {
|
||||
const currentNodeData = currentNode.getData();
|
||||
if (currentNodeData._type in this.Nodes && this.Nodes[currentNodeData._type].hasId) {
|
||||
const nodeType = mapType(currentNodeData._type);
|
||||
if (result[nodeType] === undefined) {
|
||||
result[nodeType] = _.extend({}, currentNodeData, {
|
||||
'priority': idx,
|
||||
});
|
||||
idx -= 1;
|
||||
}
|
||||
}
|
||||
currentNode = currentNode.hasParent() ? currentNode.parent() : null;
|
||||
} while (currentNode);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function mapType(type) {
|
||||
return type === 'partition' ? 'table' : type;
|
||||
}
|
@ -59,17 +59,20 @@ export class TreeNode {
|
||||
tree.aciTreeApi.unload(this.domNode);
|
||||
}
|
||||
|
||||
anyParent(condition) {
|
||||
/*
|
||||
* Find the ancestor with matches this condition
|
||||
*/
|
||||
ancestorNode(condition) {
|
||||
let node = this;
|
||||
|
||||
while (node.hasParent()) {
|
||||
node = node.parent();
|
||||
if (condition(node)) {
|
||||
return true;
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -81,7 +84,10 @@ export class TreeNode {
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.anyParent(condition);
|
||||
return this.ancestorNode(condition) !== null;
|
||||
}
|
||||
anyParent(condition) {
|
||||
return this.ancestorNode(condition) !== null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -210,3 +216,7 @@ function findInTree(rootNode, path) {
|
||||
}
|
||||
})(rootNode);
|
||||
}
|
||||
|
||||
export function isValidTreeNodeData(treeNodeData) {
|
||||
return !_.isUndefined(treeNodeData) && !_.isNull(treeNodeData);
|
||||
}
|
||||
|
@ -3,9 +3,12 @@ define([
|
||||
'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
|
||||
'underscore.string', 'pgadmin.alertifyjs', 'backbone', 'pgadmin.backgrid',
|
||||
'pgadmin.backform', 'pgadmin.browser', 'sources/utils',
|
||||
'tools/backup/static/js/menu_utils',
|
||||
'tools/backup/static/js/backup_dialog',
|
||||
'sources/nodes/supported_database_node',
|
||||
], function(
|
||||
gettext, url_for, $, _, S, alertify, Backbone, Backgrid, Backform, pgBrowser,
|
||||
commonUtils
|
||||
commonUtils, menuUtils, globalBackupDialog, supportedNodes
|
||||
) {
|
||||
|
||||
// if module is already initialized, refer to that.
|
||||
@ -394,48 +397,6 @@ commonUtils
|
||||
|
||||
this.initialized = true;
|
||||
|
||||
// Define list of nodes on which backup context menu option appears
|
||||
var backup_supported_nodes = [
|
||||
'database', 'schema', 'table', 'partition',
|
||||
];
|
||||
|
||||
/**
|
||||
Enable/disable backup menu in tools based
|
||||
on node selected
|
||||
if selected node is present in supported_nodes,
|
||||
menu will be enabled otherwise disabled.
|
||||
Also, hide it for system view in catalogs
|
||||
*/
|
||||
var menu_enabled = function(itemData, item) {
|
||||
var t = pgBrowser.tree,
|
||||
i = item,
|
||||
d = itemData,
|
||||
parent_item = t.hasParent(i) ? t.parent(i) : null,
|
||||
parent_data = parent_item ? t.itemData(parent_item) : null;
|
||||
|
||||
if (!_.isUndefined(d) && !_.isNull(d) && !_.isNull(parent_data)) {
|
||||
if (_.indexOf(backup_supported_nodes, d._type) !== -1 &&
|
||||
parent_data._type != 'catalog') {
|
||||
if (d._type == 'database' && d.allowConn)
|
||||
return true;
|
||||
else if (d._type != 'database')
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
} else
|
||||
return false;
|
||||
} else
|
||||
return false;
|
||||
};
|
||||
|
||||
var menu_enabled_server = function(itemData) {
|
||||
// If server node selected && connected
|
||||
if (!_.isUndefined(itemData) && !_.isNull(itemData))
|
||||
return (('server' === itemData._type) && itemData.connected);
|
||||
else
|
||||
return false;
|
||||
};
|
||||
|
||||
// Define the nodes on which the menus to be appear
|
||||
var menus = [{
|
||||
name: 'backup_global',
|
||||
@ -445,7 +406,7 @@ commonUtils
|
||||
priority: 12,
|
||||
label: gettext('Backup Globals...'),
|
||||
icon: 'fa fa-floppy-o',
|
||||
enable: menu_enabled_server,
|
||||
enable: menuUtils.menuEnabledServer,
|
||||
}, {
|
||||
name: 'backup_server',
|
||||
module: this,
|
||||
@ -454,7 +415,7 @@ commonUtils
|
||||
priority: 12,
|
||||
label: gettext('Backup Server...'),
|
||||
icon: 'fa fa-floppy-o',
|
||||
enable: menu_enabled_server,
|
||||
enable: menuUtils.menuEnabledServer,
|
||||
}, {
|
||||
name: 'backup_global_ctx',
|
||||
module: this,
|
||||
@ -464,7 +425,7 @@ commonUtils
|
||||
priority: 12,
|
||||
label: gettext('Backup Globals...'),
|
||||
icon: 'fa fa-floppy-o',
|
||||
enable: menu_enabled_server,
|
||||
enable: menuUtils.menuEnabledServer,
|
||||
}, {
|
||||
name: 'backup_server_ctx',
|
||||
module: this,
|
||||
@ -474,7 +435,7 @@ commonUtils
|
||||
priority: 12,
|
||||
label: gettext('Backup Server...'),
|
||||
icon: 'fa fa-floppy-o',
|
||||
enable: menu_enabled_server,
|
||||
enable: menuUtils.menuEnabledServer,
|
||||
}, {
|
||||
name: 'backup_object',
|
||||
module: this,
|
||||
@ -483,20 +444,24 @@ commonUtils
|
||||
priority: 11,
|
||||
label: gettext('Backup...'),
|
||||
icon: 'fa fa-floppy-o',
|
||||
enable: menu_enabled,
|
||||
enable: supportedNodes.enabled.bind(
|
||||
null, pgBrowser.treeMenu, menuUtils.backupSupportedNodes
|
||||
),
|
||||
}];
|
||||
|
||||
for (var idx = 0; idx < backup_supported_nodes.length; idx++) {
|
||||
for (var idx = 0; idx < menuUtils.backupSupportedNodes.length; idx++) {
|
||||
menus.push({
|
||||
name: 'backup_' + backup_supported_nodes[idx],
|
||||
node: backup_supported_nodes[idx],
|
||||
name: 'backup_' + menuUtils.backupSupportedNodes[idx],
|
||||
node: menuUtils.backupSupportedNodes[idx],
|
||||
module: this,
|
||||
applies: ['context'],
|
||||
callback: 'backup_objects',
|
||||
priority: 11,
|
||||
label: gettext('Backup...'),
|
||||
icon: 'fa fa-floppy-o',
|
||||
enable: menu_enabled,
|
||||
enable: supportedNodes.enabled.bind(
|
||||
null, pgBrowser.treeMenu, menuUtils.backupSupportedNodes
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
@ -521,542 +486,25 @@ commonUtils
|
||||
},
|
||||
|
||||
// Callback to draw Backup Dialog for globals/server
|
||||
start_backup_global_server: function(action, item, params) {
|
||||
var i = item || pgBrowser.tree.selected(),
|
||||
server_data = null;
|
||||
|
||||
while (i) {
|
||||
var node_data = pgBrowser.tree.itemData(i);
|
||||
if (node_data._type == 'server') {
|
||||
server_data = node_data;
|
||||
break;
|
||||
}
|
||||
|
||||
if (pgBrowser.tree.hasParent(i)) {
|
||||
i = $(pgBrowser.tree.parent(i));
|
||||
} else {
|
||||
alertify.alert(
|
||||
gettext('Backup Error'),
|
||||
gettext('Please select server or child node from the browser tree.')
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!server_data) {
|
||||
return;
|
||||
}
|
||||
|
||||
var module = 'paths',
|
||||
preference_name = 'pg_bin_dir',
|
||||
msg = gettext('Please configure the PostgreSQL Binary Path in the Preferences dialog.');
|
||||
|
||||
if ((server_data.type && server_data.type == 'ppas') ||
|
||||
server_data.server_type == 'ppas') {
|
||||
preference_name = 'ppas_bin_dir';
|
||||
msg = gettext('Please configure the EDB Advanced Server Binary Path in the Preferences dialog.');
|
||||
}
|
||||
|
||||
var preference = pgBrowser.get_preference(module, preference_name);
|
||||
|
||||
if (preference) {
|
||||
if (!preference.value) {
|
||||
alertify.alert(gettext('Configuration required'), msg);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
alertify.alert(
|
||||
gettext('Backup Error'),
|
||||
S(gettext('Failed to load preference %s of module %s')).sprintf(preference_name, module).value()
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
var of_type = undefined;
|
||||
|
||||
// Set Notes according to type of backup
|
||||
if (!_.isUndefined(params['globals']) && params['globals']) {
|
||||
of_type = 'globals';
|
||||
} else {
|
||||
of_type = 'server';
|
||||
}
|
||||
|
||||
var DialogName = 'BackupDialog_' + of_type,
|
||||
DialogTitle = ((of_type == 'globals') ?
|
||||
gettext('Backup Globals...') :
|
||||
gettext('Backup Server...'));
|
||||
|
||||
if (!alertify[DialogName]) {
|
||||
alertify.dialog(DialogName, function factory() {
|
||||
return {
|
||||
main: function(title) {
|
||||
this.set('title', title);
|
||||
},
|
||||
build: function() {
|
||||
alertify.pgDialogBuild.apply(this);
|
||||
},
|
||||
setup: function() {
|
||||
return {
|
||||
buttons: [{
|
||||
text: '',
|
||||
className: 'btn btn-default pull-left fa fa-lg fa-info',
|
||||
attrs: {
|
||||
name: 'object_help',
|
||||
type: 'button',
|
||||
url: 'backup.html',
|
||||
label: gettext('Backup'),
|
||||
},
|
||||
}, {
|
||||
text: '',
|
||||
key: 112,
|
||||
className: 'btn btn-default pull-left fa fa-lg fa-question',
|
||||
attrs: {
|
||||
name: 'dialog_help',
|
||||
type: 'button',
|
||||
label: gettext('Backup'),
|
||||
url: url_for('help.static', {
|
||||
'filename': 'backup_dialog.html',
|
||||
}),
|
||||
},
|
||||
}, {
|
||||
text: gettext('Backup'),
|
||||
key: 13,
|
||||
className: 'btn btn-primary fa fa-lg fa-save pg-alertify-button',
|
||||
'data-btn-name': 'backup',
|
||||
}, {
|
||||
text: gettext('Cancel'),
|
||||
key: 27,
|
||||
className: 'btn btn-danger fa fa-lg fa-times pg-alertify-button',
|
||||
'data-btn-name': 'cancel',
|
||||
}],
|
||||
// Set options for dialog
|
||||
options: {
|
||||
title: DialogTitle,
|
||||
//disable both padding and overflow control.
|
||||
padding: !1,
|
||||
overflow: !1,
|
||||
model: 0,
|
||||
resizable: true,
|
||||
maximizable: true,
|
||||
pinnable: false,
|
||||
closableByDimmer: false,
|
||||
modal: false,
|
||||
},
|
||||
};
|
||||
},
|
||||
hooks: {
|
||||
// Triggered when the dialog is closed
|
||||
onclose: function() {
|
||||
if (this.view) {
|
||||
// clear our backform model/view
|
||||
this.view.remove({
|
||||
data: true,
|
||||
internal: true,
|
||||
silent: true,
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
prepare: function() {
|
||||
var self = this;
|
||||
// Disable Backup button until user provides Filename
|
||||
this.__internal.buttons[2].element.disabled = true;
|
||||
|
||||
var $container = $('<div class=\'backup_dialog\'></div>');
|
||||
// Find current/selected node
|
||||
var t = pgBrowser.tree,
|
||||
i = t.selected(),
|
||||
d = i && i.length == 1 ? t.itemData(i) : undefined,
|
||||
node = d && pgBrowser.Nodes[d._type];
|
||||
|
||||
if (!d)
|
||||
return;
|
||||
// Create treeInfo
|
||||
var treeInfo = node.getTreeNodeHierarchy.apply(node, [i]);
|
||||
// Instance of backbone model
|
||||
var newModel = new BackupModel({
|
||||
type: of_type,
|
||||
}, {
|
||||
node_info: treeInfo,
|
||||
}),
|
||||
fields = Backform.generateViewSchema(
|
||||
treeInfo, newModel, 'create', node, treeInfo.server, true
|
||||
);
|
||||
|
||||
var view = this.view = new Backform.Dialog({
|
||||
el: $container,
|
||||
model: newModel,
|
||||
schema: fields,
|
||||
});
|
||||
// Add our class to alertify
|
||||
$(this.elements.body.childNodes[0]).addClass(
|
||||
'alertify_tools_dialog_properties obj_properties'
|
||||
);
|
||||
// Render dialog
|
||||
view.render();
|
||||
|
||||
this.elements.content.appendChild($container.get(0));
|
||||
|
||||
var container = view.$el.find('.tab-content:first > .tab-pane.active:first');
|
||||
commonUtils.findAndSetFocus(container);
|
||||
|
||||
// Listen to model & if filename is provided then enable Backup button
|
||||
this.view.model.on('change', function() {
|
||||
if (!_.isUndefined(this.get('file')) && this.get('file') !== '') {
|
||||
this.errorModel.clear();
|
||||
self.__internal.buttons[2].element.disabled = false;
|
||||
} else {
|
||||
self.__internal.buttons[2].element.disabled = true;
|
||||
this.errorModel.set('file', gettext('Please provide a filename'));
|
||||
}
|
||||
});
|
||||
},
|
||||
// Callback functions when click on the buttons of the Alertify dialogs
|
||||
callback: function(e) {
|
||||
// Fetch current server id
|
||||
var t = pgBrowser.tree,
|
||||
i = t.selected(),
|
||||
d = i && i.length == 1 ? t.itemData(i) : undefined,
|
||||
node = d && pgBrowser.Nodes[d._type];
|
||||
|
||||
if (e.button.element.name == 'dialog_help' || e.button.element.name == 'object_help') {
|
||||
e.cancel = true;
|
||||
pgBrowser.showHelp(e.button.element.name, e.button.element.getAttribute('url'),
|
||||
node, i, e.button.element.getAttribute('label'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.button['data-btn-name'] === 'backup') {
|
||||
|
||||
if (!d)
|
||||
return;
|
||||
|
||||
var treeInfo = node.getTreeNodeHierarchy.apply(node, [i]);
|
||||
|
||||
var self = this,
|
||||
baseUrl = url_for('backup.create_server_job', {
|
||||
'sid': treeInfo.server._id,
|
||||
}),
|
||||
args = this.view.model.toJSON();
|
||||
|
||||
$.ajax({
|
||||
url: baseUrl,
|
||||
method: 'POST',
|
||||
data: {
|
||||
'data': JSON.stringify(args),
|
||||
},
|
||||
success: function(res) {
|
||||
if (res.success) {
|
||||
alertify.success(gettext('Backup job created.'), 5);
|
||||
pgBrowser.Events.trigger('pgadmin-bgprocess:created', self);
|
||||
} else {
|
||||
console.warn(res);
|
||||
}
|
||||
},
|
||||
error: function(xhr) {
|
||||
try {
|
||||
var err = JSON.parse(xhr.responseText);
|
||||
alertify.alert(
|
||||
gettext('Backup job failed.'),
|
||||
err.errormsg
|
||||
);
|
||||
} catch (e) {
|
||||
console.warn(e.stack || e);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
alertify[DialogName](true).resizeTo('60%', '50%');
|
||||
start_backup_global_server: function(action, treeItem, params) {
|
||||
let dialog = new globalBackupDialog.BackupDialog(
|
||||
pgBrowser,
|
||||
$,
|
||||
alertify,
|
||||
BackupModel
|
||||
);
|
||||
dialog.draw(action, treeItem, params);
|
||||
},
|
||||
|
||||
// Callback to draw Backup Dialog for objects
|
||||
backup_objects: function(action, treeItem) {
|
||||
|
||||
var i = treeItem || pgBrowser.tree.selected(),
|
||||
server_data = null;
|
||||
|
||||
while (i) {
|
||||
var node_data = pgBrowser.tree.itemData(i);
|
||||
if (node_data._type == 'server') {
|
||||
server_data = node_data;
|
||||
break;
|
||||
}
|
||||
|
||||
if (pgBrowser.tree.hasParent(i)) {
|
||||
i = $(pgBrowser.tree.parent(i));
|
||||
} else {
|
||||
alertify.alert(
|
||||
gettext('Backup Error'),
|
||||
gettext('Please select server or child node from tree.')
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!server_data) {
|
||||
return;
|
||||
}
|
||||
|
||||
var module = 'paths',
|
||||
preference_name = 'pg_bin_dir',
|
||||
msg = gettext('Please set binary path for PostgreSQL Server from preferences.');
|
||||
|
||||
if ((server_data.type && server_data.type == 'ppas') ||
|
||||
server_data.server_type == 'ppas') {
|
||||
preference_name = 'ppas_bin_dir';
|
||||
msg = gettext('Please set binary path for EDB Postgres Advanced Server from preferences.');
|
||||
}
|
||||
|
||||
var preference = pgBrowser.get_preference(module, preference_name);
|
||||
|
||||
if (preference) {
|
||||
if (!preference.value) {
|
||||
alertify.alert(gettext('Configuration required'), msg);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
alertify.alert(
|
||||
gettext('Backup Error'),
|
||||
S(gettext('Failed to load preference %s of module %s')).sprintf(preference_name, module).value()
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
var title = S(gettext('Backup (%s: %s)')),
|
||||
tree = pgBrowser.tree,
|
||||
item = treeItem || tree.selected(),
|
||||
data = item && item.length == 1 && tree.itemData(item),
|
||||
node = data && data._type && pgBrowser.Nodes[data._type];
|
||||
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
var treeInfo = node.getTreeNodeHierarchy.apply(node, [item]);
|
||||
|
||||
if (treeInfo.database._label.indexOf('=') >= 0) {
|
||||
alertify.alert(
|
||||
gettext('Backup error'),
|
||||
gettext('Backup job creation failed. '+
|
||||
'Databases with = symbols in the name cannot be backed up using this utility.')
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
title = title.sprintf(node.label, data.label).value();
|
||||
|
||||
if (!alertify.backup_objects) {
|
||||
// Create Dialog title on the fly with node details
|
||||
alertify.dialog('backup_objects', function factory() {
|
||||
return {
|
||||
main: function(title) {
|
||||
this.set('title', title);
|
||||
},
|
||||
build: function() {
|
||||
alertify.pgDialogBuild.apply(this);
|
||||
},
|
||||
setup: function() {
|
||||
return {
|
||||
buttons: [{
|
||||
text: '',
|
||||
className: 'btn btn-default pull-left fa fa-lg fa-info',
|
||||
attrs: {
|
||||
name: 'object_help',
|
||||
type: 'button',
|
||||
url: 'backup.html',
|
||||
label: gettext('Backup'),
|
||||
},
|
||||
}, {
|
||||
text: '',
|
||||
key: 112,
|
||||
className: 'btn btn-default pull-left fa fa-lg fa-question',
|
||||
attrs: {
|
||||
name: 'dialog_help',
|
||||
type: 'button',
|
||||
label: gettext('Backup'),
|
||||
url: url_for('help.static', {
|
||||
'filename': 'backup_dialog.html',
|
||||
}),
|
||||
},
|
||||
}, {
|
||||
text: gettext('Backup'),
|
||||
key: 13,
|
||||
className: 'btn btn-primary fa fa-lg fa-save pg-alertify-button',
|
||||
'data-btn-name': 'backup',
|
||||
}, {
|
||||
text: gettext('Cancel'),
|
||||
key: 27,
|
||||
className: 'btn btn-danger fa fa-lg fa-times pg-alertify-button',
|
||||
'data-btn-name': 'cancel',
|
||||
}],
|
||||
// Set options for dialog
|
||||
options: {
|
||||
title: title,
|
||||
//disable both padding and overflow control.
|
||||
padding: !1,
|
||||
overflow: !1,
|
||||
model: 0,
|
||||
resizable: true,
|
||||
maximizable: true,
|
||||
pinnable: false,
|
||||
closableByDimmer: false,
|
||||
modal: false,
|
||||
},
|
||||
};
|
||||
},
|
||||
hooks: {
|
||||
// triggered when the dialog is closed
|
||||
onclose: function() {
|
||||
if (this.view) {
|
||||
this.view.remove({
|
||||
data: true,
|
||||
internal: true,
|
||||
silent: true,
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
prepare: function() {
|
||||
var self = this;
|
||||
// Disable Backup button until user provides Filename
|
||||
this.__internal.buttons[2].element.disabled = true;
|
||||
var $container = $('<div class=\'backup_dialog\'></div>');
|
||||
var t = pgBrowser.tree,
|
||||
i = t.selected(),
|
||||
d = i && i.length == 1 ? t.itemData(i) : undefined,
|
||||
node = d && pgBrowser.Nodes[d._type];
|
||||
|
||||
if (!d)
|
||||
return;
|
||||
|
||||
var treeInfo = node.getTreeNodeHierarchy.apply(node, [i]);
|
||||
|
||||
var newModel = new BackupObjectModel({}, {
|
||||
node_info: treeInfo,
|
||||
}),
|
||||
fields = Backform.generateViewSchema(
|
||||
treeInfo, newModel, 'create', node, treeInfo.server, true
|
||||
);
|
||||
|
||||
var view = this.view = new Backform.Dialog({
|
||||
el: $container,
|
||||
model: newModel,
|
||||
schema: fields,
|
||||
});
|
||||
|
||||
$(this.elements.body.childNodes[0]).addClass(
|
||||
'alertify_tools_dialog_properties obj_properties'
|
||||
);
|
||||
|
||||
view.render();
|
||||
|
||||
this.elements.content.appendChild($container.get(0));
|
||||
|
||||
if(view) {
|
||||
view.$el.attr('tabindex', -1);
|
||||
// var dialogTabNavigator = pgBrowser.keyboardNavigation.getDialogTabNavigator(view);
|
||||
pgBrowser.keyboardNavigation.getDialogTabNavigator(view);
|
||||
var container = view.$el.find('.tab-content:first > .tab-pane.active:first');
|
||||
commonUtils.findAndSetFocus(container);
|
||||
}
|
||||
// Listen to model & if filename is provided then enable Backup button
|
||||
this.view.model.on('change', function() {
|
||||
if (!_.isUndefined(this.get('file')) && this.get('file') !== '') {
|
||||
this.errorModel.clear();
|
||||
self.__internal.buttons[2].element.disabled = false;
|
||||
} else {
|
||||
self.__internal.buttons[2].element.disabled = true;
|
||||
this.errorModel.set('file', gettext('Please provide filename'));
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
// Callback functions when click on the buttons of the Alertify dialogs
|
||||
callback: function(e) {
|
||||
// Fetch current server id
|
||||
var t = pgBrowser.tree,
|
||||
i = t.selected(),
|
||||
d = i && i.length == 1 ? t.itemData(i) : undefined,
|
||||
node = d && pgBrowser.Nodes[d._type];
|
||||
|
||||
if (e.button.element.name == 'dialog_help' || e.button.element.name == 'object_help') {
|
||||
e.cancel = true;
|
||||
pgBrowser.showHelp(e.button.element.name, e.button.element.getAttribute('url'),
|
||||
node, i, e.button.element.getAttribute('label'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.button['data-btn-name'] === 'backup') {
|
||||
if (!d)
|
||||
return;
|
||||
|
||||
var treeInfo = node.getTreeNodeHierarchy.apply(node, [i]);
|
||||
|
||||
// Set current database into model
|
||||
this.view.model.set('database', treeInfo.database._label);
|
||||
|
||||
// We will remove once object tree is implemented
|
||||
// If selected node is Schema then add it in model
|
||||
if (d._type == 'schema') {
|
||||
var schemas = [];
|
||||
schemas.push(d._label);
|
||||
this.view.model.set('schemas', schemas);
|
||||
}
|
||||
// If selected node is Table then add it in model along with
|
||||
// its schema
|
||||
if (d._type == 'table') {
|
||||
this.view.model.set(
|
||||
'tables', [
|
||||
[treeInfo.schema._label, d._label],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
// Remove ratio attribute from model if it has empty string.
|
||||
// The valid value can be between 0 to 9.
|
||||
if (_.isEmpty(this.view.model.get('ratio'))) {
|
||||
this.view.model.unset('ratio');
|
||||
}
|
||||
|
||||
var self = this,
|
||||
baseUrl = url_for('backup.create_object_job', {
|
||||
'sid': treeInfo.server._id,
|
||||
}),
|
||||
args = this.view.model.toJSON();
|
||||
|
||||
$.ajax({
|
||||
url: baseUrl,
|
||||
method: 'POST',
|
||||
data: {
|
||||
'data': JSON.stringify(args),
|
||||
},
|
||||
success: function(res) {
|
||||
if (res.success) {
|
||||
alertify.success(gettext('Backup job created.'), 5);
|
||||
pgBrowser.Events.trigger('pgadmin-bgprocess:created', self);
|
||||
}
|
||||
},
|
||||
error: function(xhr) {
|
||||
try {
|
||||
var err = JSON.parse(xhr.responseText);
|
||||
alertify.alert(
|
||||
gettext('Backup job failed.'),
|
||||
err.errormsg
|
||||
);
|
||||
} catch (e) {
|
||||
console.warn(e.stack || e);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
alertify.backup_objects(title).resizeTo('65%', '60%');
|
||||
let dialog = new globalBackupDialog.BackupDialog(
|
||||
pgBrowser,
|
||||
$,
|
||||
alertify,
|
||||
BackupObjectModel
|
||||
);
|
||||
dialog.draw(action, treeItem, null);
|
||||
},
|
||||
};
|
||||
return pgBrowser.Backup;
|
||||
|
72
web/pgadmin/tools/backup/static/js/backup_dialog.js
Normal file
72
web/pgadmin/tools/backup/static/js/backup_dialog.js
Normal file
@ -0,0 +1,72 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import gettext from '../../../../static/js/gettext';
|
||||
import Backform from '../../../../static/js/backform.pgadmin';
|
||||
import {Dialog} from '../../../../static/js/alertify/dialog';
|
||||
|
||||
export class BackupDialog extends Dialog {
|
||||
constructor(pgBrowser, $, alertify, BackupModel, backform = Backform) {
|
||||
super('Backup Error',
|
||||
'<div class=\'backup_dialog\'></div>',
|
||||
pgBrowser, $, alertify, BackupModel, backform
|
||||
);
|
||||
}
|
||||
|
||||
draw(action, aciTreeItem, params) {
|
||||
const serverInformation = this.retrieveAncestorOfTypeServer(aciTreeItem);
|
||||
|
||||
if (!serverInformation) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.hasBinariesConfiguration(serverInformation)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const typeOfDialog = BackupDialog.typeOfDialog(params);
|
||||
|
||||
if (!this.canExecuteOnCurrentDatabase(aciTreeItem)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const dialog = this.createOrGetDialog(
|
||||
BackupDialog.dialogTitle(typeOfDialog),
|
||||
typeOfDialog
|
||||
);
|
||||
dialog(true).resizeTo('60%', '50%');
|
||||
}
|
||||
|
||||
static typeOfDialog(params) {
|
||||
if (params === null) {
|
||||
return 'backup_objects';
|
||||
}
|
||||
let typeOfDialog = 'server';
|
||||
if (!_.isUndefined(params['globals']) && params['globals']) {
|
||||
typeOfDialog = 'globals';
|
||||
}
|
||||
return typeOfDialog;
|
||||
}
|
||||
|
||||
static dialogTitle(typeOfDialog) {
|
||||
if (typeOfDialog === 'backup_objects') {
|
||||
return null;
|
||||
}
|
||||
return ((typeOfDialog === 'globals') ?
|
||||
gettext('Backup Globals...') :
|
||||
gettext('Backup Server...'));
|
||||
}
|
||||
|
||||
dialogName(typeOfDialog) {
|
||||
if (typeOfDialog === 'backup_objects') {
|
||||
return typeOfDialog;
|
||||
}
|
||||
return 'BackupDialog_' + typeOfDialog;
|
||||
}
|
||||
}
|
258
web/pgadmin/tools/backup/static/js/backup_dialog_wrapper.js
Normal file
258
web/pgadmin/tools/backup/static/js/backup_dialog_wrapper.js
Normal file
@ -0,0 +1,258 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import {getTreeNodeHierarchyFromElement} from '../../../../static/js/tree/pgadmin_tree_node';
|
||||
import axios from 'axios/index';
|
||||
import gettext from '../../../../static/js/gettext';
|
||||
import url_for from '../../../../static/js/url_for';
|
||||
import _ from 'underscore';
|
||||
import {DialogWrapper} from '../../../../static/js/alertify/dialog_wrapper';
|
||||
|
||||
export class BackupDialogWrapper extends DialogWrapper {
|
||||
constructor(dialogContainerSelector, dialogTitle, typeOfDialog,
|
||||
jquery, pgBrowser, alertify, dialogModel, backform) {
|
||||
super(dialogContainerSelector, dialogTitle, jquery,
|
||||
pgBrowser, alertify, dialogModel, backform);
|
||||
this.typeOfDialog = typeOfDialog;
|
||||
}
|
||||
|
||||
main(title) {
|
||||
this.set('title', title);
|
||||
}
|
||||
|
||||
setup() {
|
||||
return {
|
||||
buttons: [{
|
||||
text: '',
|
||||
className: 'btn btn-default pull-left fa fa-lg fa-info',
|
||||
attrs: {
|
||||
name: 'object_help',
|
||||
type: 'button',
|
||||
url: 'backup.html',
|
||||
label: gettext('Backup'),
|
||||
},
|
||||
}, {
|
||||
text: '',
|
||||
key: 112,
|
||||
className: 'btn btn-default pull-left fa fa-lg fa-question',
|
||||
attrs: {
|
||||
name: 'dialog_help',
|
||||
type: 'button',
|
||||
label: gettext('Backup'),
|
||||
url: url_for('help.static', {
|
||||
'filename': 'backup_dialog.html',
|
||||
}),
|
||||
},
|
||||
}, {
|
||||
text: gettext('Backup'),
|
||||
key: 13,
|
||||
className: 'btn btn-primary fa fa-lg fa-save pg-alertify-button',
|
||||
'data-btn-name': 'backup',
|
||||
}, {
|
||||
text: gettext('Cancel'),
|
||||
key: 27,
|
||||
className: 'btn btn-danger fa fa-lg fa-times pg-alertify-button',
|
||||
'data-btn-name': 'cancel',
|
||||
}],
|
||||
// Set options for dialog
|
||||
options: {
|
||||
title: this.dialogTitle,
|
||||
//disable both padding and overflow control.
|
||||
padding: !1,
|
||||
overflow: !1,
|
||||
model: 0,
|
||||
resizable: true,
|
||||
maximizable: true,
|
||||
pinnable: false,
|
||||
closableByDimmer: false,
|
||||
modal: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
prepare() {
|
||||
this.disableBackupButton();
|
||||
|
||||
const $container = this.jquery(this.dialogContainerSelector);
|
||||
const selectedTreeNode = this.getSelectedNode();
|
||||
const selectedTreeNodeData = this.getSelectedNodeData(selectedTreeNode);
|
||||
if (!selectedTreeNodeData) {
|
||||
return;
|
||||
}
|
||||
|
||||
const node = this.pgBrowser.Nodes[selectedTreeNodeData._type];
|
||||
if (this.dialogTitle === null) {
|
||||
const title = `Backup (${node.label}: ${selectedTreeNodeData.label})`;
|
||||
this.main(title);
|
||||
}
|
||||
|
||||
const treeInfo = getTreeNodeHierarchyFromElement(this.pgBrowser, selectedTreeNode);
|
||||
const dialog = this.createDialog(node, treeInfo, this.typeOfDialog, $container);
|
||||
this.addAlertifyClassToBackupNodeChildNodes();
|
||||
dialog.render();
|
||||
|
||||
this.elements.content.appendChild($container.get(0));
|
||||
|
||||
this.focusOnDialog(dialog);
|
||||
this.setListenersForFilenameChanges();
|
||||
}
|
||||
|
||||
callback(event) {
|
||||
const selectedTreeNode = this.getSelectedNode();
|
||||
const selectedTreeNodeData = this.getSelectedNodeData(selectedTreeNode);
|
||||
const node = selectedTreeNodeData && this.pgBrowser.Nodes[selectedTreeNodeData._type];
|
||||
|
||||
if (this.wasHelpButtonPressed(event)) {
|
||||
event.cancel = true;
|
||||
this.pgBrowser.showHelp(
|
||||
event.button.element.name,
|
||||
event.button.element.getAttribute('url'),
|
||||
node,
|
||||
selectedTreeNode,
|
||||
event.button.element.getAttribute('label')
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.wasBackupButtonPressed(event)) {
|
||||
|
||||
if (!selectedTreeNodeData)
|
||||
return;
|
||||
|
||||
const serverIdentifier = this.retrieveServerIdentifier(node, selectedTreeNode);
|
||||
|
||||
const dialog = this;
|
||||
let urlShortcut = 'backup.create_server_job';
|
||||
if (this.typeOfDialog === 'backup_objects') {
|
||||
urlShortcut = 'backup.create_object_job';
|
||||
}
|
||||
const baseUrl = url_for(urlShortcut, {
|
||||
'sid': serverIdentifier,
|
||||
});
|
||||
|
||||
const treeInfo = getTreeNodeHierarchyFromElement(
|
||||
this.pgBrowser,
|
||||
selectedTreeNode
|
||||
);
|
||||
|
||||
this.setExtraParameters(selectedTreeNode, treeInfo);
|
||||
|
||||
let service = axios.create({});
|
||||
service.post(
|
||||
baseUrl,
|
||||
this.view.model.toJSON()
|
||||
).then(function () {
|
||||
dialog.alertify.success(gettext('Backup job created.'), 5);
|
||||
dialog.pgBrowser.Events.trigger('pgadmin-bgprocess:created', dialog);
|
||||
}).catch(function (error) {
|
||||
try {
|
||||
const err = error.response.data;
|
||||
dialog.alertify.alert(
|
||||
gettext('Backup job failed.'),
|
||||
err.errormsg
|
||||
);
|
||||
} catch (e) {
|
||||
console.warn(e.stack || e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
addAlertifyClassToBackupNodeChildNodes() {
|
||||
this.jquery(this.elements.body.childNodes[0]).addClass(
|
||||
'alertify_tools_dialog_properties obj_properties'
|
||||
);
|
||||
}
|
||||
|
||||
getSelectedNode() {
|
||||
const tree = this.pgBrowser.treeMenu;
|
||||
const selectedNode = tree.selected();
|
||||
if (selectedNode) {
|
||||
return tree.findNodeByDomElement(selectedNode);
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
disableBackupButton() {
|
||||
this.__internal.buttons[2].element.disabled = true;
|
||||
}
|
||||
|
||||
enableBackupButton() {
|
||||
this.__internal.buttons[2].element.disabled = false;
|
||||
}
|
||||
|
||||
createDialog(node, treeInfo, typeOfDialog, $container) {
|
||||
let attributes = {};
|
||||
if (typeOfDialog !== 'backup_objects') {
|
||||
attributes['type'] = typeOfDialog;
|
||||
}
|
||||
// Instance of backbone model
|
||||
const newModel = new this.dialogModel(attributes, {
|
||||
node_info: treeInfo,
|
||||
});
|
||||
const fields = this.backform.generateViewSchema(
|
||||
treeInfo, newModel, 'create', node, treeInfo.server, true
|
||||
);
|
||||
|
||||
return this.view = new this.backform.Dialog({
|
||||
el: $container,
|
||||
model: newModel,
|
||||
schema: fields,
|
||||
});
|
||||
}
|
||||
|
||||
retrieveServerIdentifier(node, selectedTreeNode) {
|
||||
const treeInfo = getTreeNodeHierarchyFromElement(
|
||||
this.pgBrowser,
|
||||
selectedTreeNode
|
||||
);
|
||||
return treeInfo.server._id;
|
||||
}
|
||||
|
||||
setListenersForFilenameChanges() {
|
||||
const self = this;
|
||||
|
||||
this.view.model.on('change', function () {
|
||||
if (!_.isUndefined(this.get('file')) && this.get('file') !== '') {
|
||||
this.errorModel.clear();
|
||||
self.enableBackupButton();
|
||||
} else {
|
||||
self.disableBackupButton();
|
||||
this.errorModel.set('file', gettext('Please provide a filename'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
setExtraParameters(selectedTreeNode, treeInfo) {
|
||||
if (this.typeOfDialog === 'backup_objects') {
|
||||
|
||||
this.view.model.set('database', treeInfo.database._label);
|
||||
|
||||
const nodeData = selectedTreeNode.getData();
|
||||
if (nodeData._type === 'schema') {
|
||||
this.view.model.set('schemas', [nodeData._label]);
|
||||
}
|
||||
|
||||
if (nodeData._type === 'table') {
|
||||
this.view.model.set('tables', [
|
||||
[treeInfo.schema._label, nodeData._label],
|
||||
]);
|
||||
}
|
||||
|
||||
if (_.isEmpty(this.view.model.get('ratio'))) {
|
||||
this.view.model.unset('ratio');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wasBackupButtonPressed(event) {
|
||||
return event.button['data-btn-name'] === 'backup';
|
||||
}
|
||||
}
|
23
web/pgadmin/tools/backup/static/js/menu_utils.js
Normal file
23
web/pgadmin/tools/backup/static/js/menu_utils.js
Normal file
@ -0,0 +1,23 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import {isValidTreeNodeData} from '../../../../static/js/tree/tree';
|
||||
|
||||
export const backupSupportedNodes = [
|
||||
'database', 'schema', 'table', 'partition',
|
||||
];
|
||||
|
||||
function isNodeAServerAndConnected(treeNodeData) {
|
||||
return (('server' === treeNodeData._type) && treeNodeData.connected);
|
||||
}
|
||||
|
||||
export function menuEnabledServer(treeNodeData) {
|
||||
return isValidTreeNodeData(treeNodeData)
|
||||
&& isNodeAServerAndConnected(treeNodeData);
|
||||
}
|
@ -1,10 +1,14 @@
|
||||
define('pgadmin.datagrid', [
|
||||
'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
|
||||
'pgadmin.alertifyjs', 'sources/pgadmin', 'bundled_codemirror',
|
||||
'sources/sqleditor_utils', 'backbone', 'wcdocker',
|
||||
'sources/sqleditor_utils', 'backbone',
|
||||
'tools/datagrid/static/js/show_data',
|
||||
'tools/datagrid/static/js/get_panel_title',
|
||||
'tools/datagrid/static/js/show_query_tool',
|
||||
'wcdocker',
|
||||
], function(
|
||||
gettext, url_for, $, _, alertify, pgAdmin, codemirror, sqlEditorUtils,
|
||||
Backbone
|
||||
Backbone, showData, panelTitle, showQueryTool
|
||||
) {
|
||||
// Some scripts do export their object in the window only.
|
||||
// Generally the one, which do no have AMD support.
|
||||
@ -161,55 +165,7 @@ define('pgadmin.datagrid', [
|
||||
|
||||
// This is a callback function to show data when user click on menu item.
|
||||
show_data_grid: function(data, i) {
|
||||
var self = this,
|
||||
d = pgAdmin.Browser.tree.itemData(i);
|
||||
if (d === undefined) {
|
||||
alertify.alert(
|
||||
gettext('Data Grid Error'),
|
||||
gettext('No object selected.')
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the parent data from the tree node hierarchy.
|
||||
var node = pgBrowser.Nodes[d._type],
|
||||
parentData = node.getTreeNodeHierarchy(i);
|
||||
|
||||
// If server, database or schema is undefined then return from the function.
|
||||
if (parentData.server === undefined || parentData.database === undefined) {
|
||||
return;
|
||||
}
|
||||
// If schema, view, catalog object all are undefined then return from the function.
|
||||
if (parentData.schema === undefined && parentData.view === undefined &&
|
||||
parentData.catalog === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
var nsp_name = '';
|
||||
|
||||
if (parentData.schema != undefined) {
|
||||
nsp_name = parentData.schema.label;
|
||||
}
|
||||
else if (parentData.view != undefined) {
|
||||
nsp_name = parentData.view.label;
|
||||
}
|
||||
else if (parentData.catalog != undefined) {
|
||||
nsp_name = parentData.catalog.label;
|
||||
}
|
||||
var url_params = {
|
||||
'cmd_type': data.mnuid,
|
||||
'obj_type': d._type,
|
||||
'sgid': parentData.server_group._id,
|
||||
'sid': parentData.server._id,
|
||||
'did': parentData.database._id,
|
||||
'obj_id': d._id,
|
||||
};
|
||||
|
||||
var baseUrl = url_for('datagrid.initialize_datagrid', url_params);
|
||||
var grid_title = parentData.server.label + ' - ' + parentData.database.label + ' - '
|
||||
+ nsp_name + '.' + d.label;
|
||||
|
||||
self.create_transaction(baseUrl, null, 'false', parentData.server.server_type, '', grid_title, '');
|
||||
showData.showDataGrid(this, pgBrowser, alertify, data, i);
|
||||
},
|
||||
|
||||
// This is a callback function to show filtered data when user click on menu item.
|
||||
@ -384,63 +340,12 @@ define('pgadmin.datagrid', [
|
||||
},
|
||||
|
||||
get_panel_title: function() {
|
||||
// Get the parent data from the tree node hierarchy.
|
||||
var tree = pgAdmin.Browser.tree,
|
||||
selected_item = tree.selected(),
|
||||
item_data = tree.itemData(selected_item);
|
||||
|
||||
var node = pgBrowser.Nodes[item_data._type],
|
||||
parentData = node.getTreeNodeHierarchy(selected_item);
|
||||
|
||||
// If server, database is undefined then return from the function.
|
||||
if (parentData.server === undefined) {
|
||||
return;
|
||||
}
|
||||
// If Database is not available then use default db
|
||||
var db_label = parentData.database ? parentData.database.label
|
||||
: parentData.server.db;
|
||||
|
||||
var grid_title = db_label + ' on ' + parentData.server.user.name + '@' +
|
||||
parentData.server.label;
|
||||
return grid_title;
|
||||
return panelTitle.getPanelTitle(pgBrowser);
|
||||
},
|
||||
// This is a callback function to show query tool when user click on menu item.
|
||||
show_query_tool: function(url, i, panel_title) {
|
||||
var sURL = url || '',
|
||||
d = pgAdmin.Browser.tree.itemData(i);
|
||||
|
||||
panel_title = panel_title || '';
|
||||
if (d === undefined) {
|
||||
alertify.alert(
|
||||
gettext('Query Tool Error'),
|
||||
gettext('No object selected.')
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the parent data from the tree node hierarchy.
|
||||
var node = pgBrowser.Nodes[d._type],
|
||||
parentData = node.getTreeNodeHierarchy(i);
|
||||
|
||||
// If server, database is undefined then return from the function.
|
||||
if (parentData.server === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
var url_params = {
|
||||
'sgid': parentData.server_group._id,
|
||||
'sid': parentData.server._id,
|
||||
},
|
||||
url_endpoint = 'datagrid.initialize_query_tool';
|
||||
// If database not present then use Maintenance database
|
||||
// We will handle this at server side
|
||||
if (parentData.database) {
|
||||
url_params['did'] = parentData.database._id;
|
||||
url_endpoint = 'datagrid.initialize_query_tool_with_did';
|
||||
}
|
||||
var baseUrl = url_for(url_endpoint, url_params);
|
||||
|
||||
this.create_transaction(baseUrl, null, 'true', parentData.server.server_type, sURL, panel_title, '', false);
|
||||
show_query_tool: function(url, aciTreeIdentifier, panelTitle) {
|
||||
showQueryTool.showQueryTool(this, pgBrowser, alertify, url,
|
||||
aciTreeIdentifier, panelTitle);
|
||||
},
|
||||
create_transaction: function(baseUrl, target, is_query_tool, server_type, sURL, panel_title, sql_filter, recreate) {
|
||||
var self = this;
|
||||
|
33
web/pgadmin/tools/datagrid/static/js/get_panel_title.js
Normal file
33
web/pgadmin/tools/datagrid/static/js/get_panel_title.js
Normal file
@ -0,0 +1,33 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import {getTreeNodeHierarchyFromIdentifier} from '../../../../static/js/tree/pgadmin_tree_node';
|
||||
|
||||
function getDatabaseLabel(parentData) {
|
||||
return parentData.database ? parentData.database.label
|
||||
: parentData.server.db;
|
||||
}
|
||||
|
||||
function isServerInformationAvailable(parentData) {
|
||||
return parentData.server === undefined;
|
||||
}
|
||||
|
||||
export function getPanelTitle(pgBrowser) {
|
||||
const selected_item = pgBrowser.treeMenu.selected();
|
||||
|
||||
const parentData = getTreeNodeHierarchyFromIdentifier
|
||||
.call(pgBrowser, selected_item);
|
||||
if (isServerInformationAvailable(parentData)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const db_label = getDatabaseLabel(parentData);
|
||||
|
||||
return `${db_label} on ${parentData.server.user.name}@${parentData.server.label}`;
|
||||
}
|
92
web/pgadmin/tools/datagrid/static/js/show_data.js
Normal file
92
web/pgadmin/tools/datagrid/static/js/show_data.js
Normal file
@ -0,0 +1,92 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
import gettext from '../../../../static/js/gettext';
|
||||
import url_for from '../../../../static/js/url_for';
|
||||
import {getTreeNodeHierarchyFromIdentifier} from '../../../../static/js/tree/pgadmin_tree_node';
|
||||
|
||||
export function showDataGrid(
|
||||
datagrid,
|
||||
pgBrowser,
|
||||
alertify,
|
||||
connectionData,
|
||||
aciTreeIdentifier
|
||||
) {
|
||||
const node = pgBrowser.treeMenu.findNodeByDomElement(aciTreeIdentifier);
|
||||
if (node === undefined || !node.getData()) {
|
||||
alertify.alert(
|
||||
gettext('Data Grid Error'),
|
||||
gettext('No object selected.')
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const parentData = getTreeNodeHierarchyFromIdentifier.call(
|
||||
pgBrowser,
|
||||
aciTreeIdentifier
|
||||
);
|
||||
|
||||
if (hasServerOrDatabaseConfiguration(parentData)
|
||||
|| !hasSchemaOrCatalogOrViewInformation(parentData)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let namespaceName = retrieveNameSpaceName(parentData);
|
||||
const baseUrl = generateUrl(connectionData, node.getData(), parentData);
|
||||
const grid_title = generateDatagridTitle(parentData, namespaceName, node.getData());
|
||||
|
||||
datagrid.create_transaction(
|
||||
baseUrl,
|
||||
null,
|
||||
'false',
|
||||
parentData.server.server_type,
|
||||
'',
|
||||
grid_title,
|
||||
''
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function retrieveNameSpaceName(parentData) {
|
||||
if (parentData.schema !== undefined) {
|
||||
return parentData.schema.label;
|
||||
}
|
||||
else if (parentData.view !== undefined) {
|
||||
return parentData.view.label;
|
||||
}
|
||||
else if (parentData.catalog !== undefined) {
|
||||
return parentData.catalog.label;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
function generateUrl(connectionData, nodeData, parentData) {
|
||||
const url_params = {
|
||||
'cmd_type': connectionData.mnuid,
|
||||
'obj_type': nodeData._type,
|
||||
'sgid': parentData.server_group._id,
|
||||
'sid': parentData.server._id,
|
||||
'did': parentData.database._id,
|
||||
'obj_id': nodeData._id,
|
||||
};
|
||||
|
||||
return url_for('datagrid.initialize_datagrid', url_params);
|
||||
}
|
||||
|
||||
function hasServerOrDatabaseConfiguration(parentData) {
|
||||
return parentData.server === undefined || parentData.database === undefined;
|
||||
}
|
||||
|
||||
function hasSchemaOrCatalogOrViewInformation(parentData) {
|
||||
return parentData.schema !== undefined || parentData.view !== undefined ||
|
||||
parentData.catalog !== undefined;
|
||||
}
|
||||
|
||||
function generateDatagridTitle(parentData, namespaceName, nodeData) {
|
||||
return `${parentData.server.label} - ${parentData.database.label} - ${namespaceName}.${nodeData.label}`;
|
||||
}
|
63
web/pgadmin/tools/datagrid/static/js/show_query_tool.js
Normal file
63
web/pgadmin/tools/datagrid/static/js/show_query_tool.js
Normal file
@ -0,0 +1,63 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import gettext from '../../../../static/js/gettext';
|
||||
import url_for from '../../../../static/js/url_for';
|
||||
import {getTreeNodeHierarchyFromIdentifier} from '../../../../static/js/tree/pgadmin_tree_node';
|
||||
|
||||
function hasDatabaseInformation(parentData) {
|
||||
return parentData.database;
|
||||
}
|
||||
|
||||
function generateUrl(parentData) {
|
||||
let url_endpoint = 'datagrid.initialize_query_tool';
|
||||
let url_params = {
|
||||
'sgid': parentData.server_group._id,
|
||||
'sid': parentData.server._id,
|
||||
};
|
||||
|
||||
if (hasDatabaseInformation(parentData)) {
|
||||
url_params['did'] = parentData.database._id;
|
||||
url_endpoint = 'datagrid.initialize_query_tool_with_did';
|
||||
}
|
||||
|
||||
return url_for(url_endpoint, url_params);
|
||||
}
|
||||
|
||||
function hasServerInformations(parentData) {
|
||||
return parentData.server === undefined;
|
||||
}
|
||||
|
||||
export function showQueryTool(datagrid, pgBrowser, alertify, url,
|
||||
aciTreeIdentifier, panelTitle) {
|
||||
const sURL = url || '';
|
||||
const queryToolTitle = panelTitle || '';
|
||||
|
||||
const currentNode = pgBrowser.treeMenu.findNodeByDomElement(aciTreeIdentifier);
|
||||
if (currentNode === undefined) {
|
||||
alertify.alert(
|
||||
gettext('Query Tool Error'),
|
||||
gettext('No object selected.')
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const parentData = getTreeNodeHierarchyFromIdentifier.call(
|
||||
pgBrowser, aciTreeIdentifier);
|
||||
|
||||
if (hasServerInformations(parentData)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const baseUrl = generateUrl(parentData);
|
||||
|
||||
datagrid.create_transaction(
|
||||
baseUrl, null, 'true',
|
||||
parentData.server.server_type, sURL, queryToolTitle, '', false);
|
||||
}
|
@ -2,12 +2,15 @@
|
||||
define([
|
||||
'sources/gettext', 'sources/url_for', 'jquery', 'underscore', 'backbone',
|
||||
'pgadmin.alertifyjs', 'pgadmin.backgrid', 'pgadmin.backform',
|
||||
'pgadmin.browser', 'pgadmin.browser.node', 'backgrid.select.all',
|
||||
'pgadmin.browser', 'pgadmin.browser.node',
|
||||
'tools/grant_wizard/static/js/menu_utils',
|
||||
'sources/nodes/supported_database_node',
|
||||
'backgrid.select.all',
|
||||
'backgrid.filter', 'pgadmin.browser.server.privilege',
|
||||
'pgadmin.browser.wizard',
|
||||
], function(
|
||||
gettext, url_for, $, _, Backbone, Alertify, Backgrid, Backform, pgBrowser,
|
||||
pgNode
|
||||
pgNode, menuUtils, supportedNodes
|
||||
) {
|
||||
|
||||
// if module is already initialized, refer to that.
|
||||
@ -143,41 +146,6 @@ define([
|
||||
|
||||
this.initialized = true;
|
||||
|
||||
// Define list of nodes on which grant wizard context menu option appears
|
||||
var supported_nodes = [
|
||||
'schema', 'coll-function', 'coll-sequence',
|
||||
'coll-table', 'coll-view', 'coll-procedure',
|
||||
'coll-mview', 'database', 'coll-trigger_function',
|
||||
],
|
||||
|
||||
/**
|
||||
Enable/disable grantwizard menu in tools based
|
||||
on node selected
|
||||
if selected node is present in supported_nodes,
|
||||
menu will be enabled otherwise disabled.
|
||||
Also, hide it for system view in catalogs
|
||||
*/
|
||||
menu_enabled = function(itemData, item) {
|
||||
var t = pgBrowser.tree,
|
||||
i = item,
|
||||
d = itemData;
|
||||
var parent_item = t.hasParent(i) ? t.parent(i) : null,
|
||||
parent_data = parent_item ? t.itemData(parent_item) : null;
|
||||
if (!_.isUndefined(d) && !_.isNull(d) && !_.isNull(parent_data)) {
|
||||
if (_.indexOf(supported_nodes, d._type) !== -1 &&
|
||||
parent_data._type != 'catalog') {
|
||||
if (d._type == 'database' && d.allowConn)
|
||||
return true;
|
||||
else if (d._type != 'database')
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
} else
|
||||
return false;
|
||||
} else
|
||||
return false;
|
||||
};
|
||||
|
||||
// Define the nodes on which the menus to be appear
|
||||
var menus = [{
|
||||
name: 'grant_wizard_schema',
|
||||
@ -187,21 +155,25 @@ define([
|
||||
priority: 14,
|
||||
label: gettext('Grant Wizard...'),
|
||||
icon: 'fa fa-unlock-alt',
|
||||
enable: menu_enabled,
|
||||
enable: supportedNodes.enabled.bind(
|
||||
null, pgBrowser.treeMenu, menuUtils.supportedNodes
|
||||
),
|
||||
}];
|
||||
|
||||
// Add supported menus into the menus list
|
||||
for (var idx = 0; idx < supported_nodes.length; idx++) {
|
||||
for (var idx = 0; idx < menuUtils.supportedNodes.length; idx++) {
|
||||
menus.push({
|
||||
name: 'grant_wizard_schema_context_' + supported_nodes[idx],
|
||||
node: supported_nodes[idx],
|
||||
name: 'grant_wizard_schema_context_' + menuUtils.supportedNodes[idx],
|
||||
node: menuUtils.supportedNodes[idx],
|
||||
module: this,
|
||||
applies: ['context'],
|
||||
callback: 'start_grant_wizard',
|
||||
priority: 14,
|
||||
label: gettext('Grant Wizard...'),
|
||||
icon: 'fa fa-unlock-alt',
|
||||
enable: menu_enabled,
|
||||
enable: supportedNodes.enabled.bind(
|
||||
null, pgBrowser.treeMenu, menuUtils.supportedNodes
|
||||
),
|
||||
});
|
||||
}
|
||||
pgBrowser.add_menus(menus);
|
||||
|
16
web/pgadmin/tools/grant_wizard/static/js/menu_utils.js
Normal file
16
web/pgadmin/tools/grant_wizard/static/js/menu_utils.js
Normal file
@ -0,0 +1,16 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
export const supportedNodes = [
|
||||
'schema', 'coll-function', 'coll-sequence',
|
||||
'coll-table', 'coll-view', 'coll-procedure',
|
||||
'coll-mview', 'database', 'coll-trigger_function',
|
||||
];
|
||||
|
||||
|
@ -1,10 +1,12 @@
|
||||
define([
|
||||
'sources/gettext', 'sources/url_for', 'jquery', 'underscore', 'underscore.string', 'pgadmin.alertifyjs',
|
||||
'sources/pgadmin', 'pgadmin.browser', 'backbone', 'backgrid', 'backform',
|
||||
'sources/utils', 'pgadmin.backform', 'pgadmin.backgrid', 'pgadmin.browser.node.ui',
|
||||
'sources/utils',
|
||||
'sources/nodes/supported_database_node',
|
||||
'pgadmin.backform', 'pgadmin.backgrid', 'pgadmin.browser.node.ui',
|
||||
], function(
|
||||
gettext, url_for, $, _, S, Alertify, pgAdmin, pgBrowser, Backbone, Backgrid,
|
||||
Backform, commonUtils
|
||||
Backform, commonUtils, supportedNodes
|
||||
) {
|
||||
|
||||
pgAdmin = pgAdmin || window.pgAdmin || {};
|
||||
@ -383,25 +385,6 @@ Backform, commonUtils
|
||||
|
||||
this.initialized = true;
|
||||
|
||||
/*
|
||||
* Enable/disable import menu in tools based on node selected. Import
|
||||
* menu will be enabled only when user select table node.
|
||||
*/
|
||||
var menu_enabled = function(itemData, item) {
|
||||
var t = pgBrowser.tree,
|
||||
i = item,
|
||||
d = itemData;
|
||||
var parent_item = t.hasParent(i) ? t.parent(i) : null,
|
||||
parent_data = parent_item ? t.itemData(parent_item) : null;
|
||||
if (!_.isUndefined(d) && !_.isNull(d) && !_.isNull(parent_data))
|
||||
return (
|
||||
(_.indexOf(['table'], d._type) !== -1 &&
|
||||
parent_data._type != 'catalog') ? true : false
|
||||
);
|
||||
else
|
||||
return false;
|
||||
};
|
||||
|
||||
// Initialize the context menu to display the import options when user open the context menu for table
|
||||
pgBrowser.add_menus([{
|
||||
name: 'import',
|
||||
@ -413,7 +396,9 @@ Backform, commonUtils
|
||||
priority: 10,
|
||||
label: gettext('Import/Export...'),
|
||||
icon: 'fa fa-shopping-cart',
|
||||
enable: menu_enabled,
|
||||
enable: supportedNodes.enabled.bind(
|
||||
null, pgBrowser.treeMenu, ['table']
|
||||
),
|
||||
}]);
|
||||
},
|
||||
|
||||
|
@ -2,11 +2,14 @@ define([
|
||||
'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
|
||||
'underscore.string', 'pgadmin.alertifyjs', 'sources/pgadmin', 'pgadmin.browser', 'backbone',
|
||||
'backgrid', 'backform', 'sources/utils',
|
||||
'tools/maintenance/static/js/menu_utils',
|
||||
'sources/nodes/supported_database_node',
|
||||
'pgadmin.backform', 'pgadmin.backgrid',
|
||||
'pgadmin.browser.node.ui',
|
||||
], function(
|
||||
gettext, url_for, $, _, S, Alertify, pgAdmin, pgBrowser, Backbone, Backgrid,
|
||||
Backform, commonUtils
|
||||
Backform, commonUtils,
|
||||
menuUtils, supportedNodes
|
||||
) {
|
||||
|
||||
pgAdmin = pgAdmin || window.pgAdmin || {};
|
||||
@ -168,36 +171,6 @@ define([
|
||||
|
||||
this.initialized = true;
|
||||
|
||||
var maintenance_supported_nodes = [
|
||||
'database', 'table', 'primary_key',
|
||||
'unique_constraint', 'index', 'partition',
|
||||
];
|
||||
|
||||
/**
|
||||
Enable/disable Maintenance menu in tools based on node selected.
|
||||
Maintenance menu will be enabled only when user select table and database node.
|
||||
*/
|
||||
var menu_enabled = function(itemData, item) {
|
||||
var t = pgBrowser.tree,
|
||||
i = item,
|
||||
d = itemData;
|
||||
var parent_item = t.hasParent(i) ? t.parent(i) : null,
|
||||
parent_data = parent_item ? t.itemData(parent_item) : null;
|
||||
if (!_.isUndefined(d) && !_.isNull(d) && !_.isNull(parent_data)) {
|
||||
if (_.indexOf(maintenance_supported_nodes, d._type) !== -1 &&
|
||||
parent_data._type != 'catalog') {
|
||||
if (d._type == 'database' && d.allowConn)
|
||||
return true;
|
||||
else if (d._type != 'database')
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
} else
|
||||
return false;
|
||||
} else
|
||||
return false;
|
||||
};
|
||||
|
||||
var menus = [{
|
||||
name: 'maintenance',
|
||||
module: this,
|
||||
@ -206,21 +179,25 @@ define([
|
||||
priority: 10,
|
||||
label: gettext('Maintenance...'),
|
||||
icon: 'fa fa-wrench',
|
||||
enable: menu_enabled,
|
||||
enable: supportedNodes.enabled.bind(
|
||||
null, pgBrowser.treeMenu, menuUtils.maintenanceSupportedNodes
|
||||
),
|
||||
}];
|
||||
|
||||
// Add supported menus into the menus list
|
||||
for (var idx = 0; idx < maintenance_supported_nodes.length; idx++) {
|
||||
for (var idx = 0; idx < menuUtils.maintenanceSupportedNodes.length; idx++) {
|
||||
menus.push({
|
||||
name: 'maintenance_context_' + maintenance_supported_nodes[idx],
|
||||
node: maintenance_supported_nodes[idx],
|
||||
name: 'maintenance_context_' + menuUtils.maintenanceSupportedNodes[idx],
|
||||
node: menuUtils.maintenanceSupportedNodes[idx],
|
||||
module: this,
|
||||
applies: ['context'],
|
||||
callback: 'callback_maintenance',
|
||||
priority: 10,
|
||||
label: gettext('Maintenance...'),
|
||||
icon: 'fa fa-wrench',
|
||||
enable: menu_enabled,
|
||||
enable: supportedNodes.enabled.bind(
|
||||
null, pgBrowser.treeMenu, menuUtils.maintenanceSupportedNodes
|
||||
),
|
||||
});
|
||||
}
|
||||
pgBrowser.add_menus(menus);
|
||||
|
13
web/pgadmin/tools/maintenance/static/js/menu_utils.js
Normal file
13
web/pgadmin/tools/maintenance/static/js/menu_utils.js
Normal file
@ -0,0 +1,13 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
export const maintenanceSupportedNodes = [
|
||||
'database', 'table', 'primary_key',
|
||||
'unique_constraint', 'index', 'partition',
|
||||
];
|
18
web/pgadmin/tools/restore/static/js/menu_utils.js
Normal file
18
web/pgadmin/tools/restore/static/js/menu_utils.js
Normal file
@ -0,0 +1,18 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
export const restoreSupportedNodes = [
|
||||
'database',
|
||||
'schema',
|
||||
'table',
|
||||
'function',
|
||||
'trigger',
|
||||
'index',
|
||||
'partition',
|
||||
];
|
@ -1,11 +1,13 @@
|
||||
// Restore dialog
|
||||
define('tools.restore', [
|
||||
'sources/gettext', 'sources/url_for', 'jquery', 'underscore', 'backbone',
|
||||
'underscore.string', 'pgadmin.alertifyjs', 'pgadmin.browser',
|
||||
'pgadmin.backgrid', 'pgadmin.backform', 'sources/utils',
|
||||
'tools/restore/static/js/menu_utils',
|
||||
'sources/nodes/supported_database_node',
|
||||
'tools/restore/static/js/restore_dialog',
|
||||
], function(
|
||||
gettext, url_for, $, _, Backbone, S, alertify, pgBrowser, Backgrid, Backform,
|
||||
commonUtils
|
||||
commonUtils, menuUtils, supportedNodes, restoreDialog
|
||||
) {
|
||||
|
||||
// if module is already initialized, refer to that.
|
||||
@ -307,59 +309,6 @@ commonUtils
|
||||
|
||||
this.initialized = true;
|
||||
|
||||
// Define list of nodes on which restore context menu option appears
|
||||
var restore_supported_nodes = [
|
||||
'database', 'schema',
|
||||
'table', 'function',
|
||||
'trigger', 'index',
|
||||
'partition',
|
||||
];
|
||||
|
||||
/**
|
||||
Enable/disable restore menu in tools based
|
||||
on node selected
|
||||
if selected node is present in supported_nodes,
|
||||
menu will be enabled otherwise disabled.
|
||||
Also, hide it for system view in catalogs
|
||||
*/
|
||||
var menu_enabled = function(itemData, item, data) {
|
||||
var t = pgBrowser.tree,
|
||||
i = item,
|
||||
d = itemData;
|
||||
var parent_item = t.hasParent(i) ? t.parent(i) : null,
|
||||
parent_data = parent_item ? t.itemData(parent_item) : null;
|
||||
if (!_.isUndefined(d) && !_.isNull(d) && !_.isNull(parent_data)) {
|
||||
if (_.indexOf(restore_supported_nodes, d._type) !== -1 &&
|
||||
is_parent_catalog(itemData, item, data)) {
|
||||
if (d._type == 'database' && d.allowConn)
|
||||
return true;
|
||||
else if (d._type != 'database')
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
} else
|
||||
return false;
|
||||
} else
|
||||
return false;
|
||||
};
|
||||
|
||||
var is_parent_catalog = function(itemData, item) {
|
||||
var t = pgBrowser.tree,
|
||||
i = item,
|
||||
d = itemData;
|
||||
|
||||
// To iterate over tree to check parent node
|
||||
while (i) {
|
||||
// If it is schema then allow user to restore
|
||||
if (_.indexOf(['catalog'], d._type) > -1)
|
||||
return false;
|
||||
i = t.hasParent(i) ? t.parent(i) : null;
|
||||
d = i ? t.itemData(i) : null;
|
||||
}
|
||||
// by default we do not want to allow create menu
|
||||
return true;
|
||||
};
|
||||
|
||||
// Define the nodes on which the menus to be appear
|
||||
var menus = [{
|
||||
name: 'restore_object',
|
||||
@ -369,20 +318,24 @@ commonUtils
|
||||
priority: 13,
|
||||
label: gettext('Restore...'),
|
||||
icon: 'fa fa-upload',
|
||||
enable: menu_enabled,
|
||||
enable: supportedNodes.enabled.bind(
|
||||
null, pgBrowser.treeMenu, menuUtils.restoreSupportedNodes
|
||||
),
|
||||
}];
|
||||
|
||||
for (var idx = 0; idx < restore_supported_nodes.length; idx++) {
|
||||
for (var idx = 0; idx < menuUtils.restoreSupportedNodes.length; idx++) {
|
||||
menus.push({
|
||||
name: 'restore_' + restore_supported_nodes[idx],
|
||||
node: restore_supported_nodes[idx],
|
||||
name: 'restore_' + menuUtils.restoreSupportedNodes[idx],
|
||||
node: menuUtils.restoreSupportedNodes[idx],
|
||||
module: this,
|
||||
applies: ['context'],
|
||||
callback: 'restore_objects',
|
||||
priority: 13,
|
||||
label: gettext('Restore...'),
|
||||
icon: 'fa fa-upload',
|
||||
enable: menu_enabled,
|
||||
enable: supportedNodes.enabled.bind(
|
||||
null, pgBrowser.treeMenu, menuUtils.restoreSupportedNodes
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
@ -391,318 +344,10 @@ commonUtils
|
||||
},
|
||||
// Callback to draw Backup Dialog for objects
|
||||
restore_objects: function(action, treeItem) {
|
||||
|
||||
var i = treeItem || pgBrowser.tree.selected(),
|
||||
server_data = null;
|
||||
|
||||
while (i) {
|
||||
var node_data = pgBrowser.tree.itemData(i);
|
||||
if (node_data._type == 'server') {
|
||||
server_data = node_data;
|
||||
break;
|
||||
}
|
||||
|
||||
if (pgBrowser.tree.hasParent(i)) {
|
||||
i = $(pgBrowser.tree.parent(i));
|
||||
} else {
|
||||
alertify.alert(
|
||||
gettext('Restore Error'),
|
||||
gettext('Please select server or child node from tree.')
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!server_data) {
|
||||
return;
|
||||
}
|
||||
|
||||
var module = 'paths',
|
||||
preference_name = 'pg_bin_dir',
|
||||
msg = gettext('Please configure the PostgreSQL Binary Path in the Preferences dialog.');
|
||||
|
||||
if ((server_data.type && server_data.type == 'ppas') ||
|
||||
server_data.server_type == 'ppas') {
|
||||
preference_name = 'ppas_bin_dir';
|
||||
msg = gettext('Please configure the EDB Advanced Server Binary Path in the Preferences dialog.');
|
||||
}
|
||||
|
||||
var preference = pgBrowser.get_preference(module, preference_name);
|
||||
|
||||
if (preference) {
|
||||
if (!preference.value) {
|
||||
alertify.alert(gettext('Configuration required'), msg);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
alertify.alert(
|
||||
gettext('Restore Error'),
|
||||
S(gettext('Failed to load preference %s of module %s')).sprintf(preference_name, module).value()
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
var title = S(gettext('Restore (%s: %s)')),
|
||||
tree = pgBrowser.tree,
|
||||
item = treeItem || tree.selected(),
|
||||
data = item && item.length == 1 && tree.itemData(item),
|
||||
node = data && data._type && pgBrowser.Nodes[data._type];
|
||||
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
var treeInfo = node.getTreeNodeHierarchy.apply(node, [item]);
|
||||
|
||||
if (treeInfo.database._label.indexOf('=') >= 0) {
|
||||
alertify.alert(
|
||||
gettext('Restore error'),
|
||||
gettext('Restore job creation failed. '+
|
||||
'Databases with = symbols in the name cannot be restored using this utility.')
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
title = title.sprintf(node.label, data.label).value();
|
||||
|
||||
if (!alertify.pg_restore) {
|
||||
// Create Dialog title on the fly with node details
|
||||
alertify.dialog('pg_restore', function factory() {
|
||||
return {
|
||||
main: function(title, item, data, node) {
|
||||
this.set('title', title);
|
||||
this.setting('pg_node', node);
|
||||
this.setting('pg_item', item);
|
||||
this.setting('pg_item_data', data);
|
||||
},
|
||||
build: function() {
|
||||
alertify.pgDialogBuild.apply(this);
|
||||
},
|
||||
setup: function() {
|
||||
return {
|
||||
buttons: [{
|
||||
text: '',
|
||||
className: 'btn btn-default pull-left fa fa-lg fa-info',
|
||||
attrs: {
|
||||
name: 'object_help',
|
||||
type: 'button',
|
||||
url: 'backup.html',
|
||||
label: gettext('Restore'),
|
||||
},
|
||||
}, {
|
||||
text: '',
|
||||
key: 112,
|
||||
className: 'btn btn-default pull-left fa fa-lg fa-question',
|
||||
attrs: {
|
||||
name: 'dialog_help',
|
||||
type: 'button',
|
||||
label: gettext('Restore'),
|
||||
url: url_for('help.static', {
|
||||
'filename': 'restore_dialog.html',
|
||||
}),
|
||||
},
|
||||
}, {
|
||||
text: gettext('Restore'),
|
||||
key: 13,
|
||||
className: 'btn btn-primary fa fa-upload pg-alertify-button',
|
||||
restore: true,
|
||||
'data-btn-name': 'restore',
|
||||
}, {
|
||||
text: gettext('Cancel'),
|
||||
key: 27,
|
||||
className: 'btn btn-danger fa fa-lg fa-times pg-alertify-button',
|
||||
restore: false,
|
||||
'data-btn-name': 'cancel',
|
||||
}],
|
||||
// Set options for dialog
|
||||
options: {
|
||||
title: title,
|
||||
//disable both padding and overflow control.
|
||||
padding: !1,
|
||||
overflow: !1,
|
||||
model: 0,
|
||||
resizable: true,
|
||||
maximizable: true,
|
||||
pinnable: false,
|
||||
closableByDimmer: false,
|
||||
modal: false,
|
||||
},
|
||||
};
|
||||
},
|
||||
hooks: {
|
||||
// triggered when the dialog is closed
|
||||
onclose: function() {
|
||||
if (this.view) {
|
||||
this.view.remove({
|
||||
data: true,
|
||||
internal: true,
|
||||
silent: true,
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
settings: {
|
||||
pg_node: null,
|
||||
pg_item: null,
|
||||
pg_item_data: null,
|
||||
},
|
||||
prepare: function() {
|
||||
|
||||
var self = this;
|
||||
// Disable Backup button until user provides Filename
|
||||
this.__internal.buttons[2].element.disabled = true;
|
||||
var $container = $('<div class=\'restore_dialog\'></div>');
|
||||
var t = pgBrowser.tree,
|
||||
i = t.selected(),
|
||||
d = i && i.length == 1 ? t.itemData(i) : undefined,
|
||||
node = d && pgBrowser.Nodes[d._type];
|
||||
|
||||
if (!d)
|
||||
return;
|
||||
|
||||
var treeInfo = node.getTreeNodeHierarchy.apply(node, [i]);
|
||||
|
||||
var newModel = new RestoreObjectModel({
|
||||
node_data: node,
|
||||
}, {
|
||||
node_info: treeInfo,
|
||||
}),
|
||||
fields = Backform.generateViewSchema(
|
||||
treeInfo, newModel, 'create', node, treeInfo.server, true
|
||||
);
|
||||
|
||||
var view = this.view = new Backform.Dialog({
|
||||
el: $container,
|
||||
model: newModel,
|
||||
schema: fields,
|
||||
});
|
||||
|
||||
$(this.elements.body.childNodes[0]).addClass(
|
||||
'alertify_tools_dialog_properties obj_properties'
|
||||
);
|
||||
|
||||
view.render();
|
||||
|
||||
this.elements.content.appendChild($container.get(0));
|
||||
|
||||
view.$el.attr('tabindex', -1);
|
||||
// var dialogTabNavigator = pgBrowser.keyboardNavigation.getDialogTabNavigator(view);
|
||||
pgBrowser.keyboardNavigation.getDialogTabNavigator(view);
|
||||
var container = view.$el.find('.tab-content:first > .tab-pane.active:first');
|
||||
commonUtils.findAndSetFocus(container);
|
||||
|
||||
// Listen to model & if filename is provided then enable Backup button
|
||||
this.view.model.on('change', function() {
|
||||
if (!_.isUndefined(this.get('file')) && this.get('file') !== '') {
|
||||
this.errorModel.clear();
|
||||
self.__internal.buttons[2].element.disabled = false;
|
||||
} else {
|
||||
self.__internal.buttons[2].element.disabled = true;
|
||||
this.errorModel.set('file', gettext('Please provide filename'));
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
// Callback functions when click on the buttons of the Alertify dialogs
|
||||
callback: function(e) {
|
||||
// Fetch current server id
|
||||
var t = pgBrowser.tree,
|
||||
i = this.settings['pg_item'] || t.selected(),
|
||||
d = this.settings['pg_item_data'] || (
|
||||
i && i.length == 1 ? t.itemData(i) : undefined
|
||||
),
|
||||
node = this.settings['pg_node'] || (
|
||||
d && pgBrowser.Nodes[d._type]
|
||||
);
|
||||
|
||||
if (e.button.element.name == 'dialog_help' || e.button.element.name == 'object_help') {
|
||||
e.cancel = true;
|
||||
pgBrowser.showHelp(e.button.element.name, e.button.element.getAttribute('url'),
|
||||
node, i, e.button.element.getAttribute('label'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.button['data-btn-name'] === 'restore') {
|
||||
if (!d)
|
||||
return;
|
||||
|
||||
var info = node.getTreeNodeHierarchy.apply(node, [i]),
|
||||
m = this.view.model;
|
||||
// Set current node info into model
|
||||
m.set('database', info.database._label);
|
||||
if (!m.get('custom')) {
|
||||
switch (d._type) {
|
||||
case 'schema':
|
||||
m.set('schemas', [d._label]);
|
||||
break;
|
||||
case 'table':
|
||||
m.set('schemas', [info.schema._label]);
|
||||
m.set('tables', [d._label]);
|
||||
break;
|
||||
case 'function':
|
||||
m.set('schemas', [info.schema._label]);
|
||||
m.set('functions', [d._label]);
|
||||
break;
|
||||
case 'index':
|
||||
m.set('schemas', [info.schema._label]);
|
||||
m.set('indexes', [d._label]);
|
||||
break;
|
||||
case 'trigger':
|
||||
m.set('schemas', [info.schema._label]);
|
||||
m.set('triggers', [d._label]);
|
||||
break;
|
||||
case 'trigger_func':
|
||||
m.set('schemas', [info.schema._label]);
|
||||
m.set('trigger_funcs', [d._label]);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// TODO::
|
||||
// When we will implement the object selection in the
|
||||
// import dialog, we will need to select the objects from
|
||||
// the tree selection tab.
|
||||
}
|
||||
|
||||
var self = this,
|
||||
baseUrl = url_for('restore.create_job', {
|
||||
'sid': info.server._id,
|
||||
}),
|
||||
args = this.view.model.toJSON();
|
||||
|
||||
$.ajax({
|
||||
url: baseUrl,
|
||||
method: 'POST',
|
||||
data: {
|
||||
'data': JSON.stringify(args),
|
||||
},
|
||||
success: function(res) {
|
||||
if (res.success) {
|
||||
alertify.success(
|
||||
gettext('Restore job created.'), 5
|
||||
);
|
||||
pgBrowser.Events.trigger('pgadmin-bgprocess:created', self);
|
||||
} else {
|
||||
console.warn(res);
|
||||
}
|
||||
},
|
||||
error: function(xhr) {
|
||||
try {
|
||||
var err = JSON.parse(xhr.responseText);
|
||||
alertify.alert(
|
||||
gettext('Restore failed.'),
|
||||
err.errormsg
|
||||
);
|
||||
} catch (e) {
|
||||
console.warn(e.stack || e);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
alertify.pg_restore(title, item, data, node).resizeTo('65%', '60%');
|
||||
let dialog = new restoreDialog.RestoreDialog(
|
||||
pgBrowser, $, alertify, RestoreObjectModel
|
||||
);
|
||||
dialog.draw(action, treeItem);
|
||||
},
|
||||
};
|
||||
return pgBrowser.Restore;
|
||||
|
322
web/pgadmin/tools/restore/static/js/restore.js.rej
Normal file
322
web/pgadmin/tools/restore/static/js/restore.js.rej
Normal file
@ -0,0 +1,322 @@
|
||||
diff a/web/pgadmin/tools/restore/static/js/restore.js b/web/pgadmin/tools/restore/static/js/restore.js (rejected hunks)
|
||||
@@ -391,318 +344,8 @@ commonUtils
|
||||
},
|
||||
// Callback to draw Backup Dialog for objects
|
||||
restore_objects: function(action, treeItem) {
|
||||
-
|
||||
- var i = treeItem || pgBrowser.tree.selected(),
|
||||
- server_data = null;
|
||||
-
|
||||
- while (i) {
|
||||
- var node_data = pgBrowser.tree.itemData(i);
|
||||
- if (node_data._type == 'server') {
|
||||
- server_data = node_data;
|
||||
- break;
|
||||
- }
|
||||
-
|
||||
- if (pgBrowser.tree.hasParent(i)) {
|
||||
- i = $(pgBrowser.tree.parent(i));
|
||||
- } else {
|
||||
- alertify.alert(
|
||||
- gettext('Restore Error'),
|
||||
- gettext('Please select server or child node from tree.')
|
||||
- );
|
||||
- break;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- if (!server_data) {
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
- var module = 'paths',
|
||||
- preference_name = 'pg_bin_dir',
|
||||
- msg = gettext('Please configure the PostgreSQL Binary Path in the Preferences dialog.');
|
||||
-
|
||||
- if ((server_data.type && server_data.type == 'ppas') ||
|
||||
- server_data.server_type == 'ppas') {
|
||||
- preference_name = 'ppas_bin_dir';
|
||||
- msg = gettext('Please configure the EDB Advanced Server Binary Path in the Preferences dialog.');
|
||||
- }
|
||||
-
|
||||
- var preference = pgBrowser.get_preference(module, preference_name);
|
||||
-
|
||||
- if (preference) {
|
||||
- if (!preference.value) {
|
||||
- alertify.alert(gettext('Configuration required'), msg);
|
||||
- return;
|
||||
- }
|
||||
- } else {
|
||||
- alertify.alert(
|
||||
- gettext('Restore Error'),
|
||||
- S(gettext('Failed to load preference %s of module %s')).sprintf(preference_name, module).value()
|
||||
- );
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
- var title = S(gettext('Restore (%s: %s)')),
|
||||
- tree = pgBrowser.tree,
|
||||
- item = treeItem || tree.selected(),
|
||||
- data = item && item.length == 1 && tree.itemData(item),
|
||||
- node = data && data._type && pgBrowser.Nodes[data._type];
|
||||
-
|
||||
- if (!node)
|
||||
- return;
|
||||
-
|
||||
- var treeInfo = node.getTreeNodeHierarchy.apply(node, [item]);
|
||||
-
|
||||
- if (treeInfo.database._label.indexOf('=') >= 0) {
|
||||
- alertify.alert(
|
||||
- gettext('Restore error'),
|
||||
- gettext('Restore job creation failed. '+
|
||||
- 'Databases with = symbols in the name cannot be restored using this utility.')
|
||||
- );
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
- title = title.sprintf(node.label, data.label).value();
|
||||
-
|
||||
- if (!alertify.pg_restore) {
|
||||
- // Create Dialog title on the fly with node details
|
||||
- alertify.dialog('pg_restore', function factory() {
|
||||
- return {
|
||||
- main: function(title, item, data, node) {
|
||||
- this.set('title', title);
|
||||
- this.setting('pg_node', node);
|
||||
- this.setting('pg_item', item);
|
||||
- this.setting('pg_item_data', data);
|
||||
- },
|
||||
- build: function() {
|
||||
- alertify.pgDialogBuild.apply(this);
|
||||
- },
|
||||
- setup: function() {
|
||||
- return {
|
||||
- buttons: [{
|
||||
- text: '',
|
||||
- className: 'btn btn-default pull-left fa fa-lg fa-info',
|
||||
- attrs: {
|
||||
- name: 'object_help',
|
||||
- type: 'button',
|
||||
- url: 'backup.html',
|
||||
- label: gettext('Restore'),
|
||||
- },
|
||||
- }, {
|
||||
- text: '',
|
||||
- key: 112,
|
||||
- className: 'btn btn-default pull-left fa fa-lg fa-question',
|
||||
- attrs: {
|
||||
- name: 'dialog_help',
|
||||
- type: 'button',
|
||||
- label: gettext('Restore'),
|
||||
- url: url_for('help.static', {
|
||||
- 'filename': 'restore_dialog.html',
|
||||
- }),
|
||||
- },
|
||||
- }, {
|
||||
- text: gettext('Restore'),
|
||||
- key: 13,
|
||||
- className: 'btn btn-primary fa fa-upload pg-alertify-button',
|
||||
- restore: true,
|
||||
- 'data-btn-name': 'restore',
|
||||
- }, {
|
||||
- text: gettext('Cancel'),
|
||||
- key: 27,
|
||||
- className: 'btn btn-danger fa fa-lg fa-times pg-alertify-button',
|
||||
- restore: false,
|
||||
- 'data-btn-name': 'cancel',
|
||||
- }],
|
||||
- // Set options for dialog
|
||||
- options: {
|
||||
- title: title,
|
||||
- //disable both padding and overflow control.
|
||||
- padding: !1,
|
||||
- overflow: !1,
|
||||
- model: 0,
|
||||
- resizable: true,
|
||||
- maximizable: true,
|
||||
- pinnable: false,
|
||||
- closableByDimmer: false,
|
||||
- modal: false,
|
||||
- },
|
||||
- };
|
||||
- },
|
||||
- hooks: {
|
||||
- // triggered when the dialog is closed
|
||||
- onclose: function() {
|
||||
- if (this.view) {
|
||||
- this.view.remove({
|
||||
- data: true,
|
||||
- internal: true,
|
||||
- silent: true,
|
||||
- });
|
||||
- }
|
||||
- },
|
||||
- },
|
||||
- settings: {
|
||||
- pg_node: null,
|
||||
- pg_item: null,
|
||||
- pg_item_data: null,
|
||||
- },
|
||||
- prepare: function() {
|
||||
-
|
||||
- var self = this;
|
||||
- // Disable Backup button until user provides Filename
|
||||
- this.__internal.buttons[2].element.disabled = true;
|
||||
- var $container = $('<div class=\'restore_dialog\'></div>');
|
||||
- var t = pgBrowser.tree,
|
||||
- i = t.selected(),
|
||||
- d = i && i.length == 1 ? t.itemData(i) : undefined,
|
||||
- node = d && pgBrowser.Nodes[d._type];
|
||||
-
|
||||
- if (!d)
|
||||
- return;
|
||||
-
|
||||
- var treeInfo = node.getTreeNodeHierarchy.apply(node, [i]);
|
||||
-
|
||||
- var newModel = new RestoreObjectModel({
|
||||
- node_data: node,
|
||||
- }, {
|
||||
- node_info: treeInfo,
|
||||
- }),
|
||||
- fields = Backform.generateViewSchema(
|
||||
- treeInfo, newModel, 'create', node, treeInfo.server, true
|
||||
- );
|
||||
-
|
||||
- var view = this.view = new Backform.Dialog({
|
||||
- el: $container,
|
||||
- model: newModel,
|
||||
- schema: fields,
|
||||
- });
|
||||
-
|
||||
- $(this.elements.body.childNodes[0]).addClass(
|
||||
- 'alertify_tools_dialog_properties obj_properties'
|
||||
- );
|
||||
-
|
||||
- view.render();
|
||||
-
|
||||
- this.elements.content.appendChild($container.get(0));
|
||||
-
|
||||
- view.$el.attr('tabindex', -1);
|
||||
- // var dialogTabNavigator = pgBrowser.keyboardNavigation.getDialogTabNavigator(view);
|
||||
- pgBrowser.keyboardNavigation.getDialogTabNavigator(view);
|
||||
- var container = view.$el.find('.tab-content:first > .tab-pane.active:first');
|
||||
- commonUtils.findAndSetFocus(container);
|
||||
-
|
||||
- // Listen to model & if filename is provided then enable Backup button
|
||||
- this.view.model.on('change', function() {
|
||||
- if (!_.isUndefined(this.get('file')) && this.get('file') !== '') {
|
||||
- this.errorModel.clear();
|
||||
- self.__internal.buttons[2].element.disabled = false;
|
||||
- } else {
|
||||
- self.__internal.buttons[2].element.disabled = true;
|
||||
- this.errorModel.set('file', gettext('Please provide filename'));
|
||||
- }
|
||||
- });
|
||||
-
|
||||
- },
|
||||
- // Callback functions when click on the buttons of the Alertify dialogs
|
||||
- callback: function(e) {
|
||||
- // Fetch current server id
|
||||
- var t = pgBrowser.tree,
|
||||
- i = this.settings['pg_item'] || t.selected(),
|
||||
- d = this.settings['pg_item_data'] || (
|
||||
- i && i.length == 1 ? t.itemData(i) : undefined
|
||||
- ),
|
||||
- node = this.settings['pg_node'] || (
|
||||
- d && pgBrowser.Nodes[d._type]
|
||||
- );
|
||||
-
|
||||
- if (e.button.element.name == 'dialog_help' || e.button.element.name == 'object_help') {
|
||||
- e.cancel = true;
|
||||
- pgBrowser.showHelp(e.button.element.name, e.button.element.getAttribute('url'),
|
||||
- node, i, e.button.element.getAttribute('label'));
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
- if (e.button['data-btn-name'] === 'restore') {
|
||||
- if (!d)
|
||||
- return;
|
||||
-
|
||||
- var info = node.getTreeNodeHierarchy.apply(node, [i]),
|
||||
- m = this.view.model;
|
||||
- // Set current node info into model
|
||||
- m.set('database', info.database._label);
|
||||
- if (!m.get('custom')) {
|
||||
- switch (d._type) {
|
||||
- case 'schema':
|
||||
- m.set('schemas', [d._label]);
|
||||
- break;
|
||||
- case 'table':
|
||||
- m.set('schemas', [info.schema._label]);
|
||||
- m.set('tables', [d._label]);
|
||||
- break;
|
||||
- case 'function':
|
||||
- m.set('schemas', [info.schema._label]);
|
||||
- m.set('functions', [d._label]);
|
||||
- break;
|
||||
- case 'index':
|
||||
- m.set('schemas', [info.schema._label]);
|
||||
- m.set('indexes', [d._label]);
|
||||
- break;
|
||||
- case 'trigger':
|
||||
- m.set('schemas', [info.schema._label]);
|
||||
- m.set('triggers', [d._label]);
|
||||
- break;
|
||||
- case 'trigger_func':
|
||||
- m.set('schemas', [info.schema._label]);
|
||||
- m.set('trigger_funcs', [d._label]);
|
||||
- break;
|
||||
- }
|
||||
- } else {
|
||||
- // TODO::
|
||||
- // When we will implement the object selection in the
|
||||
- // import dialog, we will need to select the objects from
|
||||
- // the tree selection tab.
|
||||
- }
|
||||
-
|
||||
- var self = this,
|
||||
- baseUrl = url_for('restore.create_job', {
|
||||
- 'sid': info.server._id,
|
||||
- }),
|
||||
- args = this.view.model.toJSON();
|
||||
-
|
||||
- $.ajax({
|
||||
- url: baseUrl,
|
||||
- method: 'POST',
|
||||
- data: {
|
||||
- 'data': JSON.stringify(args),
|
||||
- },
|
||||
- success: function(res) {
|
||||
- if (res.success) {
|
||||
- alertify.success(
|
||||
- gettext('Restore job created.'), 5
|
||||
- );
|
||||
- pgBrowser.Events.trigger('pgadmin-bgprocess:created', self);
|
||||
- } else {
|
||||
- console.warn(res);
|
||||
- }
|
||||
- },
|
||||
- error: function(xhr) {
|
||||
- try {
|
||||
- var err = $.parseJSON(xhr.responseText);
|
||||
- alertify.alert(
|
||||
- gettext('Restore failed.'),
|
||||
- err.errormsg
|
||||
- );
|
||||
- } catch (e) {
|
||||
- console.warn(e.stack || e);
|
||||
- }
|
||||
- },
|
||||
- });
|
||||
- }
|
||||
- },
|
||||
- };
|
||||
- });
|
||||
- }
|
||||
-
|
||||
- alertify.pg_restore(title, item, data, node).resizeTo('65%', '60%');
|
||||
+ let dialog = new restoreDialog.RestoreDialog(pgBrowser, $, alertify, RestoreObjectModel);
|
||||
+ dialog.draw(action, treeItem);
|
||||
},
|
||||
};
|
||||
return pgBrowser.Restore;
|
57
web/pgadmin/tools/restore/static/js/restore_dialog.js
Normal file
57
web/pgadmin/tools/restore/static/js/restore_dialog.js
Normal file
@ -0,0 +1,57 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import gettext from '../../../../static/js/gettext';
|
||||
import {sprintf} from 'sprintf-js';
|
||||
import Backform from '../../../../static/js/backform.pgadmin';
|
||||
import {Dialog} from '../../../../static/js/alertify/dialog';
|
||||
|
||||
export class RestoreDialog extends Dialog {
|
||||
constructor(pgBrowser, $, alertify, RestoreModel, backform = Backform) {
|
||||
super('Restore Error',
|
||||
'<div class=\'restore_dialog\'></div>',
|
||||
pgBrowser, $, alertify, RestoreModel, backform);
|
||||
}
|
||||
|
||||
draw(action, aciTreeItem) {
|
||||
|
||||
const serverInformation = this.retrieveAncestorOfTypeServer(aciTreeItem);
|
||||
|
||||
if (!serverInformation) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.hasBinariesConfiguration(serverInformation)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.canExecuteOnCurrentDatabase(aciTreeItem)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let aciTreeItem1 = aciTreeItem || this.pgBrowser.treeMenu.selected();
|
||||
let item = this.pgBrowser.treeMenu.findNodeByDomElement(aciTreeItem1);
|
||||
const data = item.getData();
|
||||
const node = this.pgBrowser.Nodes[data._type];
|
||||
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
let title = sprintf(gettext('Restore (%s: %s)'), node.label, data.label);
|
||||
|
||||
this.createOrGetDialog(title, 'restore');
|
||||
|
||||
this.alertify.pg_restore(title, aciTreeItem1, data, node).resizeTo('65%', '60%');
|
||||
}
|
||||
|
||||
dialogName() {
|
||||
return 'pg_restore';
|
||||
}
|
||||
}
|
||||
|
255
web/pgadmin/tools/restore/static/js/restore_dialog_wrapper.js
Normal file
255
web/pgadmin/tools/restore/static/js/restore_dialog_wrapper.js
Normal file
@ -0,0 +1,255 @@
|
||||
import {getTreeNodeHierarchyFromElement} from '../../../../static/js/tree/pgadmin_tree_node';
|
||||
import axios from 'axios/index';
|
||||
import _ from 'underscore';
|
||||
import gettext from '../../../../static/js/gettext';
|
||||
import url_for from '../../../../static/js/url_for';
|
||||
import {DialogWrapper} from '../../../../static/js/alertify/dialog_wrapper';
|
||||
|
||||
export class RestoreDialogWrapper extends DialogWrapper {
|
||||
constructor(dialogContainerSelector, dialogTitle, typeOfDialog,
|
||||
jquery, pgBrowser, alertify, dialogModel, backform) {
|
||||
super(dialogContainerSelector, dialogTitle, jquery,
|
||||
pgBrowser, alertify, dialogModel, backform);
|
||||
}
|
||||
|
||||
main(title, item, data, node) {
|
||||
this.set('title', title);
|
||||
this.setting('pg_node', node);
|
||||
this.setting('pg_item', item);
|
||||
this.setting('pg_item_data', data);
|
||||
}
|
||||
|
||||
setup() {
|
||||
return {
|
||||
buttons: [{
|
||||
text: '',
|
||||
className: 'btn btn-default pull-left fa fa-lg fa-info',
|
||||
attrs: {
|
||||
name: 'object_help',
|
||||
type: 'button',
|
||||
url: 'backup.html',
|
||||
label: gettext('Restore'),
|
||||
},
|
||||
}, {
|
||||
text: '',
|
||||
key: 112,
|
||||
className: 'btn btn-default pull-left fa fa-lg fa-question',
|
||||
attrs: {
|
||||
name: 'dialog_help',
|
||||
type: 'button',
|
||||
label: gettext('Restore'),
|
||||
url: url_for('help.static', {
|
||||
'filename': 'restore_dialog.html',
|
||||
}),
|
||||
},
|
||||
}, {
|
||||
text: gettext('Restore'),
|
||||
key: 13,
|
||||
className: 'btn btn-primary fa fa-upload pg-alertify-button',
|
||||
restore: true,
|
||||
'data-btn-name': 'restore',
|
||||
}, {
|
||||
text: gettext('Cancel'),
|
||||
key: 27,
|
||||
className: 'btn btn-danger fa fa-lg fa-times pg-alertify-button',
|
||||
restore: false,
|
||||
'data-btn-name': 'cancel',
|
||||
}],
|
||||
// Set options for dialog
|
||||
options: {
|
||||
title: this.dialogTitle,
|
||||
//disable both padding and overflow control.
|
||||
padding: !1,
|
||||
overflow: !1,
|
||||
model: 0,
|
||||
resizable: true,
|
||||
maximizable: true,
|
||||
pinnable: false,
|
||||
closableByDimmer: false,
|
||||
modal: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
prepare() {
|
||||
this.disableRestoreButton();
|
||||
|
||||
const $container = this.jquery(this.dialogContainerSelector);
|
||||
const selectedTreeNode = this.getSelectedNode();
|
||||
const selectedTreeNodeData = this.getSelectedNodeData(selectedTreeNode);
|
||||
if (!selectedTreeNodeData) {
|
||||
return;
|
||||
}
|
||||
|
||||
const node = this.pgBrowser.Nodes[selectedTreeNodeData._type];
|
||||
|
||||
const treeInfo = getTreeNodeHierarchyFromElement(this.pgBrowser, selectedTreeNode);
|
||||
const dialog = this.createDialog(node, treeInfo, $container);
|
||||
this.addAlertifyClassToRestoreNodeChildNodes();
|
||||
dialog.render();
|
||||
|
||||
this.elements.content.appendChild($container.get(0));
|
||||
|
||||
this.focusOnDialog(dialog);
|
||||
this.setListenersForFilenameChanges();
|
||||
}
|
||||
|
||||
callback(event) {
|
||||
const selectedTreeNode = this.getSelectedNode();
|
||||
const selectedTreeNodeData = this.getSelectedNodeData(selectedTreeNode);
|
||||
const node = selectedTreeNodeData && this.pgBrowser.Nodes[selectedTreeNodeData._type];
|
||||
|
||||
if (this.wasHelpButtonPressed(event)) {
|
||||
event.cancel = true;
|
||||
this.pgBrowser.showHelp(
|
||||
event.button.element.name,
|
||||
event.button.element.getAttribute('url'),
|
||||
node,
|
||||
selectedTreeNode,
|
||||
event.button.element.getAttribute('label')
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.wasRestoreButtonPressed(event)) {
|
||||
|
||||
if (!selectedTreeNodeData)
|
||||
return;
|
||||
|
||||
const serverIdentifier = this.retrieveServerIdentifier(node, selectedTreeNode);
|
||||
|
||||
const dialogWrapper = this;
|
||||
let urlShortcut = 'restore.create_job';
|
||||
|
||||
const baseUrl = url_for(urlShortcut, {
|
||||
'sid': serverIdentifier,
|
||||
});
|
||||
|
||||
const treeInfo = getTreeNodeHierarchyFromElement(
|
||||
this.pgBrowser,
|
||||
selectedTreeNode
|
||||
);
|
||||
|
||||
this.setExtraParameters(selectedTreeNode, treeInfo);
|
||||
|
||||
let service = axios.create({});
|
||||
service.post(
|
||||
baseUrl,
|
||||
this.view.model.toJSON()
|
||||
).then(function () {
|
||||
dialogWrapper.alertify.success(gettext('Restore job created.'), 5);
|
||||
dialogWrapper.pgBrowser.Events.trigger('pgadmin-bgprocess:created', dialogWrapper);
|
||||
}).catch(function (error) {
|
||||
try {
|
||||
const err = error.response.data;
|
||||
dialogWrapper.alertify.alert(
|
||||
gettext('Restore job failed.'),
|
||||
err.errormsg
|
||||
);
|
||||
} catch (e) {
|
||||
console.warn(e.stack || e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
addAlertifyClassToRestoreNodeChildNodes() {
|
||||
this.jquery(this.elements.body.childNodes[0]).addClass(
|
||||
'alertify_tools_dialog_properties obj_properties'
|
||||
);
|
||||
}
|
||||
|
||||
getSelectedNode() {
|
||||
const tree = this.pgBrowser.treeMenu;
|
||||
const selectedNode = tree.selected();
|
||||
if (selectedNode) {
|
||||
return tree.findNodeByDomElement(selectedNode);
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
disableRestoreButton() {
|
||||
this.__internal.buttons[2].element.disabled = true;
|
||||
}
|
||||
|
||||
enableRestoreButton() {
|
||||
this.__internal.buttons[2].element.disabled = false;
|
||||
}
|
||||
|
||||
createDialog(node, treeInfo, $container) {
|
||||
const newModel = new this.dialogModel({
|
||||
node_data: node,
|
||||
}, {
|
||||
node_info: treeInfo,
|
||||
});
|
||||
const fields = this.backform.generateViewSchema(
|
||||
treeInfo, newModel, 'create', node, treeInfo.server, true
|
||||
);
|
||||
|
||||
return this.view = new this.backform.Dialog({
|
||||
el: $container,
|
||||
model: newModel,
|
||||
schema: fields,
|
||||
});
|
||||
}
|
||||
|
||||
retrieveServerIdentifier(node, selectedTreeNode) {
|
||||
const treeInfo = getTreeNodeHierarchyFromElement(
|
||||
this.pgBrowser,
|
||||
selectedTreeNode
|
||||
);
|
||||
return treeInfo.server._id;
|
||||
}
|
||||
|
||||
setListenersForFilenameChanges() {
|
||||
const self = this;
|
||||
|
||||
this.view.model.on('change', function () {
|
||||
if (!_.isUndefined(this.get('file')) && this.get('file') !== '') {
|
||||
this.errorModel.clear();
|
||||
self.enableRestoreButton();
|
||||
} else {
|
||||
self.disableRestoreButton();
|
||||
this.errorModel.set('file', gettext('Please provide a filename'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
setExtraParameters(selectedTreeNode, treeInfo) {
|
||||
this.view.model.set('database', treeInfo.database._label);
|
||||
if (!this.view.model.get('custom')) {
|
||||
const nodeData = selectedTreeNode.getData();
|
||||
|
||||
switch (nodeData._type) {
|
||||
case 'schema':
|
||||
this.view.model.set('schemas', [nodeData._label]);
|
||||
break;
|
||||
case 'table':
|
||||
this.view.model.set('schemas', [treeInfo.schema._label]);
|
||||
this.view.model.set('tables', [nodeData._label]);
|
||||
break;
|
||||
case 'function':
|
||||
this.view.model.set('schemas', [treeInfo.schema._label]);
|
||||
this.view.model.set('functions', [nodeData._label]);
|
||||
break;
|
||||
case 'index':
|
||||
this.view.model.set('schemas', [treeInfo.schema._label]);
|
||||
this.view.model.set('indexes', [nodeData._label]);
|
||||
break;
|
||||
case 'trigger':
|
||||
this.view.model.set('schemas', [treeInfo.schema._label]);
|
||||
this.view.model.set('triggers', [nodeData._label]);
|
||||
break;
|
||||
case 'trigger_func':
|
||||
this.view.model.set('schemas', [treeInfo.schema._label]);
|
||||
this.view.model.set('trigger_funcs', [nodeData._label]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wasRestoreButtonPressed(event) {
|
||||
return event.button['data-btn-name'] === 'restore';
|
||||
}
|
||||
}
|
205
web/regression/javascript/backup/backup_dialog_spec.js
Normal file
205
web/regression/javascript/backup/backup_dialog_spec.js
Normal file
@ -0,0 +1,205 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
import {BackupDialog} from '../../../pgadmin/tools/backup/static/js/backup_dialog';
|
||||
import {TreeFake} from '../tree/tree_fake';
|
||||
|
||||
const context = describe;
|
||||
|
||||
describe('BackupDialog', () => {
|
||||
let backupDialog;
|
||||
let pgBrowser;
|
||||
let jquerySpy;
|
||||
let alertifySpy;
|
||||
let backupModelSpy;
|
||||
|
||||
beforeEach(() => {
|
||||
pgBrowser = {
|
||||
treeMenu: new TreeFake(),
|
||||
Nodes: {
|
||||
server: {
|
||||
hasId: true,
|
||||
label: 'server',
|
||||
getTreeNodeHierarchy: jasmine.createSpy('server.getTreeNodeHierarchy'),
|
||||
},
|
||||
database: {
|
||||
hasId: true,
|
||||
label: 'database',
|
||||
getTreeNodeHierarchy: jasmine.createSpy('db.getTreeNodeHierarchy'),
|
||||
},
|
||||
schema: {
|
||||
hasId: true,
|
||||
label: 'schema',
|
||||
getTreeNodeHierarchy: jasmine.createSpy('db.getTreeNodeHierarchy'),
|
||||
},
|
||||
},
|
||||
};
|
||||
pgBrowser.Nodes.server.hasId = true;
|
||||
pgBrowser.Nodes.database.hasId = true;
|
||||
jquerySpy = jasmine.createSpy('jquerySpy');
|
||||
backupModelSpy = jasmine.createSpy('backupModelSpy');
|
||||
|
||||
const hierarchy = {
|
||||
children: [
|
||||
{
|
||||
id: 'root',
|
||||
children: [
|
||||
{
|
||||
id: 'serverTreeNode',
|
||||
data: {
|
||||
_id: 10,
|
||||
_type: 'server',
|
||||
},
|
||||
children: [
|
||||
{
|
||||
id: 'some_database',
|
||||
data: {
|
||||
_type: 'database',
|
||||
_id: 11,
|
||||
label: 'some_database',
|
||||
_label: 'some_database_label',
|
||||
},
|
||||
}, {
|
||||
id: 'database_with_equal_in_name',
|
||||
data: {
|
||||
_type: 'database',
|
||||
label: 'some_database',
|
||||
_label: '=some_database_label',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'ppasServer',
|
||||
data: {
|
||||
_type: 'server',
|
||||
server_type: 'ppas',
|
||||
children: [
|
||||
{id: 'someNodeUnderneathPPASServer'},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
pgBrowser.treeMenu = TreeFake.build(hierarchy);
|
||||
});
|
||||
|
||||
describe('#draw', () => {
|
||||
beforeEach(() => {
|
||||
alertifySpy = jasmine.createSpyObj('alertify', ['alert', 'dialog']);
|
||||
alertifySpy['backup_objects'] = jasmine.createSpy('backup_objects');
|
||||
backupDialog = new BackupDialog(
|
||||
pgBrowser,
|
||||
jquerySpy,
|
||||
alertifySpy,
|
||||
backupModelSpy
|
||||
);
|
||||
|
||||
pgBrowser.get_preference = jasmine.createSpy('get_preferences');
|
||||
});
|
||||
|
||||
context('there are no ancestors of the type server', () => {
|
||||
it('does not create a dialog', () => {
|
||||
pgBrowser.treeMenu.selectNode([{id: 'root'}]);
|
||||
backupDialog.draw(null, null, null);
|
||||
expect(alertifySpy['backup_objects']).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('display an alert with a Backup Error', () => {
|
||||
backupDialog.draw(null, [{id: 'root'}], null);
|
||||
expect(alertifySpy.alert).toHaveBeenCalledWith(
|
||||
'Backup Error',
|
||||
'Please select server or child node from the browser tree.'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
context('there is an ancestor of the type server', () => {
|
||||
context('no preference can be found', () => {
|
||||
beforeEach(() => {
|
||||
pgBrowser.get_preference.and.returnValue(undefined);
|
||||
});
|
||||
|
||||
context('server is a ppas server', () => {
|
||||
it('display an alert with "Backup Error"', () => {
|
||||
backupDialog.draw(null, [{id: 'some_database'}], null);
|
||||
expect(alertifySpy.alert).toHaveBeenCalledWith(
|
||||
'Backup Error',
|
||||
'Failed to load preference pg_bin_dir of module paths'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
context('server is not a ppas server', () => {
|
||||
it('display an alert with "Backup Error"', () => {
|
||||
backupDialog.draw(null, [{id: 'ppasServer'}], null);
|
||||
expect(alertifySpy.alert).toHaveBeenCalledWith(
|
||||
'Backup Error',
|
||||
'Failed to load preference ppas_bin_dir of module paths'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('preference can be found', () => {
|
||||
context('binary folder is not configured', () => {
|
||||
beforeEach(() => {
|
||||
pgBrowser.get_preference.and.returnValue({});
|
||||
});
|
||||
|
||||
context('server is a ppas server', () => {
|
||||
it('display an alert with "Configuration required"', () => {
|
||||
backupDialog.draw(null, [{id: 'serverTreeNode'}], null);
|
||||
expect(alertifySpy.alert).toHaveBeenCalledWith(
|
||||
'Configuration required',
|
||||
'Please configure the PostgreSQL Binary Path in the Preferences dialog.'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
context('server is not a ppas server', () => {
|
||||
it('display an alert with "Configuration required"', () => {
|
||||
backupDialog.draw(null, [{id: 'ppasServer'}], null);
|
||||
expect(alertifySpy.alert).toHaveBeenCalledWith(
|
||||
'Configuration required',
|
||||
'Please configure the EDB Advanced Server Binary Path in the Preferences dialog.'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('binary folder is configured', () => {
|
||||
let backupDialogResizeToSpy;
|
||||
beforeEach(() => {
|
||||
backupDialogResizeToSpy = jasmine.createSpyObj('backupDialogResizeToSpy', ['resizeTo']);
|
||||
alertifySpy['backup_objects'].and
|
||||
.returnValue(backupDialogResizeToSpy);
|
||||
pgBrowser.get_preference.and.returnValue({value: '/some/path'});
|
||||
});
|
||||
|
||||
it('displays the dialog', () => {
|
||||
backupDialog.draw(null, [{id: 'serverTreeNode'}], null);
|
||||
expect(alertifySpy['backup_objects']).toHaveBeenCalledWith(true);
|
||||
expect(backupDialogResizeToSpy.resizeTo).toHaveBeenCalledWith('60%', '50%');
|
||||
});
|
||||
|
||||
context('database label contain "="', () => {
|
||||
it('should create alert dialog with backup error', () => {
|
||||
backupDialog.draw(null, [{id: 'database_with_equal_in_name'}], null);
|
||||
expect(alertifySpy.alert).toHaveBeenCalledWith('Backup Error',
|
||||
'Databases with = symbols in the name cannot be backed up or restored using this utility.');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
675
web/regression/javascript/backup/backup_dialog_wrapper_spec.js
Normal file
675
web/regression/javascript/backup/backup_dialog_wrapper_spec.js
Normal file
@ -0,0 +1,675 @@
|
||||
import {TreeFake} from '../tree/tree_fake';
|
||||
import {BackupDialogWrapper} from '../../../pgadmin/tools/backup/static/js/backup_dialog_wrapper';
|
||||
import axios from 'axios/index';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import {FakeModel} from '../fake_model';
|
||||
import {TreeNode} from '../../../pgadmin/static/js/tree/tree';
|
||||
|
||||
let context = describe;
|
||||
|
||||
describe('BackupDialogWrapper', () => {
|
||||
let jquerySpy;
|
||||
let pgBrowser;
|
||||
let alertifySpy;
|
||||
let dialogModelKlassSpy;
|
||||
let backform;
|
||||
let generatedBackupModel;
|
||||
let backupDialogWrapper;
|
||||
let noDataNode;
|
||||
let serverTreeNode;
|
||||
let databaseTreeNode;
|
||||
let viewSchema;
|
||||
let backupJQueryContainerSpy;
|
||||
let backupNodeChildNodeSpy;
|
||||
let backupNode;
|
||||
|
||||
beforeEach(() => {
|
||||
pgBrowser = {
|
||||
treeMenu: new TreeFake(),
|
||||
Nodes: {
|
||||
server: {
|
||||
hasId: true,
|
||||
getTreeNodeHierarchy: jasmine.createSpy('getTreeNodeHierarchy'),
|
||||
},
|
||||
database: {
|
||||
hasId: true,
|
||||
},
|
||||
},
|
||||
keyboardNavigation: jasmine.createSpyObj('keyboardNavigation', ['getDialogTabNavigator']),
|
||||
};
|
||||
noDataNode = pgBrowser.treeMenu.addNewNode('level1.1', undefined, [{id: 'level1'}]);
|
||||
serverTreeNode = pgBrowser.treeMenu.addNewNode('level2.1', {
|
||||
_type: 'server',
|
||||
_id: 10,
|
||||
label: 'some-tree-label',
|
||||
}, [{id: 'level2.1'}]);
|
||||
databaseTreeNode = new TreeNode('database-tree-node', {
|
||||
_type: 'database',
|
||||
_label: 'some-database-label',
|
||||
}, [{id: 'database-tree-node'}]);
|
||||
pgBrowser.treeMenu.addChild(serverTreeNode, databaseTreeNode);
|
||||
|
||||
jquerySpy = jasmine.createSpy('jquerySpy');
|
||||
backupNode = {
|
||||
__internal: {
|
||||
buttons: [{}, {}, {
|
||||
element: {
|
||||
disabled: false,
|
||||
},
|
||||
}],
|
||||
},
|
||||
elements: {
|
||||
body: {
|
||||
childNodes: [
|
||||
{},
|
||||
],
|
||||
},
|
||||
content: jasmine.createSpyObj('content', ['appendChild', 'attr']),
|
||||
},
|
||||
};
|
||||
|
||||
backupJQueryContainerSpy = jasmine.createSpyObj('backupJQueryContainer', ['get', 'attr']);
|
||||
backupJQueryContainerSpy.get.and.returnValue(backupJQueryContainerSpy);
|
||||
|
||||
generatedBackupModel = {};
|
||||
dialogModelKlassSpy = jasmine.createSpy('dialogModelKlass');
|
||||
dialogModelKlassSpy.and.returnValue(generatedBackupModel);
|
||||
|
||||
viewSchema = {};
|
||||
backform = jasmine.createSpyObj('backform', ['generateViewSchema', 'Dialog']);
|
||||
backform.generateViewSchema.and.returnValue(viewSchema);
|
||||
|
||||
backupNodeChildNodeSpy = jasmine.createSpyObj('something', ['addClass']);
|
||||
jquerySpy.and.callFake((selector) => {
|
||||
if (selector === '<div class=\'backup_dialog\'></div>') {
|
||||
return backupJQueryContainerSpy;
|
||||
} else if (selector === backupNode.elements.body.childNodes[0]) {
|
||||
return backupNodeChildNodeSpy;
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#prepare', () => {
|
||||
beforeEach(() => {
|
||||
alertifySpy = jasmine.createSpyObj('alertify', ['alert', 'dialog']);
|
||||
backupDialogWrapper = new BackupDialogWrapper(
|
||||
'<div class=\'backup_dialog\'></div>',
|
||||
'backupDialogTitle',
|
||||
'backup',
|
||||
jquerySpy,
|
||||
pgBrowser,
|
||||
alertifySpy,
|
||||
dialogModelKlassSpy,
|
||||
backform
|
||||
);
|
||||
backupDialogWrapper = Object.assign(backupDialogWrapper, backupNode);
|
||||
});
|
||||
|
||||
context('no tree element is selected', () => {
|
||||
it('does not create a backform dialog', () => {
|
||||
backupDialogWrapper.prepare();
|
||||
expect(backform.Dialog).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('disables the button "submit button" until a filename is selected', () => {
|
||||
backupDialogWrapper.prepare();
|
||||
expect(backupDialogWrapper.__internal.buttons[2].element.disabled).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
context('selected tree node has no data', () => {
|
||||
beforeEach(() => {
|
||||
pgBrowser.treeMenu.selectNode(noDataNode.domNode);
|
||||
});
|
||||
|
||||
it('does not create a backform dialog', () => {
|
||||
backupDialogWrapper.prepare();
|
||||
expect(backform.Dialog).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('disables the button "submit button" until a filename is selected', () => {
|
||||
backupDialogWrapper.prepare();
|
||||
expect(backupDialogWrapper.__internal.buttons[2].element.disabled).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
context('tree element is selected', () => {
|
||||
let treeHierarchyInformation;
|
||||
let dialogSpy;
|
||||
|
||||
beforeEach(() => {
|
||||
treeHierarchyInformation = {
|
||||
server: {
|
||||
_type: 'server',
|
||||
_id: 10,
|
||||
priority: 0,
|
||||
label: 'some-tree-label',
|
||||
},
|
||||
};
|
||||
pgBrowser.treeMenu.selectNode(serverTreeNode.domNode);
|
||||
pgBrowser.Nodes['server'].getTreeNodeHierarchy.and
|
||||
.returnValue(treeHierarchyInformation);
|
||||
dialogSpy = jasmine.createSpyObj('newView', ['render']);
|
||||
dialogSpy.$el = jasmine.createSpyObj('$el', ['find', 'attr']);
|
||||
dialogSpy.model = jasmine.createSpyObj('model', ['on']);
|
||||
dialogSpy.$el.find.and.returnValue([]);
|
||||
|
||||
backform.Dialog.and.returnValue(dialogSpy);
|
||||
});
|
||||
|
||||
it('creates a backform dialog and displays it', () => {
|
||||
backupDialogWrapper.prepare();
|
||||
expect(backform.Dialog).toHaveBeenCalledWith({
|
||||
el: backupJQueryContainerSpy,
|
||||
model: generatedBackupModel,
|
||||
schema: viewSchema,
|
||||
});
|
||||
|
||||
expect(dialogSpy.render).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
||||
it('add alertify classes to restore node childnode', () => {
|
||||
backupDialogWrapper.prepare();
|
||||
expect(backupNodeChildNodeSpy.addClass)
|
||||
.toHaveBeenCalledWith('alertify_tools_dialog_properties obj_properties');
|
||||
});
|
||||
|
||||
it('disables the button submit button until a filename is selected', () => {
|
||||
backupDialogWrapper.prepare();
|
||||
expect(backupNode.__internal.buttons[2].element.disabled).toBe(true);
|
||||
});
|
||||
|
||||
it('generates a new backup model', () => {
|
||||
backupDialogWrapper.prepare();
|
||||
expect(dialogModelKlassSpy).toHaveBeenCalledWith(
|
||||
{type: 'backup'},
|
||||
{node_info: treeHierarchyInformation}
|
||||
);
|
||||
});
|
||||
|
||||
it('add the new dialog to the backup node HTML', () => {
|
||||
backupDialogWrapper.prepare();
|
||||
expect(backupNode.elements.content.appendChild).toHaveBeenCalledWith(backupJQueryContainerSpy);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('onButtonClicked', () => {
|
||||
let networkMock;
|
||||
beforeEach(() => {
|
||||
networkMock = new MockAdapter(axios);
|
||||
backupDialogWrapper = new BackupDialogWrapper(
|
||||
'<div class=\'backup_dialog\'></div>',
|
||||
'backupDialogTitle',
|
||||
'backup',
|
||||
jquerySpy,
|
||||
pgBrowser,
|
||||
alertifySpy,
|
||||
dialogModelKlassSpy,
|
||||
backform
|
||||
);
|
||||
|
||||
backupDialogWrapper = Object.assign(backupDialogWrapper, backupNode);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
networkMock.restore();
|
||||
});
|
||||
|
||||
context('dialog help button was pressed', () => {
|
||||
let networkCalled;
|
||||
beforeEach(() => {
|
||||
networkCalled = false;
|
||||
networkMock.onAny(/.*/).reply(() => {
|
||||
networkCalled = true;
|
||||
return [200, {}];
|
||||
});
|
||||
pgBrowser.treeMenu.selectNode(serverTreeNode.domNode);
|
||||
pgBrowser.showHelp = jasmine.createSpy('showHelp');
|
||||
|
||||
const event = {
|
||||
button: {
|
||||
element: {
|
||||
name: 'dialog_help',
|
||||
getAttribute: (attributeName) => {
|
||||
if (attributeName === 'url') {
|
||||
return 'http://someurl';
|
||||
} else if (attributeName === 'label') {
|
||||
return 'some label';
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
backupDialogWrapper.callback(event);
|
||||
});
|
||||
|
||||
it('displays help for dialog', () => {
|
||||
expect(pgBrowser.showHelp).toHaveBeenCalledWith(
|
||||
'dialog_help',
|
||||
'http://someurl',
|
||||
pgBrowser.Nodes['server'],
|
||||
serverTreeNode,
|
||||
'some label'
|
||||
);
|
||||
});
|
||||
|
||||
it('does not start the backup', () => {
|
||||
expect(networkCalled).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
context('object help button was pressed', () => {
|
||||
let networkCalled;
|
||||
beforeEach(() => {
|
||||
networkCalled = false;
|
||||
networkMock.onAny(/.*/).reply(() => {
|
||||
networkCalled = true;
|
||||
return [200, {}];
|
||||
});
|
||||
pgBrowser.treeMenu.selectNode(serverTreeNode.domNode);
|
||||
pgBrowser.showHelp = jasmine.createSpy('showHelp');
|
||||
|
||||
const event = {
|
||||
button: {
|
||||
element: {
|
||||
name: 'object_help',
|
||||
getAttribute: (attributeName) => {
|
||||
if (attributeName === 'url') {
|
||||
return 'http://someurl';
|
||||
} else if (attributeName === 'label') {
|
||||
return 'some label';
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
backupDialogWrapper.callback(event);
|
||||
});
|
||||
|
||||
it('displays help for dialog', () => {
|
||||
expect(pgBrowser.showHelp).toHaveBeenCalledWith(
|
||||
'object_help',
|
||||
'http://someurl',
|
||||
pgBrowser.Nodes['server'],
|
||||
serverTreeNode,
|
||||
'some label'
|
||||
);
|
||||
});
|
||||
|
||||
it('does not start the backup', () => {
|
||||
expect(networkCalled).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
context('backup button was pressed', () => {
|
||||
context('no tree node is selected', () => {
|
||||
it('does not start the backup', () => {
|
||||
let networkCalled = false;
|
||||
networkMock.onAny(/.*/).reply(() => {
|
||||
networkCalled = true;
|
||||
return [200, {}];
|
||||
});
|
||||
|
||||
let event = {
|
||||
button: {
|
||||
'data-btn-name': 'backup',
|
||||
element: {
|
||||
getAttribute: () => {
|
||||
return 'http://someurl';
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
backupDialogWrapper.callback(event);
|
||||
expect(networkCalled).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
context('tree node has no data', () => {
|
||||
it('does not start the backup', () => {
|
||||
pgBrowser.treeMenu.selectNode(noDataNode.domNode);
|
||||
|
||||
let networkCalled = false;
|
||||
networkMock.onAny(/.*/).reply(() => {
|
||||
networkCalled = true;
|
||||
return [200, {}];
|
||||
});
|
||||
|
||||
let event = {
|
||||
button: {
|
||||
'data-btn-name': 'backup',
|
||||
element: {
|
||||
getAttribute: () => {
|
||||
return 'http://someurl';
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
backupDialogWrapper.callback(event);
|
||||
expect(networkCalled).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
context('tree node has data', () => {
|
||||
context('when dialog type is global', () => {
|
||||
let event;
|
||||
beforeEach(() => {
|
||||
pgBrowser.treeMenu.selectNode(serverTreeNode.domNode);
|
||||
|
||||
backupDialogWrapper.view = {
|
||||
model: new FakeModel(),
|
||||
};
|
||||
|
||||
event = {
|
||||
button: {
|
||||
'data-btn-name': 'backup',
|
||||
element: {
|
||||
getAttribute: () => {
|
||||
return 'http://someurl';
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
context('when the backup job is created successfully', () => {
|
||||
let dataSentToServer;
|
||||
beforeEach(() => {
|
||||
pgBrowser.Events = jasmine.createSpyObj('Events', ['trigger']);
|
||||
alertifySpy.success = jasmine.createSpy('success');
|
||||
|
||||
networkMock.onPost('/backup/job/10').reply((request) => {
|
||||
dataSentToServer = request.data;
|
||||
return [200, {}];
|
||||
});
|
||||
});
|
||||
|
||||
it('creates a success alert box', (done) => {
|
||||
backupDialogWrapper.callback(event);
|
||||
setTimeout(() => {
|
||||
expect(alertifySpy.success).toHaveBeenCalledWith(
|
||||
'Backup job created.',
|
||||
5
|
||||
);
|
||||
done();
|
||||
}, 0);
|
||||
});
|
||||
|
||||
it('trigger an event to background process', (done) => {
|
||||
backupDialogWrapper.callback(event);
|
||||
|
||||
setTimeout(() => {
|
||||
expect(pgBrowser.Events.trigger).toHaveBeenCalledWith(
|
||||
'pgadmin-bgprocess:created',
|
||||
backupDialogWrapper
|
||||
);
|
||||
done();
|
||||
}, 0);
|
||||
});
|
||||
|
||||
it('send the correct paramenters to the backend', (done) => {
|
||||
backupDialogWrapper.callback(event);
|
||||
setTimeout(() => {
|
||||
expect(JSON.parse(dataSentToServer)).toEqual(
|
||||
{}
|
||||
);
|
||||
done();
|
||||
}, 0);
|
||||
});
|
||||
});
|
||||
|
||||
context('when creating backup job fails', () => {
|
||||
it('creates an alert box', (done) => {
|
||||
alertifySpy.alert = jasmine.createSpy('alert');
|
||||
networkMock.onPost('/backup/job/10').reply(() => {
|
||||
return [400, {
|
||||
errormsg: 'some-error-message',
|
||||
}];
|
||||
});
|
||||
|
||||
backupDialogWrapper.callback(event);
|
||||
setTimeout(() => {
|
||||
expect(alertifySpy.alert).toHaveBeenCalledWith(
|
||||
'Backup job failed.',
|
||||
'some-error-message'
|
||||
);
|
||||
done();
|
||||
}, 0);
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('when dialog type is object', () => {
|
||||
let event;
|
||||
beforeEach(() => {
|
||||
backupDialogWrapper = new BackupDialogWrapper(
|
||||
'<div class=\'backup_dialog\'></div>',
|
||||
'backupDialogTitle',
|
||||
'backup_objects',
|
||||
jquerySpy,
|
||||
pgBrowser,
|
||||
alertifySpy,
|
||||
dialogModelKlassSpy,
|
||||
backform
|
||||
);
|
||||
|
||||
pgBrowser.treeMenu.selectNode(databaseTreeNode.domNode);
|
||||
|
||||
backupDialogWrapper.view = {
|
||||
model: new FakeModel(),
|
||||
};
|
||||
|
||||
event = {
|
||||
button: {
|
||||
'data-btn-name': 'backup',
|
||||
element: {
|
||||
getAttribute: () => {
|
||||
return 'http://someurl';
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
context('when the backup job is created successfully', () => {
|
||||
let dataSentToServer;
|
||||
beforeEach(() => {
|
||||
pgBrowser.Events = jasmine.createSpyObj('Events', ['trigger']);
|
||||
alertifySpy.success = jasmine.createSpy('success');
|
||||
|
||||
networkMock.onPost('/backup/job/10/object').reply((request) => {
|
||||
dataSentToServer = request.data;
|
||||
return [200, {}];
|
||||
});
|
||||
});
|
||||
|
||||
it('creates a success alert box', (done) => {
|
||||
backupDialogWrapper.callback(event);
|
||||
setTimeout(() => {
|
||||
expect(alertifySpy.success).toHaveBeenCalledWith(
|
||||
'Backup job created.',
|
||||
5
|
||||
);
|
||||
done();
|
||||
}, 0);
|
||||
});
|
||||
|
||||
it('trigger an event to background process', (done) => {
|
||||
backupDialogWrapper.callback(event);
|
||||
|
||||
setTimeout(() => {
|
||||
expect(pgBrowser.Events.trigger).toHaveBeenCalledWith(
|
||||
'pgadmin-bgprocess:created',
|
||||
backupDialogWrapper
|
||||
);
|
||||
done();
|
||||
}, 0);
|
||||
});
|
||||
|
||||
it('send the correct parameters to the backend', (done) => {
|
||||
backupDialogWrapper.callback(event);
|
||||
setTimeout(() => {
|
||||
expect(JSON.parse(dataSentToServer)).toEqual(
|
||||
{database: 'some-database-label'}
|
||||
);
|
||||
done();
|
||||
}, 0);
|
||||
});
|
||||
});
|
||||
|
||||
context('when creating backup job fails', () => {
|
||||
it('creates an alert box', (done) => {
|
||||
alertifySpy.alert = jasmine.createSpy('alert');
|
||||
networkMock.onPost('/backup/job/10/object').reply(() => {
|
||||
return [400, {
|
||||
errormsg: 'some-error-message',
|
||||
}];
|
||||
});
|
||||
|
||||
backupDialogWrapper.callback(event);
|
||||
setTimeout(() => {
|
||||
expect(alertifySpy.alert).toHaveBeenCalledWith(
|
||||
'Backup job failed.',
|
||||
'some-error-message'
|
||||
);
|
||||
done();
|
||||
}, 0);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#setExtraParameters', () => {
|
||||
let selectedTreeNode;
|
||||
let treeInfo;
|
||||
let model;
|
||||
|
||||
context('when dialog type is global', () => {
|
||||
beforeEach(() => {
|
||||
backupDialogWrapper = new BackupDialogWrapper(
|
||||
'<div class=\'backup_dialog\'></div>',
|
||||
'backupDialogTitle',
|
||||
'backup',
|
||||
jquerySpy,
|
||||
pgBrowser,
|
||||
alertifySpy,
|
||||
dialogModelKlassSpy,
|
||||
backform
|
||||
);
|
||||
|
||||
treeInfo = {};
|
||||
model = new FakeModel();
|
||||
backupDialogWrapper.view = {
|
||||
model: model,
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
it('sets nothing on the view model', () => {
|
||||
backupDialogWrapper.setExtraParameters(selectedTreeNode, treeInfo);
|
||||
expect(model.toJSON()).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
context('when dialog type is object', () => {
|
||||
beforeEach(() => {
|
||||
backupDialogWrapper = new BackupDialogWrapper(
|
||||
'<div class=\'backup_dialog\'></div>',
|
||||
'backupDialogTitle',
|
||||
'backup_objects',
|
||||
jquerySpy,
|
||||
pgBrowser,
|
||||
alertifySpy,
|
||||
dialogModelKlassSpy,
|
||||
backform
|
||||
);
|
||||
|
||||
treeInfo = {
|
||||
database: {
|
||||
_label: 'some-database-label',
|
||||
},
|
||||
schema: {
|
||||
_label: 'some-treeinfo-label',
|
||||
},
|
||||
};
|
||||
|
||||
model = new FakeModel();
|
||||
selectedTreeNode = new TreeNode('some-selected-node',
|
||||
{_type: 'some-type', _label: 'some-selected-label'},
|
||||
[]);
|
||||
backupDialogWrapper.view = {
|
||||
model: model,
|
||||
};
|
||||
});
|
||||
|
||||
it('sets the database label on the model', () => {
|
||||
backupDialogWrapper.setExtraParameters(selectedTreeNode, treeInfo);
|
||||
expect(model.toJSON()).toEqual({
|
||||
'database': 'some-database-label',
|
||||
});
|
||||
});
|
||||
|
||||
context('when the selected is a schema type', () => {
|
||||
beforeEach(() => {
|
||||
selectedTreeNode = new TreeNode('some-selected-node',
|
||||
{_type: 'schema', _label: 'some-schema-label'},
|
||||
[]);
|
||||
});
|
||||
|
||||
it('sets the schema label on the model', () => {
|
||||
backupDialogWrapper.setExtraParameters(selectedTreeNode, treeInfo);
|
||||
expect(model.toJSON()).toEqual({
|
||||
'database': 'some-database-label',
|
||||
'schemas': ['some-schema-label'],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('when the selected is a table type', () => {
|
||||
beforeEach(() => {
|
||||
selectedTreeNode = new TreeNode('some-selected-node',
|
||||
{_type: 'table', _label: 'some-table-label'},
|
||||
[]);
|
||||
});
|
||||
|
||||
it('sets the schema label on the model', () => {
|
||||
backupDialogWrapper.setExtraParameters(selectedTreeNode, treeInfo);
|
||||
expect(model.toJSON()).toEqual({
|
||||
'database': 'some-database-label',
|
||||
'tables': [['some-treeinfo-label', 'some-table-label']],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('when the model has no ratio value', () => {
|
||||
beforeEach(() => {
|
||||
model.set('ratio', '');
|
||||
});
|
||||
|
||||
it('sets clears the ratio value', () => {
|
||||
backupDialogWrapper.setExtraParameters(selectedTreeNode, treeInfo);
|
||||
expect(model.get('ratio')).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
context('when the model has a valid ratio value', () => {
|
||||
beforeEach(() => {
|
||||
model.set('ratio', '0.25');
|
||||
});
|
||||
|
||||
it('sets clears the ratio value', () => {
|
||||
backupDialogWrapper.setExtraParameters(selectedTreeNode, treeInfo);
|
||||
expect(model.get('ratio')).toEqual('0.25');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -0,0 +1,168 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
import {BackupDialog} from '../../../pgadmin/tools/backup/static/js/backup_dialog';
|
||||
import {TreeFake} from '../tree/tree_fake';
|
||||
|
||||
const context = describe;
|
||||
|
||||
describe('GlobalServerBackupDialog', () => {
|
||||
let backupDialog;
|
||||
let pgBrowser;
|
||||
let jquerySpy;
|
||||
let alertifySpy;
|
||||
let backupModelSpy;
|
||||
|
||||
|
||||
let rootNode;
|
||||
let serverTreeNode;
|
||||
let ppasServerTreeNode;
|
||||
|
||||
beforeEach(() => {
|
||||
pgBrowser = {
|
||||
treeMenu: new TreeFake(),
|
||||
Nodes: {
|
||||
server: jasmine.createSpyObj('Node[server]', ['getTreeNodeHierarchy']),
|
||||
},
|
||||
};
|
||||
pgBrowser.Nodes.server.hasId = true;
|
||||
jquerySpy = jasmine.createSpy('jquerySpy');
|
||||
backupModelSpy = jasmine.createSpy('backupModelSpy');
|
||||
|
||||
rootNode = pgBrowser.treeMenu.addNewNode('level1', {}, undefined, []);
|
||||
serverTreeNode = pgBrowser.treeMenu.addNewNode('level1.1', {
|
||||
_type: 'server',
|
||||
_id: 10,
|
||||
}, undefined, ['level1']);
|
||||
ppasServerTreeNode = pgBrowser.treeMenu.addNewNode('level1.2', {
|
||||
_type: 'server',
|
||||
server_type: 'ppas',
|
||||
}, undefined, ['level1']);
|
||||
pgBrowser.treeMenu.addNewNode('level3', {}, undefined, ['level1', 'level1.2']);
|
||||
pgBrowser.treeMenu.addNewNode('level3.1', undefined, undefined, ['level1', 'level1.2', 'level3']);
|
||||
});
|
||||
|
||||
describe('#draw', () => {
|
||||
beforeEach(() => {
|
||||
alertifySpy = jasmine.createSpyObj('alertify', ['alert', 'dialog']);
|
||||
alertifySpy['BackupDialog_globals'] = jasmine.createSpy('BackupDialog_globals');
|
||||
alertifySpy['BackupDialog_server'] = jasmine.createSpy('BackupDialog_server');
|
||||
backupDialog = new BackupDialog(
|
||||
pgBrowser,
|
||||
jquerySpy,
|
||||
alertifySpy,
|
||||
backupModelSpy
|
||||
);
|
||||
|
||||
pgBrowser.get_preference = jasmine.createSpy('get_preferences');
|
||||
});
|
||||
|
||||
context('there are no ancestors of the type server', () => {
|
||||
it('does not create a dialog', () => {
|
||||
pgBrowser.treeMenu.selectNode([{id: 'level1'}]);
|
||||
backupDialog.draw(null, null, null);
|
||||
expect(alertifySpy['BackupDialog_globals']).not.toHaveBeenCalled();
|
||||
expect(alertifySpy['BackupDialog_server']).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('display an alert with a Backup Error', () => {
|
||||
backupDialog.draw(null, [rootNode], null);
|
||||
expect(alertifySpy.alert).toHaveBeenCalledWith(
|
||||
'Backup Error',
|
||||
'Please select server or child node from the browser tree.'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
context('there is an ancestor of the type server', () => {
|
||||
context('no preference can be found', () => {
|
||||
beforeEach(() => {
|
||||
pgBrowser.get_preference.and.returnValue(undefined);
|
||||
});
|
||||
|
||||
context('server is a ppas server', () => {
|
||||
it('display an alert with "Backup Error"', () => {
|
||||
backupDialog.draw(null, [serverTreeNode], null);
|
||||
expect(alertifySpy.alert).toHaveBeenCalledWith(
|
||||
'Backup Error',
|
||||
'Failed to load preference pg_bin_dir of module paths'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
context('server is not a ppas server', () => {
|
||||
it('display an alert with "Backup Error"', () => {
|
||||
backupDialog.draw(null, [ppasServerTreeNode], null);
|
||||
expect(alertifySpy.alert).toHaveBeenCalledWith(
|
||||
'Backup Error',
|
||||
'Failed to load preference ppas_bin_dir of module paths'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('preference can be found', () => {
|
||||
context('binary folder is not configured', () => {
|
||||
beforeEach(() => {
|
||||
pgBrowser.get_preference.and.returnValue({});
|
||||
});
|
||||
|
||||
context('server is a ppas server', () => {
|
||||
it('display an alert with "Configuration required"', () => {
|
||||
backupDialog.draw(null, [serverTreeNode], null);
|
||||
expect(alertifySpy.alert).toHaveBeenCalledWith(
|
||||
'Configuration required',
|
||||
'Please configure the PostgreSQL Binary Path in the Preferences dialog.'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
context('server is not a ppas server', () => {
|
||||
it('display an alert with "Configuration required"', () => {
|
||||
backupDialog.draw(null, [ppasServerTreeNode], null);
|
||||
expect(alertifySpy.alert).toHaveBeenCalledWith(
|
||||
'Configuration required',
|
||||
'Please configure the EDB Advanced Server Binary Path in the Preferences dialog.'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('binary folder is configured', () => {
|
||||
let globalResizeToSpy;
|
||||
let serverResizeToSpy;
|
||||
beforeEach(() => {
|
||||
globalResizeToSpy = jasmine.createSpyObj('globals', ['resizeTo']);
|
||||
alertifySpy['BackupDialog_globals'].and
|
||||
.returnValue(globalResizeToSpy);
|
||||
serverResizeToSpy = jasmine.createSpyObj('server', ['resizeTo']);
|
||||
alertifySpy['BackupDialog_server'].and
|
||||
.returnValue(serverResizeToSpy);
|
||||
pgBrowser.get_preference.and.returnValue({value: '/some/path'});
|
||||
});
|
||||
|
||||
context('dialog for global backup', () => {
|
||||
it('displays the dialog', () => {
|
||||
backupDialog.draw(null, [serverTreeNode], {globals: true});
|
||||
expect(alertifySpy['BackupDialog_globals']).toHaveBeenCalledWith(true);
|
||||
expect(globalResizeToSpy.resizeTo).toHaveBeenCalledWith('60%', '50%');
|
||||
});
|
||||
});
|
||||
|
||||
context('dialog for server backup', () => {
|
||||
it('displays the dialog', () => {
|
||||
backupDialog.draw(null, [serverTreeNode], {server: true});
|
||||
expect(alertifySpy['BackupDialog_server']).toHaveBeenCalledWith(true);
|
||||
expect(serverResizeToSpy.resizeTo).toHaveBeenCalledWith('60%', '50%');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
55
web/regression/javascript/backup/menu_utils_spec.js
Normal file
55
web/regression/javascript/backup/menu_utils_spec.js
Normal file
@ -0,0 +1,55 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
import {menuEnabledServer} from '../../../pgadmin/tools/backup/static/js/menu_utils';
|
||||
|
||||
const context = describe;
|
||||
|
||||
describe('backup.menuUtils', () => {
|
||||
describe('#menuEnabledServer', () => {
|
||||
context('provided node data is undefined', () => {
|
||||
it('returns false', () => {
|
||||
expect(menuEnabledServer(undefined)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
context('provided node data is null', () => {
|
||||
it('returns false', () => {
|
||||
expect(menuEnabledServer(null)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
context('current node type is not of the type server', () => {
|
||||
it('returns false', () => {
|
||||
expect(menuEnabledServer({_type: 'schema'})).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
context('current node type is of the type server', () => {
|
||||
context('is connected', () => {
|
||||
it('returns true', () => {
|
||||
expect(menuEnabledServer({
|
||||
_type: 'server',
|
||||
connected: true,
|
||||
})).toBe(true);
|
||||
});
|
||||
});
|
||||
context('is not connected', () => {
|
||||
it('returns false', () => {
|
||||
expect(menuEnabledServer({
|
||||
_type: 'server',
|
||||
connected: false,
|
||||
})).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -11,10 +11,6 @@ import keyboardShortcuts from 'sources/keyboard_shortcuts';
|
||||
|
||||
describe('the keyboard shortcuts', () => {
|
||||
const F1_KEY = 112;
|
||||
// const EDIT_KEY = 71; // Key: G -> Grid values
|
||||
// const LEFT_ARROW_KEY = 37;
|
||||
// const RIGHT_ARROW_KEY = 39;
|
||||
// const MOVE_NEXT = 'right';
|
||||
|
||||
let debuggerElementSpy, event, debuggerUserShortcutSpy;
|
||||
debuggerUserShortcutSpy = jasmine.createSpyObj(
|
||||
|
82
web/regression/javascript/datagrid/get_panel_title_spec.js
Normal file
82
web/regression/javascript/datagrid/get_panel_title_spec.js
Normal file
@ -0,0 +1,82 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import {getPanelTitle} from '../../../pgadmin/tools/datagrid/static/js/get_panel_title';
|
||||
import {TreeFake} from '../tree/tree_fake';
|
||||
import {TreeNode} from '../../../pgadmin/static/js/tree/tree';
|
||||
|
||||
const context = describe;
|
||||
|
||||
describe('#getPanelTitle', () => {
|
||||
let pgBrowser;
|
||||
let tree;
|
||||
beforeEach(() => {
|
||||
tree = new TreeFake();
|
||||
pgBrowser = {
|
||||
treeMenu: tree,
|
||||
Nodes: {
|
||||
server: {
|
||||
hasId: true,
|
||||
_type: 'server',
|
||||
},
|
||||
database: {
|
||||
hasId: true,
|
||||
_type: 'database',
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
context('selected node does not belong to a server', () => {
|
||||
it('returns undefined', () => {
|
||||
const root = tree.addNewNode('level1', {_type: 'server_groups'});
|
||||
tree.addChild(root, new TreeNode('level1.1', {_type: 'other'}));
|
||||
tree.selectNode([{id: 'level1'}]);
|
||||
expect(getPanelTitle(pgBrowser)).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
context('selected node belong to a server', () => {
|
||||
context('selected node does not belong to a database', () => {
|
||||
it('returns the server label and the username', () => {
|
||||
tree.addNewNode('level1', {
|
||||
_type: 'server',
|
||||
db: 'other db label',
|
||||
user: {name: 'some user name'},
|
||||
label: 'server label',
|
||||
}, []);
|
||||
|
||||
tree.selectNode([{id: 'level1'}]);
|
||||
expect(getPanelTitle(pgBrowser))
|
||||
.toBe('other db label on some user name@server label');
|
||||
});
|
||||
});
|
||||
|
||||
context('selected node belongs to a database', () => {
|
||||
it('returns the database label and the username', () => {
|
||||
const root = tree.addNewNode('level1', {
|
||||
_type: 'server',
|
||||
db: 'other db label',
|
||||
user: {name: 'some user name'},
|
||||
label: 'server label',
|
||||
});
|
||||
const level1 = new TreeNode('level1.1', {
|
||||
_type: 'database',
|
||||
label: 'db label',
|
||||
});
|
||||
tree.addChild(root, level1);
|
||||
tree.addChild(level1,
|
||||
new TreeNode('level1.1.1', {_type: 'table'}));
|
||||
tree.selectNode([{id: 'level1.1.1'}]);
|
||||
expect(getPanelTitle(pgBrowser))
|
||||
.toBe('db label on some user name@server label');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
171
web/regression/javascript/datagrid/show_data_spec.js
Normal file
171
web/regression/javascript/datagrid/show_data_spec.js
Normal file
@ -0,0 +1,171 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import {showDataGrid} from '../../../pgadmin/tools/datagrid/static/js/show_data';
|
||||
import {TreeFake} from '../tree/tree_fake';
|
||||
import {TreeNode} from '../../../pgadmin/static/js/tree/tree';
|
||||
|
||||
const context = describe;
|
||||
|
||||
describe('#show_data', () => {
|
||||
let datagrid;
|
||||
let pgBrowser;
|
||||
let alertify;
|
||||
beforeEach(() => {
|
||||
alertify = jasmine.createSpyObj('alertify', ['alert']);
|
||||
datagrid = {
|
||||
create_transaction: jasmine.createSpy('create_transaction'),
|
||||
};
|
||||
pgBrowser = {
|
||||
treeMenu: new TreeFake(),
|
||||
Nodes: {
|
||||
server_group: {
|
||||
_type: 'server_group',
|
||||
hasId: true,
|
||||
},
|
||||
server: {
|
||||
_type: 'server',
|
||||
hasId: true,
|
||||
},
|
||||
database: {
|
||||
_type: 'database',
|
||||
hasId: true,
|
||||
},
|
||||
schema: {
|
||||
_type: 'schema',
|
||||
hasId: true,
|
||||
},
|
||||
view: {
|
||||
_type: 'view',
|
||||
hasId: true,
|
||||
},
|
||||
catalog: {
|
||||
_type: 'catalog',
|
||||
hasId: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
const parent = pgBrowser.treeMenu.addNewNode('parent', {_type: 'parent'}, []);
|
||||
const serverGroup1 = new TreeNode('server_group1', {
|
||||
_type: 'server_group',
|
||||
_id: 1,
|
||||
});
|
||||
pgBrowser.treeMenu.addChild(parent, serverGroup1);
|
||||
|
||||
const server1 = new TreeNode('server1', {
|
||||
_type: 'server',
|
||||
label: 'server1',
|
||||
server_type: 'pg',
|
||||
_id: 2,
|
||||
}, ['parent', 'server_group1']);
|
||||
pgBrowser.treeMenu.addChild(serverGroup1, server1);
|
||||
|
||||
const database1 = new TreeNode('database1', {
|
||||
_type: 'database',
|
||||
label: 'database1',
|
||||
_id: 3,
|
||||
}, ['parent', 'server_group1', 'server1']);
|
||||
pgBrowser.treeMenu.addChild(server1, database1);
|
||||
|
||||
const schema1 = new TreeNode('schema1', {
|
||||
_type: 'schema',
|
||||
label: 'schema1',
|
||||
_id: 4,
|
||||
});
|
||||
pgBrowser.treeMenu.addChild(database1, schema1);
|
||||
|
||||
const view1 = new TreeNode('view1', {
|
||||
_type: 'view',
|
||||
label: 'view1',
|
||||
_id: 5,
|
||||
}, ['parent', 'server_group1', 'server1', 'database1']);
|
||||
pgBrowser.treeMenu.addChild(database1, view1);
|
||||
|
||||
const catalog1 = new TreeNode('catalog1', {
|
||||
_type: 'catalog',
|
||||
label: 'catalog1',
|
||||
_id: 6,
|
||||
}, ['parent', 'server_group1', 'server1', 'database1']);
|
||||
pgBrowser.treeMenu.addChild(database1, catalog1);
|
||||
});
|
||||
|
||||
context('cannot find the tree node', () => {
|
||||
it('does not create a transaction', () => {
|
||||
showDataGrid(datagrid, pgBrowser, alertify, {}, [{id: '10'}]);
|
||||
expect(datagrid.create_transaction).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('display alert', () => {
|
||||
showDataGrid(datagrid, pgBrowser, alertify, {}, [{id: '10'}]);
|
||||
expect(alertify.alert).toHaveBeenCalledWith(
|
||||
'Data Grid Error',
|
||||
'No object selected.'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
context('current node is not underneath a server', () => {
|
||||
it('does not create a transaction', () => {
|
||||
showDataGrid(datagrid, pgBrowser, alertify, {}, [{id: 'parent'}]);
|
||||
expect(datagrid.create_transaction).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
context('current node is not underneath a schema or view or catalog', () => {
|
||||
it('does not create a transaction', () => {
|
||||
showDataGrid(datagrid, pgBrowser, alertify, {}, [{id: 'database1'}]);
|
||||
expect(datagrid.create_transaction).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
context('current node is underneath a schema', () => {
|
||||
it('does not create a transaction', () => {
|
||||
showDataGrid(datagrid, pgBrowser, alertify, {mnuid: 11}, [{id: 'schema1'}]);
|
||||
expect(datagrid.create_transaction).toHaveBeenCalledWith(
|
||||
'/initialize/datagrid/11/schema/1/2/3/4',
|
||||
null,
|
||||
'false',
|
||||
'pg',
|
||||
'',
|
||||
'server1 - database1 - schema1.schema1',
|
||||
''
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
context('current node is underneath a view', () => {
|
||||
it('does not create a transaction', () => {
|
||||
showDataGrid(datagrid, pgBrowser, alertify, {mnuid: 11}, [{id: 'view1'}]);
|
||||
expect(datagrid.create_transaction).toHaveBeenCalledWith(
|
||||
'/initialize/datagrid/11/view/1/2/3/5',
|
||||
null,
|
||||
'false',
|
||||
'pg',
|
||||
'',
|
||||
'server1 - database1 - view1.view1',
|
||||
''
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
context('current node is underneath a catalog', () => {
|
||||
it('does not create a transaction', () => {
|
||||
showDataGrid(datagrid, pgBrowser, alertify, {mnuid: 11}, [{id: 'catalog1'}]);
|
||||
expect(datagrid.create_transaction).toHaveBeenCalledWith(
|
||||
'/initialize/datagrid/11/catalog/1/2/3/6',
|
||||
null,
|
||||
'false',
|
||||
'pg',
|
||||
'',
|
||||
'server1 - database1 - catalog1.catalog1',
|
||||
''
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
125
web/regression/javascript/datagrid/show_query_tool_spec.js
Normal file
125
web/regression/javascript/datagrid/show_query_tool_spec.js
Normal file
@ -0,0 +1,125 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import {TreeFake} from '../tree/tree_fake';
|
||||
import {showQueryTool} from '../../../pgadmin/tools/datagrid/static/js/show_query_tool';
|
||||
import {TreeNode} from '../../../pgadmin/static/js/tree/tree';
|
||||
|
||||
const context = describe;
|
||||
|
||||
describe('#showQueryTool', () => {
|
||||
let queryTool;
|
||||
let pgBrowser;
|
||||
let alertify;
|
||||
beforeEach(() => {
|
||||
alertify = jasmine.createSpyObj('alertify', ['alert']);
|
||||
queryTool = {
|
||||
create_transaction: jasmine.createSpy('create_transaction'),
|
||||
};
|
||||
pgBrowser = {
|
||||
treeMenu: new TreeFake(),
|
||||
Nodes: {
|
||||
server_group: {
|
||||
_type: 'server_group',
|
||||
hasId: true,
|
||||
},
|
||||
server: {
|
||||
_type: 'server',
|
||||
hasId: true,
|
||||
},
|
||||
database: {
|
||||
_type: 'database',
|
||||
hasId: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
const parent = pgBrowser.treeMenu.addNewNode('parent', {_type: 'parent'});
|
||||
const serverGroup1 = new TreeNode('server_group1', {
|
||||
_type: 'server_group',
|
||||
_id: 1,
|
||||
}, ['parent']);
|
||||
pgBrowser.treeMenu.addChild(parent, serverGroup1);
|
||||
|
||||
const server1 = new TreeNode('server1', {
|
||||
_type: 'server',
|
||||
label: 'server1',
|
||||
server_type: 'pg',
|
||||
_id: 2,
|
||||
});
|
||||
pgBrowser.treeMenu.addChild(serverGroup1, server1);
|
||||
|
||||
const database1 = new TreeNode('database1', {
|
||||
_type: 'database',
|
||||
label: 'database1',
|
||||
_id: 3,
|
||||
});
|
||||
pgBrowser.treeMenu.addChild(server1, database1);
|
||||
});
|
||||
|
||||
context('cannot find the tree node', () => {
|
||||
beforeEach(() => {
|
||||
showQueryTool(queryTool, pgBrowser, alertify, '', [{id: '10'}], 'title');
|
||||
});
|
||||
it('does not create a transaction', () => {
|
||||
expect(queryTool.create_transaction).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('display alert', () => {
|
||||
expect(alertify.alert).toHaveBeenCalledWith(
|
||||
'Query Tool Error',
|
||||
'No object selected.'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
context('current node is not underneath a server', () => {
|
||||
it('does not create a transaction', () => {
|
||||
showQueryTool(queryTool, pgBrowser, alertify, '', [{id: 'parent'}], 'title');
|
||||
expect(queryTool.create_transaction).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('no alert is displayed', () => {
|
||||
expect(alertify.alert).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
context('current node is underneath a server', () => {
|
||||
context('current node is not underneath a database', () => {
|
||||
it('creates a transaction', () => {
|
||||
showQueryTool(queryTool, pgBrowser, alertify, 'http://someurl', [{id: 'server1'}], 'title');
|
||||
expect(queryTool.create_transaction).toHaveBeenCalledWith(
|
||||
'/initialize/query_tool/1/2',
|
||||
null,
|
||||
'true',
|
||||
'pg',
|
||||
'http://someurl',
|
||||
'title',
|
||||
'',
|
||||
false
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
context('current node is underneath a database', () => {
|
||||
it('creates a transaction', () => {
|
||||
showQueryTool(queryTool, pgBrowser, alertify, 'http://someurl', [{id: 'database1'}], 'title');
|
||||
expect(queryTool.create_transaction).toHaveBeenCalledWith(
|
||||
'/initialize/query_tool/1/2/3',
|
||||
null,
|
||||
'true',
|
||||
'pg',
|
||||
'http://someurl',
|
||||
'title',
|
||||
'',
|
||||
false
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
12
web/regression/javascript/fake_browser/browser.js
Normal file
12
web/regression/javascript/fake_browser/browser.js
Normal file
@ -0,0 +1,12 @@
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
let treeMenu = null;
|
||||
|
||||
export {treeMenu};
|
@ -12,5 +12,11 @@ define(function () {
|
||||
'static': '/base/pgadmin/static/<path:filename>',
|
||||
'sqleditor.poll': '/sqleditor/query_tool/poll/<path:trans_id>',
|
||||
'sqleditor.query_tool_start': '/sqleditor/query_tool/start/<path:trans_id>',
|
||||
'backup.create_server_job': '/backup/job/<int:sid>',
|
||||
'backup.create_object_job': '/backup/job/<int:sid>/object',
|
||||
'datagrid.initialize_datagrid': '/initialize/datagrid/<int:cmd_type>/<obj_type>/<int:sgid>/<int:sid>/<int:did>/<int:obj_id>',
|
||||
'datagrid.initialize_query_tool': '/initialize/query_tool/<int:sgid>/<int:sid>',
|
||||
'datagrid.initialize_query_tool_with_did': '/initialize/query_tool/<int:sgid>/<int:sid>/<int:did>',
|
||||
'restore.create_job': '/restore/job/<int:sid>',
|
||||
};
|
||||
});
|
||||
|
21
web/regression/javascript/fake_model.js
Normal file
21
web/regression/javascript/fake_model.js
Normal file
@ -0,0 +1,21 @@
|
||||
export class FakeModel {
|
||||
constructor() {
|
||||
this.values = {};
|
||||
}
|
||||
|
||||
set(key, value) {
|
||||
this.values[key] = value;
|
||||
}
|
||||
|
||||
get(key) {
|
||||
return this.values[key];
|
||||
}
|
||||
|
||||
unset(key) {
|
||||
delete this.values[key];
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return Object.assign({}, this.values);
|
||||
}
|
||||
}
|
253
web/regression/javascript/nodes/schema/child_menu_spec.js
Normal file
253
web/regression/javascript/nodes/schema/child_menu_spec.js
Normal file
@ -0,0 +1,253 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
/////////////////////////////////////////////////////////////
|
||||
|
||||
import {
|
||||
isTreeItemOfChildOfSchema, childCreateMenuEnabled,
|
||||
} from 'pgadmin.schema.dir/schema_child_tree_node';
|
||||
|
||||
import * as pgBrowser from 'pgbrowser/browser';
|
||||
import {TreeFake} from '../../tree/tree_fake';
|
||||
|
||||
describe('#childCreateMenuEnabled', () => {
|
||||
let data;
|
||||
let tree;
|
||||
|
||||
describe(' - when data is not null', () => {
|
||||
beforeEach(() => {
|
||||
data = {};
|
||||
});
|
||||
describe(' and check is false', () => {
|
||||
beforeEach(() => {
|
||||
data = {check: false};
|
||||
});
|
||||
it(', then it returns true', () => {
|
||||
expect(childCreateMenuEnabled({}, {}, data)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe(' and check', () => {
|
||||
describe(' is true', () => {
|
||||
beforeEach(() => {
|
||||
data = {check: true};
|
||||
});
|
||||
|
||||
describe(', on schema node', () => {
|
||||
beforeEach(() => {
|
||||
let hierarchy = {
|
||||
id: 'root',
|
||||
children: [{
|
||||
id: 'level2',
|
||||
data: {_type: 'schema'},
|
||||
}],
|
||||
};
|
||||
|
||||
tree = TreeFake.build(hierarchy);
|
||||
pgBrowser.treeMenu = tree;
|
||||
});
|
||||
it(' it is true', () => {
|
||||
expect(childCreateMenuEnabled(
|
||||
{}, [{id: 'level2'}], data
|
||||
)).toBe(true);
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe(', on child collection node under schema node ', () => {
|
||||
beforeEach(() => {
|
||||
let hierarchy = {
|
||||
id: 'root',
|
||||
children: [{
|
||||
id: 'level2',
|
||||
data: {_type: 'schema'},
|
||||
children: [{
|
||||
id: 'coll-table',
|
||||
data: {_type: 'coll-table'},
|
||||
}],
|
||||
}],
|
||||
};
|
||||
|
||||
tree = TreeFake.build(hierarchy);
|
||||
pgBrowser.treeMenu = tree;
|
||||
});
|
||||
|
||||
it(' it is true', () => {
|
||||
expect(childCreateMenuEnabled(
|
||||
{}, [{id: 'coll-table'}], data
|
||||
)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe(', on one of the child node under schema node ', () => {
|
||||
beforeEach(() => {
|
||||
let hierarchy = {
|
||||
id: 'root',
|
||||
children: [{
|
||||
id: 'level2',
|
||||
data: {_type: 'schema'},
|
||||
children: [{
|
||||
id: 'coll-table',
|
||||
data: {_type: 'coll-table'},
|
||||
children: [{
|
||||
id: 'table/1',
|
||||
data: {_type: 'table'},
|
||||
}],
|
||||
}],
|
||||
}],
|
||||
};
|
||||
|
||||
tree = TreeFake.build(hierarchy);
|
||||
pgBrowser.treeMenu = tree;
|
||||
});
|
||||
|
||||
it(' it is true', () => {
|
||||
expect(childCreateMenuEnabled(
|
||||
{}, [{id: 'table/1'}], data
|
||||
)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe(', on catalog node', () => {
|
||||
beforeEach(() => {
|
||||
let hierarchy = {
|
||||
id: 'root',
|
||||
children: [{
|
||||
id: 'level2',
|
||||
data: {_type: 'catalog'},
|
||||
}],
|
||||
};
|
||||
|
||||
tree = TreeFake.build(hierarchy);
|
||||
pgBrowser.treeMenu = tree;
|
||||
});
|
||||
it(' it is false', () => {
|
||||
expect(
|
||||
childCreateMenuEnabled({}, [{id: 'level2'}], data)
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe(', on child collection node under catalog node ', () => {
|
||||
beforeEach(() => {
|
||||
let hierarchy = {
|
||||
id: 'root',
|
||||
children: [{
|
||||
id: 'level2',
|
||||
data: {_type: 'catalog'},
|
||||
children: [{
|
||||
id: 'coll-table',
|
||||
data: {_type: 'coll-table'},
|
||||
}],
|
||||
}],
|
||||
};
|
||||
|
||||
tree = TreeFake.build(hierarchy);
|
||||
pgBrowser.treeMenu = tree;
|
||||
});
|
||||
|
||||
it(' it is false', () => {
|
||||
expect(childCreateMenuEnabled(
|
||||
{}, [{id: 'coll-table'}], data
|
||||
)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe(', on one of the child node under catalog node ', () => {
|
||||
beforeEach(() => {
|
||||
let hierarchy = {
|
||||
id: 'root',
|
||||
children: [{
|
||||
id: 'level2',
|
||||
data: {_type: 'catalog'},
|
||||
children: [{
|
||||
id: 'coll-table',
|
||||
data: {_type: 'coll-table'},
|
||||
children: [{
|
||||
id: 'table/1',
|
||||
data: {_type: 'table'},
|
||||
}],
|
||||
}],
|
||||
}],
|
||||
};
|
||||
|
||||
tree = TreeFake.build(hierarchy);
|
||||
pgBrowser.treeMenu = tree;
|
||||
});
|
||||
|
||||
it(' it is false', () => {
|
||||
expect(childCreateMenuEnabled(
|
||||
{}, [{id: 'table/1'}], data
|
||||
)).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#childDropMenuEnabled', () => {
|
||||
let tree;
|
||||
|
||||
describe(' - the child node under schema node ', () => {
|
||||
beforeEach(() => {
|
||||
let hierarchy = {
|
||||
id: 'root',
|
||||
children: [{
|
||||
id: 'level2',
|
||||
data: {_type: 'schema'},
|
||||
children: [{
|
||||
id: 'coll-table',
|
||||
data: {_type: 'coll-table'},
|
||||
children: [{
|
||||
id: 'table/1',
|
||||
data: {_type: 'table'},
|
||||
}],
|
||||
}],
|
||||
}],
|
||||
};
|
||||
|
||||
tree = TreeFake.build(hierarchy);
|
||||
pgBrowser.treeMenu = tree;
|
||||
});
|
||||
|
||||
it(' it is true', () => {
|
||||
expect(isTreeItemOfChildOfSchema(
|
||||
{}, [{id: 'table/1'}]
|
||||
)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('- the child node under the catalog node ', () => {
|
||||
beforeEach(() => {
|
||||
let hierarchy = {
|
||||
id: 'root',
|
||||
children: [{
|
||||
id: 'level2',
|
||||
data: {_type: 'catalog'},
|
||||
children: [{
|
||||
id: 'coll-table',
|
||||
data: {_type: 'coll-table'},
|
||||
children: [{
|
||||
id: 'table/1',
|
||||
data: {_type: 'table'},
|
||||
}],
|
||||
}],
|
||||
}],
|
||||
};
|
||||
|
||||
tree = TreeFake.build(hierarchy);
|
||||
pgBrowser.treeMenu = tree;
|
||||
});
|
||||
|
||||
it(' it is false', () => {
|
||||
expect(isTreeItemOfChildOfSchema(
|
||||
{}, [{id: 'table/1'}]
|
||||
)).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
203
web/regression/javascript/restore/restore_dialog_spec.js
Normal file
203
web/regression/javascript/restore/restore_dialog_spec.js
Normal file
@ -0,0 +1,203 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
import {TreeFake} from '../tree/tree_fake';
|
||||
import {RestoreDialog} from '../../../pgadmin/tools/restore/static/js/restore_dialog';
|
||||
|
||||
const context = describe;
|
||||
|
||||
describe('RestoreDialog', () => {
|
||||
let restoreDialog;
|
||||
let pgBrowser;
|
||||
let jquerySpy;
|
||||
let alertifySpy;
|
||||
let restoreModelSpy;
|
||||
|
||||
beforeEach(() => {
|
||||
pgBrowser = {
|
||||
treeMenu: new TreeFake(),
|
||||
Nodes: {
|
||||
server: jasmine.createSpyObj('Node[server]', ['getTreeNodeHierarchy']),
|
||||
database: jasmine.createSpyObj('Node[database]', ['getTreeNodeHierarchy']),
|
||||
},
|
||||
};
|
||||
pgBrowser.Nodes.server.hasId = true;
|
||||
pgBrowser.Nodes.database.hasId = true;
|
||||
jquerySpy = jasmine.createSpy('jquerySpy');
|
||||
restoreModelSpy = jasmine.createSpy('restoreModelSpy');
|
||||
|
||||
const hierarchy = {
|
||||
children: [
|
||||
{
|
||||
id: 'root',
|
||||
children: [
|
||||
{
|
||||
id: 'serverTreeNode',
|
||||
data: {
|
||||
_id: 10,
|
||||
_type: 'server',
|
||||
label: 'some-tree-label',
|
||||
},
|
||||
children: [
|
||||
{
|
||||
id: 'some_database',
|
||||
data: {
|
||||
_type: 'database',
|
||||
_id: 11,
|
||||
label: 'some_database',
|
||||
_label: 'some_database_label',
|
||||
},
|
||||
}, {
|
||||
id: 'database_with_equal_in_name',
|
||||
data: {
|
||||
_type: 'database',
|
||||
label: 'some_database',
|
||||
_label: '=some_database_label',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'ppasServer',
|
||||
data: {
|
||||
_type: 'server',
|
||||
server_type: 'ppas',
|
||||
children: [
|
||||
{id: 'someNodeUnderneathPPASServer'},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
pgBrowser.treeMenu = TreeFake.build(hierarchy);
|
||||
});
|
||||
|
||||
describe('#draw', () => {
|
||||
beforeEach(() => {
|
||||
alertifySpy = jasmine.createSpyObj('alertify', ['alert', 'dialog']);
|
||||
alertifySpy['pg_restore'] = jasmine.createSpy('pg_restore');
|
||||
restoreDialog = new RestoreDialog(
|
||||
pgBrowser,
|
||||
jquerySpy,
|
||||
alertifySpy,
|
||||
restoreModelSpy
|
||||
);
|
||||
|
||||
pgBrowser.get_preference = jasmine.createSpy('get_preferences');
|
||||
});
|
||||
|
||||
context('there are no ancestors of the type server', () => {
|
||||
it('does not create a dialog', () => {
|
||||
pgBrowser.treeMenu.selectNode([{id: 'root'}]);
|
||||
restoreDialog.draw(null, null, null);
|
||||
expect(alertifySpy['pg_restore']).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('display an alert with a Restore Error', () => {
|
||||
restoreDialog.draw(null, [{id: 'root'}], null);
|
||||
expect(alertifySpy.alert).toHaveBeenCalledWith(
|
||||
'Restore Error',
|
||||
'Please select server or child node from the browser tree.'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
context('there is an ancestor of the type server', () => {
|
||||
context('no preference can be found', () => {
|
||||
beforeEach(() => {
|
||||
pgBrowser.get_preference.and.returnValue(undefined);
|
||||
});
|
||||
|
||||
context('server is a ppas server', () => {
|
||||
it('display an alert with "Restore Error"', () => {
|
||||
restoreDialog.draw(null, [{id: 'serverTreeNode'}], null);
|
||||
expect(alertifySpy.alert).toHaveBeenCalledWith(
|
||||
'Restore Error',
|
||||
'Failed to load preference pg_bin_dir of module paths'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
context('server is not a ppas server', () => {
|
||||
it('display an alert with "Restore Error"', () => {
|
||||
restoreDialog.draw(null, [{id: 'ppasServer'}], null);
|
||||
expect(alertifySpy.alert).toHaveBeenCalledWith(
|
||||
'Restore Error',
|
||||
'Failed to load preference ppas_bin_dir of module paths'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('preference can be found', () => {
|
||||
context('binary folder is not configured', () => {
|
||||
beforeEach(() => {
|
||||
pgBrowser.get_preference.and.returnValue({});
|
||||
});
|
||||
|
||||
context('server is a ppas server', () => {
|
||||
it('display an alert with "Configuration required"', () => {
|
||||
restoreDialog.draw(null, [{id: 'serverTreeNode'}], null);
|
||||
expect(alertifySpy.alert).toHaveBeenCalledWith(
|
||||
'Configuration required',
|
||||
'Please configure the PostgreSQL Binary Path in the Preferences dialog.'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
context('server is not a ppas server', () => {
|
||||
it('display an alert with "Configuration required"', () => {
|
||||
restoreDialog.draw(null, [{id: 'ppasServer'}], null);
|
||||
expect(alertifySpy.alert).toHaveBeenCalledWith(
|
||||
'Configuration required',
|
||||
'Please configure the EDB Advanced Server Binary Path in the Preferences dialog.'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('binary folder is configured', () => {
|
||||
let spy;
|
||||
beforeEach(() => {
|
||||
spy = jasmine.createSpyObj('globals', ['resizeTo']);
|
||||
alertifySpy['pg_restore'].and
|
||||
.returnValue(spy);
|
||||
pgBrowser.get_preference.and.returnValue({value: '/some/path'});
|
||||
pgBrowser.Nodes.server.label = 'some-server-label';
|
||||
});
|
||||
|
||||
it('displays the dialog', () => {
|
||||
restoreDialog.draw(null, [{id: 'serverTreeNode'}], {server: true});
|
||||
expect(alertifySpy['pg_restore']).toHaveBeenCalledWith(
|
||||
'Restore (some-server-label: some-tree-label)',
|
||||
[{id: 'serverTreeNode'}],
|
||||
{
|
||||
_id: 10,
|
||||
_type: 'server',
|
||||
label: 'some-tree-label',
|
||||
},
|
||||
pgBrowser.Nodes.server
|
||||
);
|
||||
expect(spy.resizeTo).toHaveBeenCalledWith('65%', '60%');
|
||||
});
|
||||
|
||||
context('database label contain "="', () => {
|
||||
it('should create alert dialog with restore error', () => {
|
||||
restoreDialog.draw(null, [{id: 'database_with_equal_in_name'}], null);
|
||||
expect(alertifySpy.alert).toHaveBeenCalledWith('Restore Error',
|
||||
'Databases with = symbols in the name cannot be backed up or restored using this utility.');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
593
web/regression/javascript/restore/restore_dialog_wrapper_spec.js
Normal file
593
web/regression/javascript/restore/restore_dialog_wrapper_spec.js
Normal file
@ -0,0 +1,593 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
import {TreeFake} from '../tree/tree_fake';
|
||||
import {RestoreDialogWrapper} from '../../../pgadmin/tools/restore/static/js/restore_dialog_wrapper';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import axios from 'axios/index';
|
||||
import {FakeModel} from '../fake_model';
|
||||
import {TreeNode} from '../../../pgadmin/static/js/tree/tree';
|
||||
|
||||
let context = describe;
|
||||
|
||||
describe('RestoreDialogWrapper', () => {
|
||||
let jquerySpy;
|
||||
let pgBrowser;
|
||||
let alertifySpy;
|
||||
let dialogModelKlassSpy;
|
||||
let backform;
|
||||
let generatedRestoreModel;
|
||||
let restoreDialogWrapper;
|
||||
let noDataNode;
|
||||
let serverTreeNode;
|
||||
let viewSchema;
|
||||
let restoreJQueryContainerSpy;
|
||||
let restoreNodeChildNodeSpy;
|
||||
let restoreNode;
|
||||
|
||||
beforeEach(() => {
|
||||
pgBrowser = {
|
||||
treeMenu: new TreeFake(),
|
||||
Nodes: {
|
||||
server: {
|
||||
hasId: true,
|
||||
getTreeNodeHierarchy: jasmine.createSpy('getTreeNodeHierarchy'),
|
||||
},
|
||||
},
|
||||
keyboardNavigation: jasmine.createSpyObj('keyboardNavigation', ['getDialogTabNavigator']),
|
||||
};
|
||||
|
||||
noDataNode = pgBrowser.treeMenu.addNewNode('level1.1', undefined, [{id: 'level1'}]);
|
||||
serverTreeNode = pgBrowser.treeMenu.addNewNode('level2.1', {
|
||||
_type: 'server',
|
||||
_id: 10,
|
||||
label: 'some-tree-label',
|
||||
}, [{id: 'level2.1'}]);
|
||||
jquerySpy = jasmine.createSpy('jquerySpy');
|
||||
dialogModelKlassSpy = jasmine.createSpy('dialogModelKlass');
|
||||
generatedRestoreModel = {};
|
||||
viewSchema = {};
|
||||
backform = jasmine.createSpyObj('backform', ['generateViewSchema', 'Dialog']);
|
||||
backform.generateViewSchema.and.returnValue(viewSchema);
|
||||
dialogModelKlassSpy.and.returnValue(generatedRestoreModel);
|
||||
restoreJQueryContainerSpy = jasmine.createSpyObj('restoreJQueryContainer', ['get', 'attr']);
|
||||
restoreJQueryContainerSpy.get.and.returnValue(restoreJQueryContainerSpy);
|
||||
|
||||
restoreNode = {
|
||||
__internal: {
|
||||
buttons: [
|
||||
{}, {},
|
||||
{
|
||||
element: {
|
||||
disabled: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
elements: {
|
||||
body: {
|
||||
childNodes: [
|
||||
{},
|
||||
],
|
||||
},
|
||||
content: jasmine.createSpyObj('content', ['appendChild', 'attr']),
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
restoreNodeChildNodeSpy = jasmine.createSpyObj('something', ['addClass']);
|
||||
|
||||
jquerySpy.and.callFake((selector) => {
|
||||
if (selector === '<div class=\'restore_dialog\'></div>') {
|
||||
return restoreJQueryContainerSpy;
|
||||
} else if (selector === restoreNode.elements.body.childNodes[0]) {
|
||||
return restoreNodeChildNodeSpy;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('#prepare', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
alertifySpy = jasmine.createSpyObj('alertify', ['alert', 'dialog']);
|
||||
restoreDialogWrapper = new RestoreDialogWrapper(
|
||||
'<div class=\'restore_dialog\'></div>',
|
||||
'restoreDialogTitle',
|
||||
'restore',
|
||||
jquerySpy,
|
||||
pgBrowser,
|
||||
alertifySpy,
|
||||
dialogModelKlassSpy,
|
||||
backform
|
||||
);
|
||||
restoreDialogWrapper = Object.assign(restoreDialogWrapper, restoreNode);
|
||||
});
|
||||
context('no tree element is selected', () => {
|
||||
it('does not create a backform dialog', () => {
|
||||
restoreDialogWrapper.prepare();
|
||||
expect(backform.Dialog).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('disables the button "submit button" until a filename is selected', () => {
|
||||
restoreDialogWrapper.prepare();
|
||||
expect(restoreDialogWrapper.__internal.buttons[2].element.disabled).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
context('selected tree node has no data', () => {
|
||||
beforeEach(() => {
|
||||
pgBrowser.treeMenu.selectNode(noDataNode.domNode);
|
||||
});
|
||||
|
||||
it('does not create a backform dialog', () => {
|
||||
restoreDialogWrapper.prepare();
|
||||
expect(backform.Dialog).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('disables the button "submit button" until a filename is selected', () => {
|
||||
restoreDialogWrapper.prepare();
|
||||
expect(restoreDialogWrapper.__internal.buttons[2].element.disabled).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
context('tree element is selected', () => {
|
||||
let treeHierarchyInformation;
|
||||
let dialogSpy;
|
||||
beforeEach(() => {
|
||||
treeHierarchyInformation = {
|
||||
server: {
|
||||
_type: 'server',
|
||||
_id: 10,
|
||||
priority: 0,
|
||||
label: 'some-tree-label',
|
||||
},
|
||||
};
|
||||
pgBrowser.treeMenu.selectNode(serverTreeNode.domNode);
|
||||
pgBrowser.Nodes['server'].getTreeNodeHierarchy.and
|
||||
.returnValue(treeHierarchyInformation);
|
||||
dialogSpy = jasmine.createSpyObj('newView', ['render']);
|
||||
dialogSpy.$el = jasmine.createSpyObj('$el', ['find', 'attr']);
|
||||
dialogSpy.model = jasmine.createSpyObj('model', ['on']);
|
||||
dialogSpy.$el.find.and.returnValue([]);
|
||||
|
||||
backform.Dialog.and.returnValue(dialogSpy);
|
||||
});
|
||||
|
||||
it('creates a backform dialog and displays it', () => {
|
||||
restoreDialogWrapper.prepare();
|
||||
expect(backform.Dialog).toHaveBeenCalledWith({
|
||||
el: restoreJQueryContainerSpy,
|
||||
model: generatedRestoreModel,
|
||||
schema: viewSchema,
|
||||
});
|
||||
|
||||
expect(dialogSpy.render).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('add alertify classes to restore node childnode', () => {
|
||||
restoreDialogWrapper.prepare();
|
||||
expect(restoreNodeChildNodeSpy.addClass)
|
||||
.toHaveBeenCalledWith('alertify_tools_dialog_properties obj_properties');
|
||||
});
|
||||
|
||||
it('disables the button submit button until a filename is selected', () => {
|
||||
restoreDialogWrapper.prepare();
|
||||
expect(restoreNode.__internal.buttons[2].element.disabled).toBe(true);
|
||||
});
|
||||
|
||||
it('generates a new restore model', () => {
|
||||
restoreDialogWrapper.prepare();
|
||||
expect(dialogModelKlassSpy).toHaveBeenCalledWith(
|
||||
{node_data: pgBrowser.Nodes['server']},
|
||||
{node_info: treeHierarchyInformation}
|
||||
);
|
||||
});
|
||||
|
||||
it('add the new dialog to the restore node HTML', () => {
|
||||
restoreDialogWrapper.prepare();
|
||||
expect(restoreNode.elements.content.appendChild).toHaveBeenCalledWith(restoreJQueryContainerSpy);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('onButtonClicked', () => {
|
||||
let networkMock;
|
||||
|
||||
beforeEach(() => {
|
||||
pgBrowser.showHelp = jasmine.createSpy('showHelp');
|
||||
networkMock = new MockAdapter(axios);
|
||||
alertifySpy = jasmine.createSpyObj('alertify', ['success', 'alert']);
|
||||
restoreDialogWrapper = new RestoreDialogWrapper(
|
||||
'<div class=\'restore_dialog\'></div>',
|
||||
'restoreDialogTitle',
|
||||
'restore',
|
||||
jquerySpy,
|
||||
pgBrowser,
|
||||
alertifySpy,
|
||||
dialogModelKlassSpy,
|
||||
backform
|
||||
);
|
||||
restoreDialogWrapper = Object.assign(restoreDialogWrapper, restoreNode);
|
||||
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
networkMock.restore();
|
||||
});
|
||||
|
||||
context('dialog help button was pressed', () => {
|
||||
let networkCalled;
|
||||
beforeEach(() => {
|
||||
networkCalled = false;
|
||||
pgBrowser.treeMenu.selectNode(serverTreeNode.domNode);
|
||||
networkMock.onAny(/.+/).reply(() => {
|
||||
networkCalled = true;
|
||||
return [200, {}];
|
||||
});
|
||||
|
||||
const event = {
|
||||
button: {
|
||||
element: {
|
||||
name: 'dialog_help',
|
||||
getAttribute: (attributeName) => {
|
||||
if (attributeName === 'url') {
|
||||
return 'http://someurl';
|
||||
} else if (attributeName === 'label') {
|
||||
return 'some label';
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
restoreDialogWrapper.callback(event);
|
||||
});
|
||||
|
||||
it('displays help for dialog', () => {
|
||||
expect(pgBrowser.showHelp).toHaveBeenCalledWith(
|
||||
'dialog_help',
|
||||
'http://someurl',
|
||||
pgBrowser.Nodes['server'],
|
||||
serverTreeNode,
|
||||
'some label'
|
||||
);
|
||||
});
|
||||
|
||||
it('does not start the restore', () => {
|
||||
expect(networkCalled).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
context('object help button was pressed', () => {
|
||||
let networkCalled;
|
||||
beforeEach(() => {
|
||||
networkCalled = false;
|
||||
pgBrowser.treeMenu.selectNode(serverTreeNode.domNode);
|
||||
networkMock.onAny(/.+/).reply(() => {
|
||||
networkCalled = true;
|
||||
return [200, {}];
|
||||
});
|
||||
|
||||
const event = {
|
||||
button: {
|
||||
element: {
|
||||
name: 'object_help',
|
||||
getAttribute: (attributeName) => {
|
||||
if (attributeName === 'url') {
|
||||
return 'http://someurl';
|
||||
} else if (attributeName === 'label') {
|
||||
return 'some label';
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
restoreDialogWrapper.callback(event);
|
||||
});
|
||||
|
||||
it('displays help for dialog', () => {
|
||||
expect(pgBrowser.showHelp).toHaveBeenCalledWith(
|
||||
'object_help',
|
||||
'http://someurl',
|
||||
pgBrowser.Nodes['server'],
|
||||
serverTreeNode,
|
||||
'some label'
|
||||
);
|
||||
});
|
||||
|
||||
it('does not start the restore', () => {
|
||||
expect(networkCalled).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
context('restore button was pressed', () => {
|
||||
let networkCalled;
|
||||
let event;
|
||||
|
||||
context('no tree node is selected', () => {
|
||||
beforeEach(() => {
|
||||
networkCalled = false;
|
||||
networkMock.onAny(/.+/).reply(() => {
|
||||
networkCalled = true;
|
||||
return [200, {}];
|
||||
});
|
||||
event = {
|
||||
button: {
|
||||
'data-btn-name': 'restore',
|
||||
element: {
|
||||
getAttribute: () => {
|
||||
return 'http://someurl';
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
it('does not start the restore', () => {
|
||||
restoreDialogWrapper.callback(event);
|
||||
expect(networkCalled).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
context('tree node selected has no data', () => {
|
||||
beforeEach(() => {
|
||||
networkCalled = false;
|
||||
networkMock.onAny(/.+/).reply(() => {
|
||||
networkCalled = true;
|
||||
return [200, {}];
|
||||
});
|
||||
event = {
|
||||
button: {
|
||||
'data-btn-name': 'restore',
|
||||
element: {
|
||||
getAttribute: () => {
|
||||
return 'http://someurl';
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
pgBrowser.treeMenu.selectNode(noDataNode.domNode);
|
||||
});
|
||||
|
||||
it('does not start the restore', () => {
|
||||
restoreDialogWrapper.callback(event);
|
||||
expect(networkCalled).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
context('tree node select has data', () => {
|
||||
|
||||
let databaseTreeNode;
|
||||
|
||||
beforeEach(() => {
|
||||
databaseTreeNode = pgBrowser.treeMenu.addNewNode('level3.1', {
|
||||
_type: 'database',
|
||||
_id: 10,
|
||||
_label: 'some-database-label',
|
||||
}, [{id: 'level3.1'}]);
|
||||
pgBrowser.treeMenu.addChild(serverTreeNode, databaseTreeNode);
|
||||
pgBrowser.Nodes.database = {
|
||||
hasId: true,
|
||||
_label: 'some-database-label',
|
||||
};
|
||||
let fakeModel = new FakeModel();
|
||||
fakeModel.set('some-key', 'some-value');
|
||||
restoreDialogWrapper.view = {
|
||||
model: fakeModel,
|
||||
};
|
||||
pgBrowser.treeMenu.selectNode(databaseTreeNode.domNode);
|
||||
pgBrowser.Events = jasmine.createSpyObj('pgBrowserEventsSpy', ['trigger']);
|
||||
event = {
|
||||
button: {
|
||||
'data-btn-name': 'restore',
|
||||
element: {
|
||||
getAttribute: () => {
|
||||
return 'http://someurl';
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
context('restore job created successfully', () => {
|
||||
let dataSentToServer;
|
||||
beforeEach(() => {
|
||||
networkMock.onPost('/restore/job/10').reply((request) => {
|
||||
dataSentToServer = request.data;
|
||||
return [200, {}];
|
||||
});
|
||||
});
|
||||
|
||||
it('create an success alert box', (done) => {
|
||||
restoreDialogWrapper.callback(event);
|
||||
setTimeout(() => {
|
||||
expect(alertifySpy.success).toHaveBeenCalledWith(
|
||||
'Restore job created.',
|
||||
5
|
||||
);
|
||||
done();
|
||||
}, 0);
|
||||
});
|
||||
|
||||
it('trigger background process', (done) => {
|
||||
restoreDialogWrapper.callback(event);
|
||||
setTimeout(() => {
|
||||
expect(pgBrowser.Events.trigger).toHaveBeenCalledWith(
|
||||
'pgadmin-bgprocess:created',
|
||||
restoreDialogWrapper
|
||||
);
|
||||
done();
|
||||
}, 0);
|
||||
});
|
||||
|
||||
it('send correct data to server', (done) => {
|
||||
restoreDialogWrapper.callback(event);
|
||||
setTimeout(() => {
|
||||
expect(JSON.parse(dataSentToServer)).toEqual({
|
||||
'some-key': 'some-value',
|
||||
'database': 'some-database-label',
|
||||
});
|
||||
done();
|
||||
}, 0);
|
||||
});
|
||||
});
|
||||
|
||||
context('error creating restore job', () => {
|
||||
beforeEach(() => {
|
||||
networkMock.onPost('/restore/job/10').reply(() => {
|
||||
return [400, {}];
|
||||
});
|
||||
});
|
||||
|
||||
it('creates an alert box', (done) => {
|
||||
restoreDialogWrapper.callback(event);
|
||||
setTimeout(() => {
|
||||
expect(alertifySpy.alert).toHaveBeenCalledWith(
|
||||
'Restore job failed.',
|
||||
undefined
|
||||
);
|
||||
done();
|
||||
}, 0);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('setExtraParameters', () => {
|
||||
let selectedNode;
|
||||
let treeInfo;
|
||||
let model;
|
||||
|
||||
beforeEach(() => {
|
||||
restoreDialogWrapper = new RestoreDialogWrapper(
|
||||
'<div class=\'restore_dialog\'></div>',
|
||||
'restoreDialogTitle',
|
||||
'restore',
|
||||
jquerySpy,
|
||||
pgBrowser,
|
||||
alertifySpy,
|
||||
dialogModelKlassSpy,
|
||||
backform
|
||||
);
|
||||
|
||||
model = new FakeModel();
|
||||
restoreDialogWrapper.view = {
|
||||
model: model,
|
||||
};
|
||||
});
|
||||
|
||||
context('when it is a custom model', () => {
|
||||
beforeEach(() => {
|
||||
model.set('custom', true);
|
||||
treeInfo = {
|
||||
'database': {
|
||||
'_label': 'some-database-label',
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
it('only sets the database', () => {
|
||||
restoreDialogWrapper.setExtraParameters(selectedNode, treeInfo);
|
||||
expect(model.toJSON()).toEqual({
|
||||
'custom': true,
|
||||
'database': 'some-database-label',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('when it is not a custom model', () => {
|
||||
beforeEach(() => {
|
||||
model.set('custom', false);
|
||||
treeInfo = {
|
||||
'database': {
|
||||
'_label': 'some-database-label',
|
||||
},
|
||||
'schema': {
|
||||
'_label': 'some-schema-label',
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
context('when selected node is a schema', () => {
|
||||
it('sets schemas on the model', () => {
|
||||
selectedNode = new TreeNode('schema', {_type: 'schema', _label: 'some-schema-label'}, '');
|
||||
restoreDialogWrapper.setExtraParameters(selectedNode, treeInfo);
|
||||
expect(model.toJSON()).toEqual({
|
||||
custom: false,
|
||||
database: 'some-database-label',
|
||||
schemas: ['some-schema-label'],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('when selected node is a table', () => {
|
||||
it('sets schemas and table on the model', () => {
|
||||
selectedNode = new TreeNode('table', {_type: 'table', _label: 'some-table-label'}, '');
|
||||
restoreDialogWrapper.setExtraParameters(selectedNode, treeInfo);
|
||||
expect(model.toJSON()).toEqual({
|
||||
custom: false,
|
||||
database: 'some-database-label',
|
||||
schemas: ['some-schema-label'],
|
||||
tables: ['some-table-label'],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('when selected node is a function', () => {
|
||||
it('sets schemas and function on the model', () => {
|
||||
selectedNode = new TreeNode('function', {_type: 'function', _label: 'some-function-label'}, '');
|
||||
restoreDialogWrapper.setExtraParameters(selectedNode, treeInfo);
|
||||
expect(model.toJSON()).toEqual({
|
||||
custom: false,
|
||||
database: 'some-database-label',
|
||||
schemas: ['some-schema-label'],
|
||||
functions: ['some-function-label'],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('when selected node is an index', () => {
|
||||
it('sets schemas and index on the model', () => {
|
||||
selectedNode = new TreeNode('index', {_type: 'index', _label: 'some-index-label'}, '');
|
||||
restoreDialogWrapper.setExtraParameters(selectedNode, treeInfo);
|
||||
expect(model.toJSON()).toEqual({
|
||||
custom: false,
|
||||
database: 'some-database-label',
|
||||
schemas: ['some-schema-label'],
|
||||
indexes: ['some-index-label'],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('when selected node is a trigger', () => {
|
||||
it('sets schemas and trigger on the model', () => {
|
||||
selectedNode = new TreeNode('trigger', {_type: 'trigger', _label: 'some-trigger-label'}, '');
|
||||
restoreDialogWrapper.setExtraParameters(selectedNode, treeInfo);
|
||||
expect(model.toJSON()).toEqual({
|
||||
custom: false,
|
||||
database: 'some-database-label',
|
||||
schemas: ['some-schema-label'],
|
||||
triggers: ['some-trigger-label'],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('when selected node is a trigger_func', () => {
|
||||
it('sets schemas and trigger_func on the model', () => {
|
||||
selectedNode = new TreeNode('trigger_func', {_type: 'trigger_func', _label: 'some-trigger_func-label'}, '');
|
||||
restoreDialogWrapper.setExtraParameters(selectedNode, treeInfo);
|
||||
expect(model.toJSON()).toEqual({
|
||||
custom: false,
|
||||
database: 'some-database-label',
|
||||
schemas: ['some-schema-label'],
|
||||
trigger_funcs: ['some-trigger_func-label'],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -7,10 +7,8 @@
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
import filterDialog from 'sources/sqleditor/filter_dialog';
|
||||
// import filterDialogModel from 'sources/sqleditor/filter_dialog_model';
|
||||
|
||||
describe('filterDialog', () => {
|
||||
jasmine.createSpy('sqlEditorController');
|
||||
describe('filterDialog', () => {
|
||||
describe('when using filter dialog', () => {
|
||||
beforeEach(() => {
|
||||
|
271
web/regression/javascript/table/enable_disable_triggers_spec.js
Normal file
271
web/regression/javascript/table/enable_disable_triggers_spec.js
Normal file
@ -0,0 +1,271 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
import axios from 'axios/index';
|
||||
import {
|
||||
enableTriggers,
|
||||
disableTriggers,
|
||||
} from '../../../pgadmin/browser/server_groups/servers/databases/schemas/tables/static/js/enable_disable_triggers';
|
||||
import {TreeFake} from '../tree/tree_fake';
|
||||
import {TreeNode} from '../../../pgadmin/static/js/tree/tree';
|
||||
|
||||
describe('#enableTriggers', () => {
|
||||
let networkMock;
|
||||
let tree;
|
||||
let alertify;
|
||||
let generateUrlSpy;
|
||||
beforeEach(() => {
|
||||
networkMock = new MockAdapter(axios);
|
||||
tree = new TreeFake();
|
||||
const server1 = tree.addNewNode('server1', {_id: 1}, ['<li>server1</li>']);
|
||||
const database1 = tree.addNewNode('database1', {_type: 'database'}, ['<li>database1</li>']);
|
||||
tree.addChild(server1, database1);
|
||||
|
||||
const schema1 = tree.addNewNode('schema1', {_type: 'schema'}, ['<li>schema1</li>']);
|
||||
tree.addChild(database1, schema1);
|
||||
|
||||
const table1 = tree.addNewNode('table1', {_type: 'table'}, ['<li>table1</li>']);
|
||||
tree.addChild(schema1, table1);
|
||||
|
||||
const column1 = tree.addNewNode('column1', {_type: 'column'}, ['<li>column1</li>']);
|
||||
tree.addChild(table1, column1);
|
||||
|
||||
const tableNoData = tree.addNewNode('table-no-data', undefined, ['<li>table-no-data</li>']);
|
||||
tree.addChild(schema1, tableNoData);
|
||||
|
||||
alertify = jasmine.createSpyObj('alertify', ['success', 'error']);
|
||||
generateUrlSpy = jasmine.createSpy('generateUrl');
|
||||
generateUrlSpy.and.returnValue('/some/place');
|
||||
});
|
||||
|
||||
describe('no node is selected', () => {
|
||||
it('does not send the request to the backend', (done) => {
|
||||
networkMock.onAny('.*').reply(200, () => {
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
expect(enableTriggers(tree, alertify, generateUrlSpy, {})).toBe(false);
|
||||
done();
|
||||
}, 0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('a node is selected', () => {
|
||||
describe('node as no data', () => {
|
||||
it('does not send the request to the backend', () => {
|
||||
tree.selectNode([{id: 'table-no-data'}]);
|
||||
|
||||
networkMock.onAny('.*').reply(200, () => {
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
expect(enableTriggers(tree, alertify, generateUrlSpy, {})).toBe(false);
|
||||
}, 0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('node as data', () => {
|
||||
describe('backend responds with success', () => {
|
||||
let networkMockCalledWith;
|
||||
beforeEach(() => {
|
||||
networkMockCalledWith = false;
|
||||
networkMock.onPut(/.*/).reply((configuration) => {
|
||||
networkMockCalledWith = configuration;
|
||||
return [200, {
|
||||
success: 1,
|
||||
info: 'some information',
|
||||
}];
|
||||
});
|
||||
});
|
||||
|
||||
it('displays an alert box with success', (done) => {
|
||||
tree.selectNode([{id: 'table1'}]);
|
||||
enableTriggers(tree, alertify, generateUrlSpy, {});
|
||||
setTimeout(() => {
|
||||
expect(alertify.success).toHaveBeenCalledWith('some information');
|
||||
done();
|
||||
}, 0);
|
||||
});
|
||||
|
||||
it('reloads the node', (done) => {
|
||||
enableTriggers(tree, alertify, generateUrlSpy, {item: [{id: 'table1'}]});
|
||||
setTimeout(() => {
|
||||
expect(tree.selected()).toEqual(['<li>table1</li>']);
|
||||
done();
|
||||
}, 20);
|
||||
});
|
||||
|
||||
it('call backend with the correct parameters', (done) => {
|
||||
enableTriggers(tree, alertify, generateUrlSpy, {item: [{id: 'table1'}]});
|
||||
setTimeout(() => {
|
||||
expect(networkMockCalledWith.data).toEqual(JSON.stringify({enable: 'true'}));
|
||||
done();
|
||||
}, 0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('backend responds with error', () => {
|
||||
beforeEach(() => {
|
||||
networkMock.onPut(/.*/).reply(() => {
|
||||
return [500, {
|
||||
success: 0,
|
||||
errormsg: 'some error message',
|
||||
}];
|
||||
});
|
||||
});
|
||||
|
||||
it('displays an error alert', (done) => {
|
||||
tree.selectNode([{id: 'table1'}]);
|
||||
enableTriggers(tree, alertify, generateUrlSpy, {});
|
||||
setTimeout(() => {
|
||||
expect(alertify.error).toHaveBeenCalledWith('some error message');
|
||||
done();
|
||||
}, 0);
|
||||
});
|
||||
|
||||
it('unload the node', (done) => {
|
||||
enableTriggers(tree, alertify, generateUrlSpy, {item: [{id: 'table1'}]});
|
||||
|
||||
setTimeout(() => {
|
||||
expect(tree.findNodeByDomElement([{id: 'table1'}]).children.length).toBe(0);
|
||||
done();
|
||||
}, 20);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#disableTriggers', () => {
|
||||
let networkMock;
|
||||
let tree;
|
||||
let alertify;
|
||||
let generateUrlSpy;
|
||||
beforeEach(() => {
|
||||
networkMock = new MockAdapter(axios);
|
||||
tree = new TreeFake();
|
||||
const server1 = tree.addNewNode('server1', {_id: 1}, ['<li>server1</li>']);
|
||||
const database1 = new TreeNode('database1', {_type: 'database'}, ['<li>database1</li>']);
|
||||
tree.addChild(server1, database1);
|
||||
|
||||
const schema1 = new TreeNode('schema1', {_type: 'schema'}, ['<li>schema1</li>']);
|
||||
tree.addChild(database1, schema1);
|
||||
|
||||
const table1 = new TreeNode('table1', {_type: 'table'}, ['<li>table1</li>']);
|
||||
tree.addChild(schema1, table1);
|
||||
|
||||
const column1 = new TreeNode('column1', {_type: 'column'}, ['<li>column1</li>']);
|
||||
tree.addChild(table1, column1);
|
||||
|
||||
const tableNoData = new TreeNode('table-no-data', undefined, ['<li>table-no-data</li>']);
|
||||
tree.addChild(schema1, tableNoData);
|
||||
|
||||
alertify = jasmine.createSpyObj('alertify', ['success', 'error']);
|
||||
generateUrlSpy = jasmine.createSpy('generateUrl');
|
||||
generateUrlSpy.and.returnValue('/some/place');
|
||||
});
|
||||
|
||||
describe('no node is selected', () => {
|
||||
it('does not send the request to the backend', (done) => {
|
||||
networkMock.onAny('.*').reply(200, () => {
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
expect(disableTriggers(tree, alertify, generateUrlSpy, {})).toBe(false);
|
||||
done();
|
||||
}, 0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('a node is selected', () => {
|
||||
describe('node as no data', () => {
|
||||
it('does not send the request to the backend', () => {
|
||||
tree.selectNode([{id: 'table-no-data'}]);
|
||||
|
||||
networkMock.onAny('.*').reply(200, () => {
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
expect(disableTriggers(tree, alertify, generateUrlSpy, {})).toBe(false);
|
||||
}, 0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('node as data', () => {
|
||||
describe('backend responds with success', () => {
|
||||
let networkMockCalledWith;
|
||||
beforeEach(() => {
|
||||
networkMockCalledWith = false;
|
||||
networkMock.onPut(/.*/).reply((configuration) => {
|
||||
networkMockCalledWith = configuration;
|
||||
return [200, {
|
||||
success: 1,
|
||||
info: 'some information',
|
||||
}];
|
||||
});
|
||||
});
|
||||
|
||||
it('displays an alert box with success', (done) => {
|
||||
tree.selectNode([{id: 'table1'}]);
|
||||
disableTriggers(tree, alertify, generateUrlSpy, {});
|
||||
setTimeout(() => {
|
||||
expect(alertify.success).toHaveBeenCalledWith('some information');
|
||||
done();
|
||||
}, 0);
|
||||
});
|
||||
|
||||
it('reloads the node', (done) => {
|
||||
disableTriggers(tree, alertify, generateUrlSpy, {item: [{id: 'table1'}]});
|
||||
setTimeout(() => {
|
||||
expect(tree.selected()).toEqual(['<li>table1</li>']);
|
||||
done();
|
||||
}, 20);
|
||||
});
|
||||
|
||||
it('call backend with the correct parameters', (done) => {
|
||||
disableTriggers(tree, alertify, generateUrlSpy, {item: [{id: 'table1'}]});
|
||||
setTimeout(() => {
|
||||
expect(networkMockCalledWith.data).toEqual(JSON.stringify({enable: 'false'}));
|
||||
done();
|
||||
}, 0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('backend responds with error', () => {
|
||||
beforeEach(() => {
|
||||
networkMock.onPut(/.*/).reply(() => {
|
||||
return [500, {
|
||||
success: 0,
|
||||
errormsg: 'some error message',
|
||||
}];
|
||||
});
|
||||
});
|
||||
|
||||
it('displays an error alert', (done) => {
|
||||
tree.selectNode([{id: 'table1'}]);
|
||||
disableTriggers(tree, alertify, generateUrlSpy, {});
|
||||
setTimeout(() => {
|
||||
expect(alertify.error).toHaveBeenCalledWith('some error message');
|
||||
done();
|
||||
}, 0);
|
||||
});
|
||||
|
||||
it('unload the node', (done) => {
|
||||
disableTriggers(tree, alertify, generateUrlSpy, {item: [{id: 'table1'}]});
|
||||
|
||||
setTimeout(() => {
|
||||
expect(tree.findNodeByDomElement([{id: 'table1'}]).children.length).toBe(0);
|
||||
done();
|
||||
}, 20);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
353
web/regression/javascript/tree/pgadmin_tree_node_spec.js
Normal file
353
web/regression/javascript/tree/pgadmin_tree_node_spec.js
Normal file
@ -0,0 +1,353 @@
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
import {
|
||||
getTreeNodeHierarchyFromElement,
|
||||
getTreeNodeHierarchyFromIdentifier,
|
||||
} from '../../../pgadmin/static/js/tree/pgadmin_tree_node';
|
||||
import {TreeNode} from '../../../pgadmin/static/js/tree/tree';
|
||||
import {TreeFake} from './tree_fake';
|
||||
|
||||
const context = describe;
|
||||
|
||||
describe('tree#node#getTreeNodeHierarchy', () => {
|
||||
let browser;
|
||||
let newTree;
|
||||
beforeEach(() => {
|
||||
newTree = new TreeFake();
|
||||
browser = {
|
||||
Nodes: {
|
||||
'special one': {hasId: true},
|
||||
'child special': {hasId: true},
|
||||
'other type': {hasId: true},
|
||||
'table': {hasId: true},
|
||||
'partition': {hasId: true},
|
||||
'no id': {hasId: false},
|
||||
},
|
||||
};
|
||||
browser.treeMenu = newTree;
|
||||
});
|
||||
|
||||
context('getTreeNodeHierarchy is called with aciTreeNode object', () => {
|
||||
describe('When the current node is root element', () => {
|
||||
beforeEach(() => {
|
||||
newTree.addNewNode('root', {
|
||||
'some key': 'some value',
|
||||
'_type': 'special one',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns a object with the element type passed data and priority == 0', () => {
|
||||
const result = getTreeNodeHierarchyFromIdentifier.bind(browser)([{id: 'root'}]);
|
||||
expect(result).toEqual({
|
||||
'special one': {
|
||||
'some key': 'some value',
|
||||
'_type': 'special one',
|
||||
'priority': 0,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('When the current node is not of a known type', () => {
|
||||
beforeEach(() => {
|
||||
newTree.addNewNode('root', {
|
||||
'some key': 'some value',
|
||||
'_type': 'do not exist',
|
||||
}, []);
|
||||
});
|
||||
|
||||
it('returns a empty object', () => {
|
||||
const result = getTreeNodeHierarchyFromIdentifier.bind(browser)('root');
|
||||
expect(result).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
describe('When the current node type has no id', () => {
|
||||
beforeEach(() => {
|
||||
newTree.addNewNode('root', {
|
||||
'some key': 'some value',
|
||||
'_type': 'no id',
|
||||
}, []);
|
||||
});
|
||||
|
||||
it('returns a empty object', () => {
|
||||
const result = getTreeNodeHierarchyFromIdentifier.bind(browser)('root');
|
||||
expect(result).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
describe('When the current node is at the second level', () => {
|
||||
beforeEach(() => {
|
||||
const root = newTree.addNewNode('root', {
|
||||
'some key': 'some value',
|
||||
'_type': 'special one',
|
||||
});
|
||||
const firstChild = new TreeNode('first child', {
|
||||
'some key': 'some other value',
|
||||
'_type': 'child special',
|
||||
}, ['root']);
|
||||
newTree.addChild(root, firstChild);
|
||||
});
|
||||
|
||||
it('returns a empty object', () => {
|
||||
const result = getTreeNodeHierarchyFromIdentifier.bind(browser)([{id: 'first child'}]);
|
||||
expect(result).toEqual({
|
||||
'child special': {
|
||||
'some key': 'some other value',
|
||||
'_type': 'child special',
|
||||
'priority': 0,
|
||||
},
|
||||
'special one': {
|
||||
'some key': 'some value',
|
||||
'_type': 'special one',
|
||||
'priority': -1,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('When tree as "special type"', () => {
|
||||
context('When "special type" have "other type"', () => {
|
||||
context('When "other type" have "special type"', () => {
|
||||
describe('When retrieving lead node', () => {
|
||||
it('does not override previous node type data', () => {
|
||||
const rootNode = newTree.addNewNode('root', {
|
||||
'some key': 'some value',
|
||||
'_type': 'special one',
|
||||
}, []);
|
||||
|
||||
const level1 = new TreeNode('level 1', {
|
||||
'some key': 'some value',
|
||||
'_type': 'other type',
|
||||
});
|
||||
newTree.addChild(rootNode, level1);
|
||||
|
||||
newTree.addChild(level1, new TreeNode('level 2', {
|
||||
'some key': 'expected value',
|
||||
'_type': 'special one',
|
||||
'some other key': 'some other value',
|
||||
}));
|
||||
|
||||
const result = getTreeNodeHierarchyFromIdentifier.bind(browser)([{id: 'level 2'}]);
|
||||
expect(result).toEqual({
|
||||
'special one': {
|
||||
'some key': 'expected value',
|
||||
'_type': 'special one',
|
||||
'some other key': 'some other value',
|
||||
'priority': 0,
|
||||
},
|
||||
'other type': {
|
||||
'some key': 'some value',
|
||||
'_type': 'other type',
|
||||
'priority': -1,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('When tree has table', () => {
|
||||
context('when table has partition', () => {
|
||||
it('returns table with partition parameters', () => {
|
||||
const root = newTree.addNewNode('root', {
|
||||
'some key': 'some value',
|
||||
'_type': 'special one',
|
||||
}, []);
|
||||
const level1 = new TreeNode('level 1', {
|
||||
'some key': 'some value',
|
||||
'_type': 'table',
|
||||
});
|
||||
newTree.addChild(root, level1);
|
||||
newTree.addChild(level1, new TreeNode('level 2', {
|
||||
'some key': 'expected value',
|
||||
'_type': 'partition',
|
||||
'some other key': 'some other value',
|
||||
}));
|
||||
|
||||
const result = getTreeNodeHierarchyFromIdentifier.bind(browser)([{id:'level 2'}]);
|
||||
expect(result).toEqual({
|
||||
'special one': {
|
||||
'some key': 'some value',
|
||||
'_type': 'special one',
|
||||
'priority': -1,
|
||||
},
|
||||
'table': {
|
||||
'some key': 'expected value',
|
||||
'some other key': 'some other value',
|
||||
'_type': 'partition',
|
||||
'priority': 0,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('getTreeNodeHierarchy is called with TreeNode object', () => {
|
||||
let treeNode;
|
||||
describe('When the current node is root element', () => {
|
||||
beforeEach(() => {
|
||||
treeNode = newTree.addNewNode('root', {
|
||||
'some key': 'some value',
|
||||
'_type': 'special one',
|
||||
}, []);
|
||||
});
|
||||
|
||||
it('returns a object with the element type passed data and priority == 0', () => {
|
||||
const result = getTreeNodeHierarchyFromElement(browser, treeNode);
|
||||
expect(result).toEqual({
|
||||
'special one': {
|
||||
'some key': 'some value',
|
||||
'_type': 'special one',
|
||||
'priority': 0,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('When the current node is not of a known type', () => {
|
||||
beforeEach(() => {
|
||||
treeNode = newTree.addNewNode('root', {
|
||||
'some key': 'some value',
|
||||
'_type': 'do not exist',
|
||||
}, []);
|
||||
});
|
||||
|
||||
it('returns a empty object', () => {
|
||||
const result = getTreeNodeHierarchyFromElement(browser, treeNode);
|
||||
expect(result).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
describe('When the current node type has no id', () => {
|
||||
beforeEach(() => {
|
||||
treeNode = newTree.addNewNode('root', {
|
||||
'some key': 'some value',
|
||||
'_type': 'no id',
|
||||
}, []);
|
||||
});
|
||||
|
||||
it('returns a empty object', () => {
|
||||
const result = getTreeNodeHierarchyFromElement(browser, treeNode);
|
||||
expect(result).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
describe('When the current node is at the second level', () => {
|
||||
beforeEach(() => {
|
||||
const root = newTree.addNewNode('root', {
|
||||
'some key': 'some value',
|
||||
'_type': 'special one',
|
||||
}, []);
|
||||
treeNode = new TreeNode('first child', {
|
||||
'some key': 'some other value',
|
||||
'_type': 'child special',
|
||||
});
|
||||
newTree.addChild(root, treeNode);
|
||||
});
|
||||
|
||||
it('returns a empty object', () => {
|
||||
const result = getTreeNodeHierarchyFromElement(browser, treeNode);
|
||||
expect(result).toEqual({
|
||||
'child special': {
|
||||
'some key': 'some other value',
|
||||
'_type': 'child special',
|
||||
'priority': 0,
|
||||
},
|
||||
'special one': {
|
||||
'some key': 'some value',
|
||||
'_type': 'special one',
|
||||
'priority': -1,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('When tree as "special type"', () => {
|
||||
context('When "special type" have "other type"', () => {
|
||||
context('When "other type" have "special type"', () => {
|
||||
describe('When retrieving lead node', () => {
|
||||
it('does not override previous node type data', () => {
|
||||
const root = newTree.addNewNode('root', {
|
||||
'some key': 'some value',
|
||||
'_type': 'special one',
|
||||
}, []);
|
||||
const level1 = new TreeNode('level 1', {
|
||||
'some key': 'some value',
|
||||
'_type': 'other type',
|
||||
});
|
||||
newTree.addChild(root, level1);
|
||||
treeNode = new TreeNode('level 2', {
|
||||
'some key': 'expected value',
|
||||
'_type': 'special one',
|
||||
'some other key': 'some other value',
|
||||
});
|
||||
newTree.addChild(level1, treeNode);
|
||||
|
||||
const result = getTreeNodeHierarchyFromElement(browser, treeNode);
|
||||
expect(result).toEqual({
|
||||
'special one': {
|
||||
'some key': 'expected value',
|
||||
'_type': 'special one',
|
||||
'some other key': 'some other value',
|
||||
'priority': 0,
|
||||
},
|
||||
'other type': {
|
||||
'some key': 'some value',
|
||||
'_type': 'other type',
|
||||
'priority': -1,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('When tree has table', () => {
|
||||
context('when table has partition', () => {
|
||||
it('returns table with partition parameters', () => {
|
||||
const root = newTree.addNewNode('root', {
|
||||
'some key': 'some value',
|
||||
'_type': 'special one',
|
||||
});
|
||||
const level1 = newTree.addNewNode('level 1', {
|
||||
'some key': 'some value',
|
||||
'_type': 'table',
|
||||
});
|
||||
newTree.addChild(root, level1);
|
||||
treeNode = new TreeNode('level 2', {
|
||||
'some key': 'expected value',
|
||||
'_type': 'partition',
|
||||
'some other key': 'some other value',
|
||||
});
|
||||
newTree.addChild(level1, treeNode);
|
||||
|
||||
const result = getTreeNodeHierarchyFromElement(browser, treeNode);
|
||||
expect(result).toEqual({
|
||||
'special one': {
|
||||
'some key': 'some value',
|
||||
'_type': 'special one',
|
||||
'priority': -1,
|
||||
},
|
||||
'table': {
|
||||
'some key': 'expected value',
|
||||
'some other key': 'some other value',
|
||||
'_type': 'partition',
|
||||
'priority': 0,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -10,6 +10,32 @@
|
||||
import {Tree} from '../../../pgadmin/static/js/tree/tree';
|
||||
|
||||
export class TreeFake extends Tree {
|
||||
static build(structure) {
|
||||
let tree = new TreeFake();
|
||||
let rootNode = tree.rootNode;
|
||||
|
||||
if (structure.children !== undefined) {
|
||||
structure.children.forEach((child) => {
|
||||
TreeFake.recursivelyAddNodes(tree, child, rootNode);
|
||||
});
|
||||
}
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
static recursivelyAddNodes(tree, newNode, parent) {
|
||||
let id = newNode.id;
|
||||
let data = newNode.data ? newNode.data : {};
|
||||
let domNode = newNode.domNode ? newNode.domNode : [{id: id}];
|
||||
tree.addNewNode(id, data, domNode, tree.translateTreeNodeIdFromACITree([parent]));
|
||||
|
||||
if (newNode.children !== undefined) {
|
||||
newNode.children.forEach((child) => {
|
||||
TreeFake.recursivelyAddNodes(tree, child, newNode);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.aciTreeToOurTreeTranslator = {};
|
||||
@ -45,7 +71,7 @@ export class TreeFake extends Tree {
|
||||
}
|
||||
|
||||
translateTreeNodeIdFromACITree(aciTreeNode) {
|
||||
if(aciTreeNode === undefined || aciTreeNode[0] === undefined) {
|
||||
if (aciTreeNode === undefined || aciTreeNode[0] === undefined) {
|
||||
return null;
|
||||
}
|
||||
return this.aciTreeToOurTreeTranslator[aciTreeNode[0].id];
|
||||
|
@ -130,6 +130,7 @@ var webpackShimConfig = {
|
||||
'sources/utils': path.join(__dirname, './pgadmin/static/js/utils'),
|
||||
'babel-polyfill': path.join(__dirname, './node_modules/babel-polyfill/dist/polyfill'),
|
||||
'tools': path.join(__dirname, './pgadmin/tools/'),
|
||||
'pgbrowser': path.join(__dirname, './pgadmin/browser/static/js/'),
|
||||
|
||||
// Vendor JS
|
||||
'jquery': path.join(__dirname, './node_modules/jquery/dist/jquery'),
|
||||
|
@ -81,6 +81,8 @@ module.exports = {
|
||||
'pgadmin.alertifyjs': sourcesDir + '/js/alertify.pgadmin.defaults',
|
||||
'pgadmin.backgrid': sourcesDir + '/js/backgrid.pgadmin',
|
||||
'pgadmin.backform': sourcesDir + '/js/backform.pgadmin',
|
||||
'pgbrowser': path.resolve(__dirname, 'regression/javascript/fake_browser'),
|
||||
'pgadmin.schema.dir': path.resolve(__dirname, 'pgadmin/browser/server_groups/servers/databases/schemas/static/js'),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user