Port Restore dialog to React. Fixes #7018
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 61 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 23 KiB |
@ -13,6 +13,7 @@ New features
|
|||||||
Housekeeping
|
Housekeeping
|
||||||
************
|
************
|
||||||
|
|
||||||
|
| `Issue #7018 <https://redmine.postgresql.org/issues/7018>`_ - Port Restore dialog to React.
|
||||||
|
|
||||||
Bug fixes
|
Bug fixes
|
||||||
*********
|
*********
|
||||||
|
@ -509,7 +509,7 @@ define('pgadmin.browser.node', [
|
|||||||
w: (!_.isUndefined(width) && !_.isNull(width)) ? width :
|
w: (!_.isUndefined(width) && !_.isNull(width)) ? width :
|
||||||
(screen.width < 700 ? screen.width * 0.95 : screen.width * 0.5),
|
(screen.width < 700 ? screen.width * 0.95 : screen.width * 0.5),
|
||||||
h: (!_.isUndefined(height) && !_.isNull(height)) ? height :
|
h: (!_.isUndefined(height) && !_.isNull(height)) ? height :
|
||||||
(screen.height < 500 ? screen.height * 0.95 : screen.height * 0.5),
|
(screen.height < 500 ? screen.height * 0.95 : screen.height * 0.35),
|
||||||
x: (screen.width < 700 ? '2%' : '25%'),
|
x: (screen.width < 700 ? '2%' : '25%'),
|
||||||
y: (screen.height < 500 ? '2%' : '25%'),
|
y: (screen.height < 500 ? '2%' : '25%'),
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
//
|
//
|
||||||
//////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
import {RestoreDialogWrapper} from '../../../tools/restore/static/js/restore_dialog_wrapper';
|
|
||||||
import SearchObjectsDialogWrapper from '../../../tools/search_objects/static/js/search_objects_dialog_wrapper';
|
import SearchObjectsDialogWrapper from '../../../tools/search_objects/static/js/search_objects_dialog_wrapper';
|
||||||
|
|
||||||
export class DialogFactory {
|
export class DialogFactory {
|
||||||
@ -30,16 +29,6 @@ export class DialogFactory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createRestoreDialog(dialogTitle, typeOfDialog) {
|
|
||||||
return new RestoreDialogWrapper(
|
|
||||||
this.dialogContainerSelector, dialogTitle, typeOfDialog,
|
|
||||||
this.jquery,
|
|
||||||
this.pgBrowser,
|
|
||||||
this.alertify,
|
|
||||||
this.dialogModel,
|
|
||||||
this.backform);
|
|
||||||
}
|
|
||||||
|
|
||||||
createSearchObjectsDialog(dialogTitle, typeOfDialog) {
|
createSearchObjectsDialog(dialogTitle, typeOfDialog) {
|
||||||
return new SearchObjectsDialogWrapper(
|
return new SearchObjectsDialogWrapper(
|
||||||
this.dialogContainerSelector, dialogTitle, typeOfDialog,
|
this.dialogContainerSelector, dialogTitle, typeOfDialog,
|
||||||
|
@ -167,6 +167,10 @@
|
|||||||
border-bottom: $panel-border;
|
border-bottom: $panel-border;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.wcFloating .wcFrameTitleBar.wcNotMoveable {
|
||||||
|
cursor: move; //overriding the existing cursor behavior for not moveable panels
|
||||||
|
}
|
||||||
|
|
||||||
.wcTabIcon {
|
.wcTabIcon {
|
||||||
background-position: center;
|
background-position: center;
|
||||||
padding: 0rem 0.75rem;
|
padding: 0rem 0.75rem;
|
||||||
|
@ -11,6 +11,8 @@ import { getNodeListByName, getNodeAjaxOptions } from '../../../../browser/stati
|
|||||||
import BackupSchema, {getSectionSchema, getTypeObjSchema, getSaveOptSchema, getQueryOptionSchema, getDisabledOptionSchema, getMiscellaneousSchema} from './backup.ui';
|
import BackupSchema, {getSectionSchema, getTypeObjSchema, getSaveOptSchema, getQueryOptionSchema, getDisabledOptionSchema, getMiscellaneousSchema} from './backup.ui';
|
||||||
import BackupGlobalSchema, {getMiscellaneousSchema as getMiscellaneousGlobalSchema} from './backupGlobal.ui';
|
import BackupGlobalSchema, {getMiscellaneousSchema as getMiscellaneousGlobalSchema} from './backupGlobal.ui';
|
||||||
import Notify from '../../../../static/js/helpers/Notifier';
|
import Notify from '../../../../static/js/helpers/Notifier';
|
||||||
|
import getApiInstance from 'sources/api_instance';
|
||||||
|
import {retrieveAncestorOfTypeServer} from 'sources/tree/tree_utils';
|
||||||
|
|
||||||
// Backup dialog
|
// Backup dialog
|
||||||
define([
|
define([
|
||||||
@ -182,6 +184,12 @@ define([
|
|||||||
pgBrowser.Events.trigger('pgadmin-bgprocess:created', dialog);
|
pgBrowser.Events.trigger('pgadmin-bgprocess:created', dialog);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
url_for_utility_exists(id, params){
|
||||||
|
return url_for('backup.utility_exists', {
|
||||||
|
'sid': id,
|
||||||
|
'backup_obj_type': params == null ? 'objects' : 'servers',
|
||||||
|
});
|
||||||
|
},
|
||||||
showBackupDialog: function(schema, item, j, data, panel, typeOfDialog, serverIdentifier, extraData) {
|
showBackupDialog: function(schema, item, j, data, panel, typeOfDialog, serverIdentifier, extraData) {
|
||||||
if(schema) {
|
if(schema) {
|
||||||
let treeNodeInfo = pgBrowser.tree.getTreeNodeHierarchy(item);
|
let treeNodeInfo = pgBrowser.tree.getTreeNodeHierarchy(item);
|
||||||
@ -204,23 +212,42 @@ define([
|
|||||||
},
|
},
|
||||||
// Callback to draw Backup Dialog for objects
|
// Callback to draw Backup Dialog for objects
|
||||||
backupObjects: function(action, treeItem) {
|
backupObjects: function(action, treeItem) {
|
||||||
pgBrowser.Node.registerUtilityPanel();
|
var that = this;
|
||||||
var panel = pgBrowser.Node.addUtilityPanel();
|
|
||||||
var tree = pgBrowser.tree,
|
var tree = pgBrowser.tree,
|
||||||
i = treeItem || tree.selected(),
|
i = treeItem || tree.selected(),
|
||||||
data = i ? tree.itemData(i) : undefined,
|
data = i ? tree.itemData(i) : undefined;
|
||||||
j = panel.$container.find('.obj_properties').first();
|
|
||||||
|
|
||||||
var schema = this.getUISchema(treeItem, 'backup_objects');
|
const serverInformation = retrieveAncestorOfTypeServer(pgBrowser, treeItem, gettext('Backup Error')),
|
||||||
panel.title(`Backup (${pgBrowser.Nodes[data._type].label}: ${data.label})`);
|
sid = serverInformation._type == 'database' ? serverInformation._pid : serverInformation._id,
|
||||||
panel.focus();
|
api = getApiInstance(),
|
||||||
|
utility_exists_url = that.url_for_utility_exists(sid);
|
||||||
|
|
||||||
var typeOfDialog = 'backup_objects';
|
return api({
|
||||||
var serverIdentifier = this.retrieveServerIdentifier();
|
url: utility_exists_url,
|
||||||
|
method: 'GET'
|
||||||
|
}).then((res)=>{
|
||||||
|
if (!res.data.success) {
|
||||||
|
Notify.alert(
|
||||||
|
gettext('Utility not found'),
|
||||||
|
gettext(res.data.errormsg)
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var extraData = this.setExtraParameters(typeOfDialog);
|
pgBrowser.Node.registerUtilityPanel();
|
||||||
this.showBackupDialog(schema, treeItem, j, data, panel, typeOfDialog, serverIdentifier, extraData);
|
var panel = pgBrowser.Node.addUtilityPanel(),
|
||||||
|
j = panel.$container.find('.obj_properties').first();
|
||||||
|
|
||||||
|
var schema = that.getUISchema(treeItem, 'backup_objects');
|
||||||
|
panel.title(gettext(`Backup (${pgBrowser.Nodes[data._type].label}: ${data.label})`));
|
||||||
|
panel.focus();
|
||||||
|
|
||||||
|
var typeOfDialog = 'backup_objects',
|
||||||
|
serverIdentifier = that.retrieveServerIdentifier(),
|
||||||
|
extraData = that.setExtraParameters(typeOfDialog);
|
||||||
|
|
||||||
|
that.showBackupDialog(schema, treeItem, j, data, panel, typeOfDialog, serverIdentifier, extraData);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
getUISchema: function(treeItem, backupType) {
|
getUISchema: function(treeItem, backupType) {
|
||||||
let treeNodeInfo = pgBrowser.tree.getTreeNodeHierarchy(treeItem);
|
let treeNodeInfo = pgBrowser.tree.getTreeNodeHierarchy(treeItem);
|
||||||
|
@ -7,16 +7,18 @@
|
|||||||
//
|
//
|
||||||
//////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
import { getNodeListByName } from '../../../../browser/static/js/node_ajax';
|
||||||
|
import {getUtilityView} from '../../../../browser/static/js/utility_view';
|
||||||
|
import Notify from '../../../../static/js/helpers/Notifier';
|
||||||
|
import getApiInstance from 'sources/api_instance';
|
||||||
|
import {retrieveAncestorOfTypeServer} from 'sources/tree/tree_utils';
|
||||||
|
import RestoreSchema, {getRestoreSaveOptSchema, getRestoreQueryOptionSchema, getRestoreDisableOptionSchema, getRestoreMiscellaneousSchema, getRestoreTypeObjSchema, getRestoreSectionSchema} from './restore.ui';
|
||||||
|
|
||||||
define('tools.restore', [
|
define('tools.restore', [
|
||||||
'sources/gettext', 'sources/url_for', 'jquery', 'underscore', 'backbone',
|
'sources/gettext', 'sources/url_for', 'pgadmin.browser',
|
||||||
'pgadmin.alertifyjs', 'pgadmin.browser',
|
'tools/restore/static/js/menu_utils', 'sources/nodes/supported_database_node',
|
||||||
'pgadmin.backgrid', 'pgadmin.backform', 'sources/utils',
|
|
||||||
'tools/restore/static/js/menu_utils',
|
|
||||||
'sources/nodes/supported_database_node',
|
|
||||||
'tools/restore/static/js/restore_dialog',
|
|
||||||
], function(
|
], function(
|
||||||
gettext, url_for, $, _, Backbone, alertify, pgBrowser, Backgrid, Backform,
|
gettext, url_for, pgBrowser, menuUtils, supportedNodes
|
||||||
commonUtils, menuUtils, supportedNodes, restoreDialog
|
|
||||||
) {
|
) {
|
||||||
|
|
||||||
// if module is already initialized, refer to that.
|
// if module is already initialized, refer to that.
|
||||||
@ -24,360 +26,6 @@ define('tools.restore', [
|
|||||||
return pgBrowser.Restore;
|
return pgBrowser.Restore;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Restore Model (Objects like Database/Schema/Table)
|
|
||||||
var RestoreObjectModel = Backbone.Model.extend({
|
|
||||||
idAttribute: 'id',
|
|
||||||
defaults: {
|
|
||||||
custom: false,
|
|
||||||
file: undefined,
|
|
||||||
role: undefined,
|
|
||||||
format: 'custom',
|
|
||||||
verbose: true,
|
|
||||||
blobs: true,
|
|
||||||
encoding: undefined,
|
|
||||||
database: undefined,
|
|
||||||
schemas: undefined,
|
|
||||||
tables: undefined,
|
|
||||||
functions: undefined,
|
|
||||||
triggers: undefined,
|
|
||||||
trigger_funcs: undefined,
|
|
||||||
indexes: undefined,
|
|
||||||
},
|
|
||||||
|
|
||||||
// Default values!
|
|
||||||
initialize: function(attrs) {
|
|
||||||
// Set default options according to node type selection by user
|
|
||||||
var node_type = attrs.node_data.type;
|
|
||||||
|
|
||||||
if (node_type) {
|
|
||||||
// Only_Schema option
|
|
||||||
if (node_type === 'function' || node_type === 'index' ||
|
|
||||||
node_type === 'trigger') {
|
|
||||||
this.set({
|
|
||||||
'only_schema': true,
|
|
||||||
}, {
|
|
||||||
silent: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only_Data option
|
|
||||||
if (node_type === 'table') {
|
|
||||||
this.set({
|
|
||||||
'only_data': true,
|
|
||||||
}, {
|
|
||||||
silent: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clean option
|
|
||||||
if (node_type === 'function' || node_type === 'trigger_function') {
|
|
||||||
this.set({
|
|
||||||
'clean': true,
|
|
||||||
}, {
|
|
||||||
silent: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Backbone.Model.prototype.initialize.apply(this, arguments);
|
|
||||||
},
|
|
||||||
schema: [{
|
|
||||||
id: 'format',
|
|
||||||
label: gettext('Format'),
|
|
||||||
type: 'text',
|
|
||||||
disabled: false,
|
|
||||||
control: 'select2',
|
|
||||||
select2: {
|
|
||||||
allowClear: false,
|
|
||||||
width: '100%',
|
|
||||||
},
|
|
||||||
options: [{
|
|
||||||
label: gettext('Custom or tar'),
|
|
||||||
value: 'custom',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: gettext('Directory'),
|
|
||||||
value: 'directory',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}, {
|
|
||||||
id: 'file',
|
|
||||||
label: gettext('Filename'),
|
|
||||||
type: 'text',
|
|
||||||
disabled: false,
|
|
||||||
control: Backform.FileControl.extend({
|
|
||||||
render: function() {
|
|
||||||
var attributes = this.model.toJSON();
|
|
||||||
if (attributes.format == 'directory') {
|
|
||||||
this.field.attributes.dialog_type = 'select_folder';
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.field.attributes.dialog_type = 'select_file';
|
|
||||||
}
|
|
||||||
|
|
||||||
Backform.InputControl.prototype.render.apply(this, arguments);
|
|
||||||
return this;
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
dialog_type: 'select_file',
|
|
||||||
supp_types: ['*', 'backup', 'sql', 'patch'],
|
|
||||||
deps: ['format'],
|
|
||||||
}, {
|
|
||||||
id: 'no_of_jobs',
|
|
||||||
label: gettext('Number of jobs'),
|
|
||||||
type: 'int',
|
|
||||||
}, {
|
|
||||||
id: 'role',
|
|
||||||
label: gettext('Role name'),
|
|
||||||
control: 'node-list-by-name',
|
|
||||||
node: 'role',
|
|
||||||
select2: {
|
|
||||||
allowClear: false,
|
|
||||||
},
|
|
||||||
}, {
|
|
||||||
type: 'nested',
|
|
||||||
control: 'fieldset',
|
|
||||||
label: gettext('Sections'),
|
|
||||||
group: gettext('Restore options'),
|
|
||||||
contentClass: 'row',
|
|
||||||
schema: [{
|
|
||||||
id: 'pre_data',
|
|
||||||
label: gettext('Pre-data'),
|
|
||||||
type: 'switch',
|
|
||||||
extraToggleClasses: 'pg-el-sm-6',
|
|
||||||
controlLabelClassName: 'control-label pg-el-sm-5 pg-el-12',
|
|
||||||
controlsClassName: 'pgadmin-controls pg-el-sm-7 pg-el-12',
|
|
||||||
group: gettext('Sections'),
|
|
||||||
deps: ['only_data', 'only_schema'],
|
|
||||||
disabled: function(m) {
|
|
||||||
return this.node.type !== 'function' && this.node.type !== 'table' &&
|
|
||||||
this.node.type !== 'trigger' &&
|
|
||||||
this.node.type !== 'trigger_function' &&
|
|
||||||
(m.get('only_data') || m.get('only_schema'));
|
|
||||||
},
|
|
||||||
}, {
|
|
||||||
id: 'data',
|
|
||||||
label: gettext('Data'),
|
|
||||||
type: 'switch',
|
|
||||||
extraToggleClasses: 'pg-el-sm-6',
|
|
||||||
controlLabelClassName: 'control-label pg-el-sm-5 pg-el-12',
|
|
||||||
controlsClassName: 'pgadmin-controls pg-el-sm-7 pg-el-12',
|
|
||||||
group: gettext('Sections'),
|
|
||||||
deps: ['only_data', 'only_schema'],
|
|
||||||
disabled: function(m) {
|
|
||||||
return this.node.type !== 'function' && this.node.type !== 'table' &&
|
|
||||||
this.node.type !== 'trigger' &&
|
|
||||||
this.node.type !== 'trigger_function' &&
|
|
||||||
(m.get('only_data') || m.get('only_schema'));
|
|
||||||
},
|
|
||||||
}, {
|
|
||||||
id: 'post_data',
|
|
||||||
label: gettext('Post-data'),
|
|
||||||
type: 'switch',
|
|
||||||
extraToggleClasses: 'pg-el-sm-6',
|
|
||||||
controlLabelClassName: 'control-label pg-el-sm-5 pg-el-12',
|
|
||||||
controlsClassName: 'pgadmin-controls pg-el-sm-7 pg-el-12',
|
|
||||||
group: gettext('Sections'),
|
|
||||||
deps: ['only_data', 'only_schema'],
|
|
||||||
disabled: function(m) {
|
|
||||||
return this.node.type !== 'function' && this.node.type !== 'table' &&
|
|
||||||
this.node.type !== 'trigger' &&
|
|
||||||
this.node.type !== 'trigger_function' &&
|
|
||||||
(m.get('only_data') || m.get('only_schema'));
|
|
||||||
},
|
|
||||||
}],
|
|
||||||
}, {
|
|
||||||
type: 'nested',
|
|
||||||
control: 'fieldset',
|
|
||||||
label: gettext('Type of objects'),
|
|
||||||
group: gettext('Restore options'),
|
|
||||||
contentClass: 'row',
|
|
||||||
schema: [{
|
|
||||||
id: 'only_data',
|
|
||||||
label: gettext('Only data'),
|
|
||||||
type: 'switch',
|
|
||||||
extraToggleClasses: 'pg-el-sm-6',
|
|
||||||
controlLabelClassName: 'control-label pg-el-sm-5 pg-el-12',
|
|
||||||
controlsClassName: 'pgadmin-controls pg-el-sm-7 pg-el-12',
|
|
||||||
group: gettext('Type of objects'),
|
|
||||||
deps: ['pre_data', 'data', 'post_data', 'only_schema'],
|
|
||||||
disabled: function(m) {
|
|
||||||
return (this.node.type !== 'database' && this.node.type !== 'schema') ||
|
|
||||||
(m.get('pre_data') ||
|
|
||||||
m.get('data') ||
|
|
||||||
m.get('post_data') ||
|
|
||||||
m.get('only_schema')
|
|
||||||
);
|
|
||||||
},
|
|
||||||
}, {
|
|
||||||
id: 'only_schema',
|
|
||||||
label: gettext('Only schema'),
|
|
||||||
type: 'switch',
|
|
||||||
extraToggleClasses: 'pg-el-sm-6',
|
|
||||||
controlLabelClassName: 'control-label pg-el-sm-5 pg-el-12',
|
|
||||||
controlsClassName: 'pgadmin-controls pg-el-sm-7 pg-el-12',
|
|
||||||
group: gettext('Type of objects'),
|
|
||||||
deps: ['pre_data', 'data', 'post_data', 'only_data'],
|
|
||||||
disabled: function(m) {
|
|
||||||
return (this.node.type !== 'database' && this.node.type !== 'schema') ||
|
|
||||||
(m.get('pre_data') ||
|
|
||||||
m.get('data') ||
|
|
||||||
m.get('post_data') ||
|
|
||||||
m.get('only_data')
|
|
||||||
);
|
|
||||||
},
|
|
||||||
}],
|
|
||||||
}, {
|
|
||||||
type: 'nested',
|
|
||||||
control: 'fieldset',
|
|
||||||
label: gettext('Do not save'),
|
|
||||||
group: gettext('Restore options'),
|
|
||||||
contentClass: 'row',
|
|
||||||
schema: [{
|
|
||||||
id: 'dns_owner',
|
|
||||||
label: gettext('Owner'),
|
|
||||||
type: 'switch',
|
|
||||||
extraToggleClasses: 'pg-el-sm-6',
|
|
||||||
controlLabelClassName: 'control-label pg-el-sm-5 pg-el-12',
|
|
||||||
controlsClassName: 'pgadmin-controls pg-el-sm-7 pg-el-12',
|
|
||||||
disabled: false,
|
|
||||||
group: gettext('Do not save'),
|
|
||||||
}, {
|
|
||||||
id: 'dns_privilege',
|
|
||||||
label: gettext('Privilege'),
|
|
||||||
type: 'switch',
|
|
||||||
extraToggleClasses: 'pg-el-sm-6',
|
|
||||||
controlLabelClassName: 'control-label pg-el-sm-5 pg-el-12',
|
|
||||||
controlsClassName: 'pgadmin-controls pg-el-sm-7 pg-el-12',
|
|
||||||
disabled: false,
|
|
||||||
group: gettext('Do not save'),
|
|
||||||
}, {
|
|
||||||
id: 'dns_tablespace',
|
|
||||||
label: gettext('Tablespace'),
|
|
||||||
type: 'switch',
|
|
||||||
extraToggleClasses: 'pg-el-sm-6',
|
|
||||||
controlLabelClassName: 'control-label pg-el-sm-5 pg-el-12',
|
|
||||||
controlsClassName: 'pgadmin-controls pg-el-sm-7 pg-el-12',
|
|
||||||
disabled: false,
|
|
||||||
group: gettext('Do not save'),
|
|
||||||
}, {
|
|
||||||
id: 'no_comments',
|
|
||||||
label: gettext('Comments'),
|
|
||||||
type: 'switch',
|
|
||||||
extraToggleClasses: 'pg-el-sm-6',
|
|
||||||
controlLabelClassName: 'control-label pg-el-sm-5 pg-el-12',
|
|
||||||
controlsClassName: 'pgadmin-controls pg-el-sm-7 pg-el-12',
|
|
||||||
disabled: false,
|
|
||||||
group: gettext('Do not save'),
|
|
||||||
visible: function() {
|
|
||||||
var t = pgBrowser.tree,
|
|
||||||
i = t.selected(),
|
|
||||||
d = i ? t.itemData(i) : undefined,
|
|
||||||
s = _.isUndefined(d) ? undefined : pgBrowser.tree.getTreeNodeHierarchy(i)['server'];
|
|
||||||
|
|
||||||
return _.isUndefined(s) ? false : s.version >= 110000;
|
|
||||||
},
|
|
||||||
}],
|
|
||||||
}, {
|
|
||||||
type: 'nested',
|
|
||||||
control: 'fieldset',
|
|
||||||
label: gettext('Queries'),
|
|
||||||
group: gettext('Restore options'),
|
|
||||||
contentClass: 'row',
|
|
||||||
schema: [{
|
|
||||||
id: 'include_create_database',
|
|
||||||
label: gettext('Include CREATE DATABASE statement'),
|
|
||||||
type: 'switch',
|
|
||||||
extraToggleClasses: 'pg-el-sm-6',
|
|
||||||
controlLabelClassName: 'control-label pg-el-sm-5 pg-el-12',
|
|
||||||
controlsClassName: 'pgadmin-controls pg-el-sm-7 pg-el-12',
|
|
||||||
disabled: false,
|
|
||||||
group: gettext('Queries'),
|
|
||||||
}, {
|
|
||||||
id: 'clean',
|
|
||||||
label: gettext('Clean before restore'),
|
|
||||||
type: 'switch',
|
|
||||||
extraToggleClasses: 'pg-el-sm-6',
|
|
||||||
controlLabelClassName: 'control-label pg-el-sm-5 pg-el-12',
|
|
||||||
controlsClassName: 'pgadmin-controls pg-el-sm-7 pg-el-12',
|
|
||||||
group: gettext('Queries'),
|
|
||||||
disabled: function() {
|
|
||||||
return this.node.type === 'function' ||
|
|
||||||
this.node.type === 'trigger_function';
|
|
||||||
},
|
|
||||||
}, {
|
|
||||||
id: 'single_transaction',
|
|
||||||
label: gettext('Single transaction'),
|
|
||||||
type: 'switch',
|
|
||||||
extraToggleClasses: 'pg-el-sm-6',
|
|
||||||
controlLabelClassName: 'control-label pg-el-sm-5 pg-el-12',
|
|
||||||
controlsClassName: 'pgadmin-controls pg-el-sm-7 pg-el-12',
|
|
||||||
disabled: false,
|
|
||||||
group: gettext('Queries'),
|
|
||||||
}],
|
|
||||||
}, {
|
|
||||||
type: 'nested',
|
|
||||||
control: 'fieldset',
|
|
||||||
label: gettext('Disable'),
|
|
||||||
group: gettext('Restore options'),
|
|
||||||
contentClass: 'row',
|
|
||||||
schema: [{
|
|
||||||
id: 'disable_trigger',
|
|
||||||
label: gettext('Trigger'),
|
|
||||||
type: 'switch',
|
|
||||||
extraToggleClasses: 'pg-el-sm-6',
|
|
||||||
controlLabelClassName: 'control-label pg-el-sm-5 pg-el-12',
|
|
||||||
controlsClassName: 'pgadmin-controls pg-el-sm-7 pg-el-12',
|
|
||||||
group: gettext('Disable'),
|
|
||||||
}, {
|
|
||||||
id: 'no_data_fail_table',
|
|
||||||
label: gettext('No data for Failed Tables'),
|
|
||||||
type: 'switch',
|
|
||||||
extraToggleClasses: 'pg-el-sm-6',
|
|
||||||
controlLabelClassName: 'control-label pg-el-sm-5 pg-el-12',
|
|
||||||
controlsClassName: 'pgadmin-controls pg-el-sm-7 pg-el-12',
|
|
||||||
disabled: false,
|
|
||||||
group: gettext('Disable'),
|
|
||||||
}],
|
|
||||||
}, {
|
|
||||||
type: 'nested',
|
|
||||||
control: 'fieldset',
|
|
||||||
label: gettext('Miscellaneous / Behavior'),
|
|
||||||
group: gettext('Restore options'),
|
|
||||||
contentClass: 'row',
|
|
||||||
schema: [{
|
|
||||||
id: 'verbose',
|
|
||||||
label: gettext('Verbose messages'),
|
|
||||||
type: 'switch',
|
|
||||||
extraToggleClasses: 'pg-el-sm-6',
|
|
||||||
controlLabelClassName: 'control-label pg-el-sm-5 pg-el-12',
|
|
||||||
controlsClassName: 'pgadmin-controls pg-el-sm-7 pg-el-12',
|
|
||||||
disabled: false,
|
|
||||||
group: gettext('Miscellaneous / Behavior'),
|
|
||||||
}, {
|
|
||||||
id: 'use_set_session_auth',
|
|
||||||
label: gettext('Use SET SESSION AUTHORIZATION'),
|
|
||||||
type: 'switch',
|
|
||||||
extraToggleClasses: 'pg-el-sm-6',
|
|
||||||
controlLabelClassName: 'control-label pg-el-sm-5 pg-el-12',
|
|
||||||
controlsClassName: 'pgadmin-controls pg-el-sm-7 pg-el-12',
|
|
||||||
disabled: false,
|
|
||||||
group: gettext('Miscellaneous / Behavior'),
|
|
||||||
}, {
|
|
||||||
id: 'exit_on_error',
|
|
||||||
label: gettext('Exit on error'),
|
|
||||||
type: 'switch',
|
|
||||||
extraToggleClasses: 'pg-el-sm-6',
|
|
||||||
controlLabelClassName: 'control-label pg-el-sm-5 pg-el-12',
|
|
||||||
controlsClassName: 'pgadmin-controls pg-el-sm-7 pg-el-12',
|
|
||||||
disabled: false,
|
|
||||||
group: gettext('Miscellaneous / Behavior'),
|
|
||||||
}],
|
|
||||||
}],
|
|
||||||
validate: function() {
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create an Object Restore of pgBrowser class
|
// Create an Object Restore of pgBrowser class
|
||||||
pgBrowser.Restore = {
|
pgBrowser.Restore = {
|
||||||
init: function() {
|
init: function() {
|
||||||
@ -391,7 +39,7 @@ define('tools.restore', [
|
|||||||
name: 'restore_object',
|
name: 'restore_object',
|
||||||
module: this,
|
module: this,
|
||||||
applies: ['tools'],
|
applies: ['tools'],
|
||||||
callback: 'restore_objects',
|
callback: 'restoreObjects',
|
||||||
priority: 2,
|
priority: 2,
|
||||||
label: gettext('Restore...'),
|
label: gettext('Restore...'),
|
||||||
icon: 'fa fa-upload',
|
icon: 'fa fa-upload',
|
||||||
@ -410,8 +58,8 @@ define('tools.restore', [
|
|||||||
node: menuUtils.restoreSupportedNodes[idx],
|
node: menuUtils.restoreSupportedNodes[idx],
|
||||||
module: this,
|
module: this,
|
||||||
applies: ['context'],
|
applies: ['context'],
|
||||||
callback: 'restore_objects',
|
callback: 'restoreObjects',
|
||||||
priority: 13,
|
priority: 2,
|
||||||
label: gettext('Restore...'),
|
label: gettext('Restore...'),
|
||||||
icon: 'fa fa-upload',
|
icon: 'fa fa-upload',
|
||||||
enable: supportedNodes.enabled.bind(
|
enable: supportedNodes.enabled.bind(
|
||||||
@ -423,12 +71,109 @@ define('tools.restore', [
|
|||||||
pgBrowser.add_menus(menus);
|
pgBrowser.add_menus(menus);
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
// Callback to draw Backup Dialog for objects
|
getUISchema: function(treeItem) {
|
||||||
restore_objects: function(action, treeItem) {
|
let treeNodeInfo = pgBrowser.tree.getTreeNodeHierarchy(treeItem);
|
||||||
let dialog = new restoreDialog.RestoreDialog(
|
const selectedNode = pgBrowser.tree.selected();
|
||||||
pgBrowser, $, alertify, RestoreObjectModel
|
let itemNodeData = pgBrowser.tree.findNodeByDomElement(selectedNode).getData();
|
||||||
|
|
||||||
|
return new RestoreSchema(
|
||||||
|
()=>getRestoreSectionSchema({selectedNodeType: itemNodeData._type}),
|
||||||
|
()=>getRestoreTypeObjSchema({selectedNodeType: itemNodeData._type}),
|
||||||
|
()=>getRestoreSaveOptSchema({nodeInfo: treeNodeInfo}),
|
||||||
|
()=>getRestoreQueryOptionSchema({nodeInfo: treeNodeInfo}),
|
||||||
|
()=>getRestoreDisableOptionSchema({nodeInfo: treeNodeInfo}),
|
||||||
|
()=>getRestoreMiscellaneousSchema({nodeInfo: treeNodeInfo}),
|
||||||
|
{
|
||||||
|
role: ()=>getNodeListByName('role', treeNodeInfo, itemNodeData)
|
||||||
|
},
|
||||||
|
treeNodeInfo,
|
||||||
|
pgBrowser
|
||||||
);
|
);
|
||||||
dialog.draw(action, treeItem, pgBrowser.stdW.calc(pgBrowser.stdW.md), pgBrowser.stdH.calc(pgBrowser.stdH.md));
|
},
|
||||||
|
saveCallBack: function(data, dialog) {
|
||||||
|
if(data.errormsg) {
|
||||||
|
Notify.alert(
|
||||||
|
gettext('Utility not found'),
|
||||||
|
gettext(data.errormsg)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
pgBrowser.Events.trigger('pgadmin-bgprocess:created', dialog);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setExtraParameters: function(treeInfo, nodeData) {
|
||||||
|
var extraData = {};
|
||||||
|
extraData['database'] = treeInfo.database._label;
|
||||||
|
|
||||||
|
if('schema' in treeInfo) {
|
||||||
|
extraData['schemas'] = treeInfo.schema._label;
|
||||||
|
}
|
||||||
|
|
||||||
|
if('table' in treeInfo) {
|
||||||
|
extraData['tables'] = [nodeData._label];
|
||||||
|
}
|
||||||
|
|
||||||
|
if('function' in treeInfo) {
|
||||||
|
extraData['functions'] = [nodeData._label];
|
||||||
|
}
|
||||||
|
return extraData;
|
||||||
|
},
|
||||||
|
url_for_utility_exists: function(id){
|
||||||
|
return url_for('restore.utility_exists', {
|
||||||
|
'sid': id,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
restoreObjects: function(action, treeItem) {
|
||||||
|
var that = this,
|
||||||
|
tree = pgBrowser.tree,
|
||||||
|
i = treeItem || tree.selected(),
|
||||||
|
data = i ? tree.itemData(i) : undefined,
|
||||||
|
treeNodeInfo = pgBrowser.tree.getTreeNodeHierarchy(treeItem);
|
||||||
|
|
||||||
|
const serverInformation = retrieveAncestorOfTypeServer(pgBrowser, treeItem, gettext('Restore Error')),
|
||||||
|
sid = serverInformation._type == 'database' ? serverInformation._pid : serverInformation._id,
|
||||||
|
api = getApiInstance(),
|
||||||
|
utility_exists_url = that.url_for_utility_exists(sid);
|
||||||
|
|
||||||
|
return api({
|
||||||
|
url: utility_exists_url,
|
||||||
|
method: 'GET'
|
||||||
|
}).then((res)=>{
|
||||||
|
if (!res.data.success) {
|
||||||
|
Notify.alert(
|
||||||
|
gettext('Utility not found'),
|
||||||
|
gettext(res.data.errormsg)
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pgBrowser.Node.registerUtilityPanel();
|
||||||
|
var panel = pgBrowser.Node.addUtilityPanel(),
|
||||||
|
j = panel.$container.find('.obj_properties').first();
|
||||||
|
|
||||||
|
var schema = that.getUISchema(treeItem);
|
||||||
|
panel.title(gettext(`Restore (${pgBrowser.Nodes[data._type].label}: ${data.label})`));
|
||||||
|
panel.focus();
|
||||||
|
|
||||||
|
let urlShortcut = 'restore.create_job',
|
||||||
|
baseUrl = url_for(urlShortcut, {
|
||||||
|
'sid': sid,
|
||||||
|
}),
|
||||||
|
extraData = that.setExtraParameters(treeNodeInfo, data);
|
||||||
|
|
||||||
|
var sqlHelpUrl = 'restore.html',
|
||||||
|
helpUrl = url_for('help.static', {
|
||||||
|
'filename': 'restore_dialog.html',
|
||||||
|
});
|
||||||
|
|
||||||
|
getUtilityView(
|
||||||
|
schema, treeNodeInfo, 'select', 'dialog', j[0], panel, that.saveCallBack, extraData, 'Restore', baseUrl, sqlHelpUrl, helpUrl);
|
||||||
|
|
||||||
|
}).catch(()=>{
|
||||||
|
Notify.alert(
|
||||||
|
gettext('Utility not found'),
|
||||||
|
gettext('Failed to fetch Utility information')
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
return pgBrowser.Restore;
|
return pgBrowser.Restore;
|
||||||
|
460
web/pgadmin/tools/restore/static/js/restore.ui.js
Normal file
@ -0,0 +1,460 @@
|
|||||||
|
/////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// pgAdmin 4 - PostgreSQL Tools
|
||||||
|
//
|
||||||
|
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
|
||||||
|
// This software is released under the PostgreSQL Licence
|
||||||
|
//
|
||||||
|
//////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
import BaseUISchema from 'sources/SchemaView/base_schema.ui';
|
||||||
|
import gettext from 'sources/gettext';
|
||||||
|
import { isEmptyString } from 'sources/validators';
|
||||||
|
|
||||||
|
export class RestoreSectionSchema extends BaseUISchema {
|
||||||
|
constructor(fieldOptions={}) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.fieldOptions = {
|
||||||
|
selectedNodeType: undefined,
|
||||||
|
...fieldOptions,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.selectedNodeType = this.fieldOptions.selectedNodeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
get idAttribute() {
|
||||||
|
return 'id';
|
||||||
|
}
|
||||||
|
|
||||||
|
get baseFields() {
|
||||||
|
let obj = this;
|
||||||
|
return [{
|
||||||
|
id: 'pre_data',
|
||||||
|
label: gettext('Pre-data'),
|
||||||
|
type: 'switch',
|
||||||
|
group: gettext('Sections'),
|
||||||
|
deps: ['only_data', 'only_schema'],
|
||||||
|
disabled: function(state) {
|
||||||
|
return obj.selectedNodeType !== 'function' && obj.selectedNodeType !== 'table' &&
|
||||||
|
obj.selectedNodeType !== 'trigger' &&
|
||||||
|
obj.selectedNodeType !== 'trigger_function' &&
|
||||||
|
(state.only_data || state.only_schema);
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
id: 'data',
|
||||||
|
label: gettext('Data'),
|
||||||
|
type: 'switch',
|
||||||
|
group: gettext('Sections'),
|
||||||
|
deps: ['only_data', 'only_schema'],
|
||||||
|
disabled: function(state) {
|
||||||
|
return obj.selectedNodeType !== 'function' &&
|
||||||
|
obj.selectedNodeType !== 'table' &&
|
||||||
|
obj.selectedNodeType !== 'trigger' &&
|
||||||
|
obj.selectedNodeType !== 'trigger_function' &&
|
||||||
|
(state.only_data || state.only_schema);
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
id: 'post_data',
|
||||||
|
label: gettext('Post-data'),
|
||||||
|
type: 'switch',
|
||||||
|
group: gettext('Sections'),
|
||||||
|
deps: ['only_data', 'only_schema'],
|
||||||
|
disabled: function(state) {
|
||||||
|
return obj.selectedNodeType !== 'function' &&
|
||||||
|
obj.selectedNodeType !== 'table' &&
|
||||||
|
obj.selectedNodeType !== 'trigger' &&
|
||||||
|
obj.selectedNodeType !== 'trigger_function' &&
|
||||||
|
(state.only_data || state.only_schema);
|
||||||
|
},
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getRestoreSectionSchema(fieldOptions) {
|
||||||
|
return new RestoreSectionSchema(fieldOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
export class RestoreTypeObjSchema extends BaseUISchema {
|
||||||
|
constructor(fieldOptions={}) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.fieldOptions = {
|
||||||
|
selectedNodeType: undefined,
|
||||||
|
...fieldOptions,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.selectedNodeType = this.fieldOptions.selectedNodeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
get idAttribute() {
|
||||||
|
return 'id';
|
||||||
|
}
|
||||||
|
|
||||||
|
get baseFields() {
|
||||||
|
let obj = this;
|
||||||
|
return [{
|
||||||
|
id: 'only_data',
|
||||||
|
label: gettext('Only data'),
|
||||||
|
type: 'switch',
|
||||||
|
group: gettext('Type of objects'),
|
||||||
|
deps: ['pre_data', 'data', 'post_data', 'only_schema'],
|
||||||
|
disabled: function(state) {
|
||||||
|
return (obj.selectedNodeType !== 'database' && obj.selectedNodeType !== 'schema') ||
|
||||||
|
(state.pre_data ||
|
||||||
|
state.data ||
|
||||||
|
state.post_data ||
|
||||||
|
state.only_schema
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
id: 'only_schema',
|
||||||
|
label: gettext('Only schema'),
|
||||||
|
type: 'switch',
|
||||||
|
group: gettext('Type of objects'),
|
||||||
|
deps: ['pre_data', 'data', 'post_data', 'only_data'],
|
||||||
|
disabled: function(state) {
|
||||||
|
return (obj.selectedNodeType !== 'database' && obj.selectedNodeType !== 'schema') ||
|
||||||
|
(state.pre_data ||
|
||||||
|
state.data ||
|
||||||
|
state.post_data ||
|
||||||
|
state.only_data
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getRestoreTypeObjSchema(fieldOptions) {
|
||||||
|
return new RestoreTypeObjSchema(fieldOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
export class RestoreSaveOptSchema extends BaseUISchema {
|
||||||
|
constructor(fieldOptions={}, initValues) {
|
||||||
|
super({
|
||||||
|
id: null,
|
||||||
|
...initValues,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.fieldOptions = {
|
||||||
|
nodeInfo: null,
|
||||||
|
...fieldOptions,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
get idAttribute() {
|
||||||
|
return 'id';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
get baseFields() {
|
||||||
|
let obj = this;
|
||||||
|
return [{
|
||||||
|
id: 'dns_owner',
|
||||||
|
label: gettext('Owner'),
|
||||||
|
type: 'switch',
|
||||||
|
disabled: false,
|
||||||
|
group: gettext('Do not save'),
|
||||||
|
}, {
|
||||||
|
id: 'dns_privilege',
|
||||||
|
label: gettext('Privilege'),
|
||||||
|
type: 'switch',
|
||||||
|
disabled: false,
|
||||||
|
group: gettext('Do not save'),
|
||||||
|
}, {
|
||||||
|
id: 'dns_tablespace',
|
||||||
|
label: gettext('Tablespace'),
|
||||||
|
type: 'switch',
|
||||||
|
disabled: false,
|
||||||
|
group: gettext('Do not save'),
|
||||||
|
}, {
|
||||||
|
id: 'no_comments',
|
||||||
|
label: gettext('Comments'),
|
||||||
|
type: 'switch',
|
||||||
|
disabled: false,
|
||||||
|
group: gettext('Do not save'),
|
||||||
|
visible: function() {
|
||||||
|
var serverInfo = obj.fieldOptions.nodeInfo;
|
||||||
|
return !_.isUndefined(serverInfo) && serverInfo.version >= 110000 ? true : false;
|
||||||
|
},
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getRestoreSaveOptSchema(fieldOptions) {
|
||||||
|
return new RestoreSaveOptSchema(fieldOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
export class RestoreQueryOptionSchema extends BaseUISchema {
|
||||||
|
constructor(fieldOptions={}, initValues) {
|
||||||
|
super({
|
||||||
|
id: null,
|
||||||
|
...initValues,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.fieldOptions = {
|
||||||
|
nodeInfo: null,
|
||||||
|
backupType: null,
|
||||||
|
...fieldOptions,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.selectedNodeType = this.fieldOptions.selectedNodeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
get idAttribute() {
|
||||||
|
return 'id';
|
||||||
|
}
|
||||||
|
|
||||||
|
get baseFields() {
|
||||||
|
let obj = this;
|
||||||
|
return [{
|
||||||
|
id: 'include_create_database',
|
||||||
|
label: gettext('Include CREATE DATABASE statement'),
|
||||||
|
type: 'switch',
|
||||||
|
disabled: false,
|
||||||
|
group: gettext('Queries')
|
||||||
|
}, {
|
||||||
|
id: 'clean',
|
||||||
|
label: gettext('Clean before restore'),
|
||||||
|
type: 'switch',
|
||||||
|
group: gettext('Queries'),
|
||||||
|
disabled: function() {
|
||||||
|
return obj.selectedNodeType === 'function'
|
||||||
|
|| obj.selectedNodeType === 'trigger_function';
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
id: 'single_transaction',
|
||||||
|
label: gettext('Single transaction'),
|
||||||
|
type: 'switch',
|
||||||
|
disabled: false,
|
||||||
|
group: gettext('Queries'),
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getRestoreQueryOptionSchema(fieldOptions) {
|
||||||
|
return new RestoreQueryOptionSchema(fieldOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
export class RestoreDisableOptionSchema extends BaseUISchema {
|
||||||
|
constructor(fieldOptions={}, initValues) {
|
||||||
|
super({
|
||||||
|
id: null,
|
||||||
|
...initValues,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.fieldOptions = {
|
||||||
|
nodeInfo: null,
|
||||||
|
...fieldOptions,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
get idAttribute() {
|
||||||
|
return 'id';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
get baseFields() {
|
||||||
|
return [{
|
||||||
|
id: 'disable_trigger',
|
||||||
|
label: gettext('Trigger'),
|
||||||
|
type: 'switch',
|
||||||
|
disable: false,
|
||||||
|
group: gettext('Disable')
|
||||||
|
}, {
|
||||||
|
id: 'no_data_fail_table',
|
||||||
|
label: gettext('No data for Failed Tables'),
|
||||||
|
type: 'switch',
|
||||||
|
disabled: false,
|
||||||
|
group: gettext('Disable'),
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getRestoreDisableOptionSchema(fieldOptions) {
|
||||||
|
return new RestoreDisableOptionSchema(fieldOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
export class RestoreMiscellaneousSchema extends BaseUISchema {
|
||||||
|
constructor(fieldOptions={}, initValues) {
|
||||||
|
super({
|
||||||
|
id: null,
|
||||||
|
verbose: true,
|
||||||
|
...initValues,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.fieldOptions = {
|
||||||
|
nodeInfo: null,
|
||||||
|
...fieldOptions,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
get idAttribute() {
|
||||||
|
return 'id';
|
||||||
|
}
|
||||||
|
|
||||||
|
get baseFields() {
|
||||||
|
return [{
|
||||||
|
id: 'verbose',
|
||||||
|
label: gettext('Verbose messages'),
|
||||||
|
type: 'switch',
|
||||||
|
disabled: false,
|
||||||
|
group: gettext('Miscellaneous / Behavior'),
|
||||||
|
}, {
|
||||||
|
id: 'use_set_session_auth',
|
||||||
|
label: gettext('Use SET SESSION AUTHORIZATION'),
|
||||||
|
type: 'switch',
|
||||||
|
disabled: false,
|
||||||
|
group: gettext('Miscellaneous / Behavior'),
|
||||||
|
}, {
|
||||||
|
id: 'exit_on_error',
|
||||||
|
label: gettext('Exit on error'),
|
||||||
|
type: 'switch',
|
||||||
|
disabled: false,
|
||||||
|
group: gettext('Miscellaneous / Behavior'),
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getRestoreMiscellaneousSchema(fieldOptions) {
|
||||||
|
return new RestoreMiscellaneousSchema(fieldOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Restore Schema
|
||||||
|
export default class RestoreSchema extends BaseUISchema {
|
||||||
|
|
||||||
|
constructor(getRestoreSectionSchema, getRestoreTypeObjSchema, getRestoreSaveOptSchema, getRestoreQueryOptionSchema, getRestoreDisableOptionSchema, getRestoreMiscellaneousSchema, fieldOptions = {}, treeNodeInfo, pgBrowser) {
|
||||||
|
super({
|
||||||
|
custom: false,
|
||||||
|
file: undefined,
|
||||||
|
role: undefined,
|
||||||
|
format: 'custom',
|
||||||
|
verbose: true,
|
||||||
|
blobs: true,
|
||||||
|
encoding: undefined,
|
||||||
|
database: undefined,
|
||||||
|
schemas: undefined,
|
||||||
|
tables: undefined,
|
||||||
|
functions: undefined,
|
||||||
|
triggers: undefined,
|
||||||
|
trigger_funcs: undefined,
|
||||||
|
indexes: undefined
|
||||||
|
});
|
||||||
|
|
||||||
|
this.fieldOptions = {
|
||||||
|
encoding: null,
|
||||||
|
role: null,
|
||||||
|
...fieldOptions,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.getSectionSchema = getRestoreSectionSchema;
|
||||||
|
this.getRestoreTypeObjSchema = getRestoreTypeObjSchema;
|
||||||
|
this.getRestoreSaveOptSchema = getRestoreSaveOptSchema;
|
||||||
|
this.getRestoreQueryOptionSchema = getRestoreQueryOptionSchema;
|
||||||
|
this.getRestoreDisableOptionSchema = getRestoreDisableOptionSchema;
|
||||||
|
this.getRestoreMiscellaneousSchema = getRestoreMiscellaneousSchema;
|
||||||
|
this.treeNodeInfo = treeNodeInfo;
|
||||||
|
this.pgBrowser = pgBrowser;
|
||||||
|
}
|
||||||
|
|
||||||
|
get idAttribute() {
|
||||||
|
return 'id';
|
||||||
|
}
|
||||||
|
|
||||||
|
get baseFields() {
|
||||||
|
var obj = this;
|
||||||
|
return [{
|
||||||
|
id: 'format',
|
||||||
|
label: gettext('Format'),
|
||||||
|
disabled: false,type: 'select',
|
||||||
|
controlProps: { allowClear: false, width: '100%' },
|
||||||
|
options: [{
|
||||||
|
label: gettext('Custom or tar'),
|
||||||
|
value: 'custom',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: gettext('Directory'),
|
||||||
|
value: 'directory',
|
||||||
|
}],
|
||||||
|
}, {
|
||||||
|
id: 'file',
|
||||||
|
label: gettext('Filename'),
|
||||||
|
type: (state) => {
|
||||||
|
return {
|
||||||
|
type: 'file',
|
||||||
|
controlProps: {
|
||||||
|
dialogType: state.format == 'directory' ? 'select_folder' : 'select_file',
|
||||||
|
supportedTypes: ['*', 'backup', 'sql', 'patch'],
|
||||||
|
dialogTitle: 'Select file',
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
disabled: false,
|
||||||
|
deps: ['format']
|
||||||
|
}, {
|
||||||
|
id: 'no_of_jobs',
|
||||||
|
label: gettext('Number of jobs'),
|
||||||
|
type: 'int',
|
||||||
|
}, {
|
||||||
|
id: 'role',
|
||||||
|
label: gettext('Role name'),
|
||||||
|
node: 'role',
|
||||||
|
type: 'select',
|
||||||
|
options: obj.fieldOptions.role,
|
||||||
|
controlProps: {
|
||||||
|
allowClear: false,
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
type: 'nested-fieldset',
|
||||||
|
label: gettext('Sections'),
|
||||||
|
group: gettext('Restore options'),
|
||||||
|
schema:obj.getSectionSchema(),
|
||||||
|
visible: true
|
||||||
|
}, {
|
||||||
|
type: 'nested-fieldset',
|
||||||
|
label: gettext('Type of objects'),
|
||||||
|
group: gettext('Restore options'),
|
||||||
|
schema:obj.getRestoreTypeObjSchema(),
|
||||||
|
visible: true
|
||||||
|
}, {
|
||||||
|
type: 'nested-fieldset',
|
||||||
|
label: gettext('Do not save'),
|
||||||
|
group: gettext('Restore options'),
|
||||||
|
schema:obj.getRestoreSaveOptSchema(),
|
||||||
|
visible: true
|
||||||
|
}, {
|
||||||
|
type: 'nested-fieldset',
|
||||||
|
label: gettext('Queries'),
|
||||||
|
group: gettext('Restore options'),
|
||||||
|
schema:obj.getRestoreQueryOptionSchema(),
|
||||||
|
visible: true
|
||||||
|
}, {
|
||||||
|
type: 'nested-fieldset',
|
||||||
|
label: gettext('Disable'),
|
||||||
|
group: gettext('Restore options'),
|
||||||
|
schema:obj.getRestoreDisableOptionSchema(),
|
||||||
|
visible: true
|
||||||
|
}, {
|
||||||
|
type: 'nested-fieldset',
|
||||||
|
label: gettext('Miscellaneous / Behavior'),
|
||||||
|
group: gettext('Restore options'),
|
||||||
|
schema:obj.getRestoreMiscellaneousSchema(),
|
||||||
|
visible: true
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
validate(state, setError) {
|
||||||
|
if (isEmptyString(state.service)) {
|
||||||
|
let errmsg = null;
|
||||||
|
/* events validation*/
|
||||||
|
if (!state.file) {
|
||||||
|
errmsg = gettext('Please provide a filename.');
|
||||||
|
setError('file', errmsg);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
errmsg = null;
|
||||||
|
setError('file', errmsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,86 +0,0 @@
|
|||||||
/////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// pgAdmin 4 - PostgreSQL Tools
|
|
||||||
//
|
|
||||||
// Copyright (C) 2013 - 2021, 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';
|
|
||||||
import url_for from 'sources/url_for';
|
|
||||||
import axios from 'axios/index';
|
|
||||||
import {retrieveAncestorOfTypeServer} from 'sources/tree/tree_utils';
|
|
||||||
import {hasBinariesConfiguration} from 'sources/utils';
|
|
||||||
import Notify from '../../../../static/js/helpers/Notifier';
|
|
||||||
|
|
||||||
export class RestoreDialog extends Dialog {
|
|
||||||
constructor(pgBrowser, $, alertify, RestoreModel, backform = Backform) {
|
|
||||||
super(gettext('Restore Error'),
|
|
||||||
'<div class=\'restore_dialog\'></div>',
|
|
||||||
pgBrowser, $, alertify, RestoreModel, backform);
|
|
||||||
}
|
|
||||||
|
|
||||||
url_for_utility_exists(id){
|
|
||||||
return url_for('restore.utility_exists', {
|
|
||||||
'sid': id,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
draw(action, aciTreeItem, width, height) {
|
|
||||||
const serverInformation = retrieveAncestorOfTypeServer(this.pgBrowser, aciTreeItem, gettext('Restore Error'));
|
|
||||||
if (!serverInformation) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hasBinariesConfiguration(this.pgBrowser, serverInformation)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var sid = serverInformation._type == 'database' ? serverInformation._pid : serverInformation._id;
|
|
||||||
const baseUrl = this.url_for_utility_exists(sid);
|
|
||||||
// Check pg_restore utility exists or not.
|
|
||||||
let that = this;
|
|
||||||
axios.get(
|
|
||||||
baseUrl
|
|
||||||
).then(function(res) {
|
|
||||||
if (!res.data.success) {
|
|
||||||
Notify.alert(
|
|
||||||
gettext('Utility not found'),
|
|
||||||
res.data.errormsg
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!that.canExecuteOnCurrentDatabase(aciTreeItem)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let aciTreeItem1 = aciTreeItem || that.pgBrowser.tree.selected();
|
|
||||||
let item = that.pgBrowser.tree.findNodeByDomElement(aciTreeItem1);
|
|
||||||
const data = item.getData();
|
|
||||||
const node = that.pgBrowser.Nodes[data._type];
|
|
||||||
|
|
||||||
if (!node)
|
|
||||||
return;
|
|
||||||
|
|
||||||
let title = gettext('Restore (%s: %s)', node.label, data.label);
|
|
||||||
that.createOrGetDialog(title, 'restore');
|
|
||||||
that.alertify.pg_restore(title, aciTreeItem1, data, node)
|
|
||||||
.resizeTo(width, height);
|
|
||||||
}).catch(function() {
|
|
||||||
Notify.alert(
|
|
||||||
gettext('Utility not found'),
|
|
||||||
gettext('Failed to fetch Utility information')
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
dialogName() {
|
|
||||||
return 'pg_restore';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,293 +0,0 @@
|
|||||||
/////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// pgAdmin 4 - PostgreSQL Tools
|
|
||||||
//
|
|
||||||
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
|
|
||||||
// This software is released under the PostgreSQL Licence
|
|
||||||
//
|
|
||||||
//////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
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';
|
|
||||||
import Notify from '../../../../static/js/helpers/Notifier';
|
|
||||||
|
|
||||||
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-primary-icon pull-left fa fa-info pg-alertify-icon-button',
|
|
||||||
attrs: {
|
|
||||||
name: 'object_help',
|
|
||||||
type: 'button',
|
|
||||||
url: 'backup.html',
|
|
||||||
label: gettext('Restore'),
|
|
||||||
'aria-label': gettext('Object Help'),
|
|
||||||
},
|
|
||||||
}, {
|
|
||||||
text: '',
|
|
||||||
key: 112,
|
|
||||||
className: 'btn btn-primary-icon pull-left fa fa-question pg-alertify-icon-button',
|
|
||||||
attrs: {
|
|
||||||
name: 'dialog_help',
|
|
||||||
type: 'button',
|
|
||||||
label: gettext('Restore'),
|
|
||||||
'aria-label': gettext('Help'),
|
|
||||||
url: url_for('help.static', {
|
|
||||||
'filename': 'restore_dialog.html',
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
}, {
|
|
||||||
text: gettext('Cancel'),
|
|
||||||
key: 27,
|
|
||||||
className: 'btn btn-secondary fa fa-lg fa-times pg-alertify-button',
|
|
||||||
restore: false,
|
|
||||||
'data-btn-name': 'cancel',
|
|
||||||
}, {
|
|
||||||
text: gettext('Restore'),
|
|
||||||
key: 13,
|
|
||||||
className: 'btn btn-primary fa fa-upload pg-alertify-button',
|
|
||||||
restore: true,
|
|
||||||
'data-btn-name': 'restore',
|
|
||||||
}],
|
|
||||||
// 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 = this.pgBrowser.tree.getTreeNodeHierarchy(selectedTreeNode);
|
|
||||||
const dialog = this.createDialog(node, treeInfo, $container);
|
|
||||||
this.addAlertifyClassToRestoreNodeChildNodes();
|
|
||||||
dialog.render();
|
|
||||||
const statusBar = this.jquery(
|
|
||||||
'<div class=\'pg-prop-status-bar pg-prop-status-bar-absolute pg-el-xs-12 d-none\'>' +
|
|
||||||
' <div class="error-in-footer"> ' +
|
|
||||||
' <div class="d-flex px-2 py-1"> ' +
|
|
||||||
' <div class="pr-2"> ' +
|
|
||||||
' <i class="fa fa-exclamation-triangle text-danger" aria-hidden="true"></i> ' +
|
|
||||||
' </div> ' +
|
|
||||||
' <div class="alert-text" role="alert"></div> ' +
|
|
||||||
' <div class="ml-auto close-error-bar"> ' +
|
|
||||||
' <a aria-label="' + gettext('Close error bar') + '" class="close-error fa fa-times text-danger"></a> ' +
|
|
||||||
' </div> ' +
|
|
||||||
' </div> ' +
|
|
||||||
' </div> ' +
|
|
||||||
'</div>').appendTo($container);
|
|
||||||
|
|
||||||
this.elements.content.appendChild($container.get(0));
|
|
||||||
|
|
||||||
this.focusOnDialog(this);
|
|
||||||
this.setListenersForFilenameChanges(statusBar);
|
|
||||||
}
|
|
||||||
|
|
||||||
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.getHtmlIdentifier()
|
|
||||||
);
|
|
||||||
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 = this.pgBrowser.tree.getTreeNodeHierarchy(selectedTreeNode);
|
|
||||||
|
|
||||||
this.setExtraParameters(selectedTreeNode, treeInfo);
|
|
||||||
|
|
||||||
axios.post(
|
|
||||||
baseUrl,
|
|
||||||
this.view.model.toJSON()
|
|
||||||
).then(function (res) {
|
|
||||||
if (res.data.success) {
|
|
||||||
Notify.success(gettext('Restore job created.'), 5);
|
|
||||||
dialogWrapper.pgBrowser.Events.trigger('pgadmin-bgprocess:created', dialogWrapper);
|
|
||||||
} else {
|
|
||||||
Notify.alert(
|
|
||||||
gettext('Restore job creation failed.'),
|
|
||||||
res.data.errormsg
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}).catch(function (error) {
|
|
||||||
try {
|
|
||||||
const err = error.response.data;
|
|
||||||
Notify.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.tree;
|
|
||||||
const selectedNode = tree.selected();
|
|
||||||
if (selectedNode) {
|
|
||||||
return tree.findNodeByDomElement(selectedNode);
|
|
||||||
} else {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
disableRestoreButton() {
|
|
||||||
this.__internal.buttons[3].element.disabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
enableRestoreButton() {
|
|
||||||
this.__internal.buttons[3].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 = this.pgBrowser.tree.getTreeNodeHierarchy(selectedTreeNode);
|
|
||||||
return treeInfo.server._id;
|
|
||||||
}
|
|
||||||
|
|
||||||
setListenersForFilenameChanges(statusBar) {
|
|
||||||
const self = this;
|
|
||||||
|
|
||||||
this.view.model.on('change', function () {
|
|
||||||
const ctx = this;
|
|
||||||
var errmsg;
|
|
||||||
|
|
||||||
const showError = function(errorField, errormsg) {
|
|
||||||
ctx.errorModel.set(errorField, errormsg);
|
|
||||||
statusBar.removeClass('d-none');
|
|
||||||
statusBar.find('.alert-text').html(errormsg);
|
|
||||||
self.elements.dialog.querySelector('.close-error').addEventListener('click', ()=>{
|
|
||||||
statusBar.addClass('d-none');
|
|
||||||
ctx.errorModel.set(errorField, errormsg);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!_.isUndefined(this.get('file')) && this.get('file') !== '') {
|
|
||||||
this.errorModel.clear();
|
|
||||||
statusBar.addClass('d-none');
|
|
||||||
self.enableRestoreButton();
|
|
||||||
} else {
|
|
||||||
self.disableRestoreButton();
|
|
||||||
errmsg = gettext('Please provide a filename');
|
|
||||||
showError('file', errmsg);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
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';
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,338 +0,0 @@
|
|||||||
/////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// pgAdmin 4 - PostgreSQL Tools
|
|
||||||
//
|
|
||||||
// Copyright (C) 2013 - 2021, 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';
|
|
||||||
import MockAdapter from 'axios-mock-adapter';
|
|
||||||
import axios from 'axios/index';
|
|
||||||
import Notify from '../../../pgadmin/static/js/helpers/Notifier';
|
|
||||||
|
|
||||||
const context = describe;
|
|
||||||
|
|
||||||
describe('RestoreDialog', () => {
|
|
||||||
let restoreDialog;
|
|
||||||
let pgBrowser;
|
|
||||||
let jquerySpy;
|
|
||||||
let alertifySpy;
|
|
||||||
let restoreModelSpy;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
pgBrowser = {
|
|
||||||
tree: new TreeFake(),
|
|
||||||
Nodes: {
|
|
||||||
server: jasmine.createSpyObj('Node[server]', ['getTreeNodeHierarchy']),
|
|
||||||
database: jasmine.createSpyObj('Node[database]', ['getTreeNodeHierarchy']),
|
|
||||||
},
|
|
||||||
stdW: {
|
|
||||||
sm: 500,
|
|
||||||
md: 700,
|
|
||||||
lg: 900,
|
|
||||||
default: 500,
|
|
||||||
},
|
|
||||||
stdH: {
|
|
||||||
sm: 200,
|
|
||||||
md: 400,
|
|
||||||
lg: 550,
|
|
||||||
default: 550,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
pgBrowser.Nodes.server.hasId = true;
|
|
||||||
pgBrowser.Nodes.database.hasId = true;
|
|
||||||
jquerySpy = jasmine.createSpy('jquerySpy');
|
|
||||||
restoreModelSpy = jasmine.createSpy('restoreModelSpy');
|
|
||||||
spyOn(Notify, 'alert');
|
|
||||||
|
|
||||||
const hierarchy = {
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
id: 'root',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
id: 'serverTreeNode',
|
|
||||||
data: {
|
|
||||||
_id: 10,
|
|
||||||
_type: 'server',
|
|
||||||
label: 'some-tree-label',
|
|
||||||
server_type: 'pg',
|
|
||||||
version: 100000,
|
|
||||||
},
|
|
||||||
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: 'serverTreeNodeWrongPath',
|
|
||||||
data: {
|
|
||||||
_id: 12,
|
|
||||||
_type: 'server',
|
|
||||||
label: 'some-tree-label',
|
|
||||||
server_type: 'pg',
|
|
||||||
version: 90600,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'ppasServer',
|
|
||||||
data: {
|
|
||||||
_id: 13,
|
|
||||||
_type: 'server',
|
|
||||||
label: 'some-tree-label',
|
|
||||||
server_type: 'ppas',
|
|
||||||
version: 130000,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'ppasServerTreeNodeWrongPath',
|
|
||||||
data: {
|
|
||||||
_id: 14,
|
|
||||||
_type: 'server',
|
|
||||||
label: 'some-tree-label',
|
|
||||||
server_type: 'ppas',
|
|
||||||
version: 90600,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
pgBrowser.tree = TreeFake.build(hierarchy, pgBrowser);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('#draw', () => {
|
|
||||||
let networkMock;
|
|
||||||
beforeEach(() => {
|
|
||||||
networkMock = new MockAdapter(axios);
|
|
||||||
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');
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
networkMock.restore();
|
|
||||||
});
|
|
||||||
|
|
||||||
context('there are no ancestors of the type server', () => {
|
|
||||||
it('does not create a dialog', () => {
|
|
||||||
pgBrowser.tree.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(Notify.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 PostgreSQL server', () => {
|
|
||||||
it('display an alert with "Preferences Error"', () => {
|
|
||||||
restoreDialog.draw(null, [{id: 'serverTreeNode'}], null);
|
|
||||||
expect(Notify.alert).toHaveBeenCalledWith(
|
|
||||||
'Preferences Error',
|
|
||||||
'Failed to load preference pg_bin_dir of module paths'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
context('server is a EPAS server', () => {
|
|
||||||
it('display an alert with "Preferences Error"', () => {
|
|
||||||
restoreDialog.draw(null, [{id: 'ppasServer'}], null);
|
|
||||||
expect(Notify.alert).toHaveBeenCalledWith(
|
|
||||||
'Preferences Error',
|
|
||||||
'Failed to load preference ppas_bin_dir of module paths'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
context('preference can be found for PostgreSQL Server', () => {
|
|
||||||
context('binary folder is not configured', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
pgBrowser.get_preference.and.returnValue({value: '[{\"serverType\":\"PostgreSQL 9.6\",\"binaryPath\":null,\"isDefault\":false,\"version\":\"90600\",\"next_major_version\":\"100000\"},{\"serverType\":\"PostgreSQL 10\",\"binaryPath\":\"/Library/PostgreSQL/10/bin\",\"isDefault\":false,\"version\":\"100000\",\"next_major_version\":\"110000\"},{\"serverType\":\"PostgreSQL 11\",\"binaryPath\":\"/Library/PostgreSQL/11/bin\",\"isDefault\":false,\"version\":\"110000\",\"next_major_version\":\"120000\"},{\"serverType\":\"PostgreSQL 12\",\"binaryPath\":\"/Library/PostgreSQL/12/bin\",\"isDefault\":false,\"version\":\"120000\",\"next_major_version\":\"130000\"},{\"serverType\":\"PostgreSQL 13\",\"binaryPath\":null,\"isDefault\":false,\"version\":\"130000\",\"next_major_version\":\"140000\"}]'});
|
|
||||||
});
|
|
||||||
|
|
||||||
context('server is a PostgreSQL server', () => {
|
|
||||||
it('display an alert with "Configuration required"', () => {
|
|
||||||
restoreDialog.draw(null, [{id: 'serverTreeNodeWrongPath'}], null);
|
|
||||||
expect(Notify.alert).toHaveBeenCalledWith(
|
|
||||||
'Configuration required',
|
|
||||||
'Please configure the PostgreSQL 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.Nodes.server.label = 'some-server-label';
|
|
||||||
pgBrowser.get_preference.and.returnValue({value: '[{\"serverType\":\"PostgreSQL 9.6\",\"binaryPath\":null,\"isDefault\":false,\"version\":\"90600\",\"next_major_version\":\"100000\"},{\"serverType\":\"PostgreSQL 10\",\"binaryPath\":\"/Library/PostgreSQL/10/bin\",\"isDefault\":true,\"version\":\"100000\",\"next_major_version\":\"110000\"},{\"serverType\":\"PostgreSQL 11\",\"binaryPath\":\"/Library/PostgreSQL/11/bin\",\"isDefault\":false,\"version\":\"110000\",\"next_major_version\":\"120000\"},{\"serverType\":\"PostgreSQL 12\",\"binaryPath\":\"/Library/PostgreSQL/12/bin\",\"isDefault\":false,\"version\":\"120000\",\"next_major_version\":\"130000\"},{\"serverType\":\"PostgreSQL 13\",\"binaryPath\":null,\"isDefault\":false,\"version\":\"130000\",\"next_major_version\":\"140000\"}]'});
|
|
||||||
spyOn(restoreDialog, 'url_for_utility_exists').and.returnValue('/restore/utility_exists/10/objects');
|
|
||||||
networkMock.onGet('/restore/utility_exists/10/objects').reply(200, {'success': 1});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('displays the dialog when binary path is for correct server version', (done) => {
|
|
||||||
restoreDialog.draw(null, [{id: 'serverTreeNode'}], pgBrowser.stdW.md, pgBrowser.stdH.md);
|
|
||||||
setTimeout(() => {
|
|
||||||
expect(alertifySpy['pg_restore']).toHaveBeenCalledWith(
|
|
||||||
'Restore (some-server-label: some-tree-label)',
|
|
||||||
[{id: 'serverTreeNode'}],
|
|
||||||
{
|
|
||||||
_id: 10,
|
|
||||||
_type: 'server',
|
|
||||||
label: 'some-tree-label',
|
|
||||||
server_type: 'pg',
|
|
||||||
version: 100000,
|
|
||||||
},
|
|
||||||
pgBrowser.Nodes.server
|
|
||||||
);
|
|
||||||
expect(spy.resizeTo).toHaveBeenCalledWith(pgBrowser.stdW.md, pgBrowser.stdH.md);
|
|
||||||
done();
|
|
||||||
}, 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('displays the dialog when default binary path is specified', (done) => {
|
|
||||||
restoreDialog.draw(null, [{id: 'serverTreeNodeWrongPath'}], pgBrowser.stdW.md, pgBrowser.stdH.md);
|
|
||||||
setTimeout(() => {
|
|
||||||
expect(alertifySpy['pg_restore']).toHaveBeenCalledWith(
|
|
||||||
'Restore (some-server-label: some-tree-label)',
|
|
||||||
[{id: 'serverTreeNodeWrongPath'}],
|
|
||||||
{
|
|
||||||
_id: 12,
|
|
||||||
_type: 'server',
|
|
||||||
label: 'some-tree-label',
|
|
||||||
server_type: 'pg',
|
|
||||||
version: 90600,
|
|
||||||
},
|
|
||||||
pgBrowser.Nodes.server
|
|
||||||
);
|
|
||||||
expect(spy.resizeTo).toHaveBeenCalledWith(pgBrowser.stdW.md, pgBrowser.stdH.md);
|
|
||||||
done();
|
|
||||||
}, 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
context('database label contain "="', () => {
|
|
||||||
it('should create alert dialog with restore error', (done) => {
|
|
||||||
restoreDialog.draw(null, [{id: 'database_with_equal_in_name'}], null);
|
|
||||||
setTimeout(() => {
|
|
||||||
expect(alertifySpy.alert).toHaveBeenCalledWith('Restore Error',
|
|
||||||
'Databases with = symbols in the name cannot be backed up or restored using this utility.');
|
|
||||||
done();
|
|
||||||
}, 0);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
context('preference can be found for EPAS server', () => {
|
|
||||||
context('binary folder is not configured', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
pgBrowser.get_preference.and.returnValue({value: '[{\"serverType\":\"EDB Advanced Server 9.6\",\"binaryPath\":\"\",\"isDefault\":false,\"version\":\"90600\",\"next_major_version\":\"100000\"},{\"serverType\":\"EDB Advanced Server 10\",\"binaryPath\":null,\"isDefault\":false,\"version\":\"100000\",\"next_major_version\":\"110000\"},{\"serverType\":\"EDB Advanced Server 11\",\"binaryPath\":\"/Library/EPAS/11/bin/\",\"isDefault\":false,\"version\":\"110000\",\"next_major_version\":\"120000\"},{\"serverType\":\"EDB Advanced Server 12\",\"binaryPath\":null,\"isDefault\":false,\"version\":\"120000\",\"next_major_version\":\"130000\"},{\"serverType\":\"EDB Advanced Server 13\",\"binaryPath\":\"/Library/EPAS/13/bin/\",\"isDefault\":false,\"version\":\"130000\",\"next_major_version\":\"140000\"}]'});
|
|
||||||
});
|
|
||||||
|
|
||||||
context('server is a EPAS server', () => {
|
|
||||||
it('display an alert with "Configuration required"', () => {
|
|
||||||
restoreDialog.draw(null, [{id: 'ppasServerTreeNodeWrongPath'}], null);
|
|
||||||
expect(Notify.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.Nodes.server.label = 'some-server-label';
|
|
||||||
pgBrowser.get_preference.and.returnValue({value: '[{\"serverType\":\"EDB Advanced Server 9.6\",\"binaryPath\":\"\",\"isDefault\":false,\"version\":\"90600\",\"next_major_version\":\"100000\"},{\"serverType\":\"EDB Advanced Server 10\",\"binaryPath\":null,\"isDefault\":false,\"version\":\"100000\",\"next_major_version\":\"110000\"},{\"serverType\":\"EDB Advanced Server 11\",\"binaryPath\":\"/Library/EPAS/11/bin/\",\"isDefault\":false,\"version\":\"110000\",\"next_major_version\":\"120000\"},{\"serverType\":\"EDB Advanced Server 12\",\"binaryPath\":null,\"isDefault\":false,\"version\":\"120000\",\"next_major_version\":\"130000\"},{\"serverType\":\"EDB Advanced Server 13\",\"binaryPath\":\"/Library/EPAS/13/bin/\",\"isDefault\":true,\"version\":\"130000\",\"next_major_version\":\"140000\"}]'});
|
|
||||||
spyOn(restoreDialog, 'url_for_utility_exists').and.returnValue('/restore/utility_exists/10/objects');
|
|
||||||
networkMock.onGet('/restore/utility_exists/10/objects').reply(200, {'success': 1});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('displays the dialog when binary path is for correct server version', (done) => {
|
|
||||||
restoreDialog.draw(null, [{id: 'ppasServer'}], pgBrowser.stdW.md, pgBrowser.stdH.md);
|
|
||||||
setTimeout(() => {
|
|
||||||
expect(alertifySpy['pg_restore']).toHaveBeenCalledWith(
|
|
||||||
'Restore (some-server-label: some-tree-label)',
|
|
||||||
[{id: 'ppasServer'}],
|
|
||||||
{
|
|
||||||
_id: 13,
|
|
||||||
_type: 'server',
|
|
||||||
label: 'some-tree-label',
|
|
||||||
server_type: 'ppas',
|
|
||||||
version: 130000,
|
|
||||||
},
|
|
||||||
pgBrowser.Nodes.server
|
|
||||||
);
|
|
||||||
expect(spy.resizeTo).toHaveBeenCalledWith(pgBrowser.stdW.md, pgBrowser.stdH.md);
|
|
||||||
done();
|
|
||||||
}, 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('displays the dialog when default binary path is specified', (done) => {
|
|
||||||
restoreDialog.draw(null, [{id: 'ppasServerTreeNodeWrongPath'}], pgBrowser.stdW.md, pgBrowser.stdH.md);
|
|
||||||
setTimeout(() => {
|
|
||||||
expect(alertifySpy['pg_restore']).toHaveBeenCalledWith(
|
|
||||||
'Restore (some-server-label: some-tree-label)',
|
|
||||||
[{id: 'ppasServerTreeNodeWrongPath'}],
|
|
||||||
{
|
|
||||||
_id: 14,
|
|
||||||
_type: 'server',
|
|
||||||
label: 'some-tree-label',
|
|
||||||
server_type: 'ppas',
|
|
||||||
version: 90600,
|
|
||||||
},
|
|
||||||
pgBrowser.Nodes.server
|
|
||||||
);
|
|
||||||
expect(spy.resizeTo).toHaveBeenCalledWith(pgBrowser.stdW.md, pgBrowser.stdH.md);
|
|
||||||
done();
|
|
||||||
}, 0);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,596 +0,0 @@
|
|||||||
/////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// pgAdmin 4 - PostgreSQL Tools
|
|
||||||
//
|
|
||||||
// Copyright (C) 2013 - 2021, 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_nodes';
|
|
||||||
import Notify from '../../../pgadmin/static/js/helpers/Notifier';
|
|
||||||
|
|
||||||
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 = {
|
|
||||||
Nodes: {
|
|
||||||
server: {
|
|
||||||
hasId: true,
|
|
||||||
getTreeNodeHierarchy: jasmine.createSpy('getTreeNodeHierarchy'),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
keyboardNavigation: jasmine.createSpyObj('keyboardNavigation', ['getDialogTabNavigator']),
|
|
||||||
};
|
|
||||||
pgBrowser.tree = new TreeFake(pgBrowser);
|
|
||||||
|
|
||||||
noDataNode = pgBrowser.tree.addNewNode('level1.1', undefined, [{id: 'level1'}]);
|
|
||||||
serverTreeNode = pgBrowser.tree.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;
|
|
||||||
} else {
|
|
||||||
return jasmine.createSpyObj('obj', ['appendTo']);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
spyOn(Notify, 'success');
|
|
||||||
spyOn(Notify, 'alert');
|
|
||||||
});
|
|
||||||
|
|
||||||
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[3].element.disabled).toEqual(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
context('selected tree node has no data', () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
pgBrowser.tree.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[3].element.disabled).toEqual(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
context('tree element is selected', () => {
|
|
||||||
let treeHierarchyInformation;
|
|
||||||
let dialogSpy;
|
|
||||||
beforeEach(() => {
|
|
||||||
treeHierarchyInformation = {
|
|
||||||
server: {
|
|
||||||
_type: 'server',
|
|
||||||
_id: 10,
|
|
||||||
priority: 0,
|
|
||||||
label: 'some-tree-label',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
pgBrowser.tree.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[3].element.disabled).toEqual(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.tree.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.getHtmlIdentifier()
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not start the restore', () => {
|
|
||||||
expect(networkCalled).toEqual(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
context('object help button was pressed', () => {
|
|
||||||
let networkCalled;
|
|
||||||
beforeEach(() => {
|
|
||||||
networkCalled = false;
|
|
||||||
pgBrowser.tree.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.getHtmlIdentifier()
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not start the restore', () => {
|
|
||||||
expect(networkCalled).toEqual(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).toEqual(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.tree.selectNode(noDataNode.domNode);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not start the restore', () => {
|
|
||||||
restoreDialogWrapper.callback(event);
|
|
||||||
expect(networkCalled).toEqual(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
context('tree node select has data', () => {
|
|
||||||
|
|
||||||
let databaseTreeNode;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
databaseTreeNode = pgBrowser.tree.addNewNode('level3.1', {
|
|
||||||
_type: 'database',
|
|
||||||
_id: 10,
|
|
||||||
_label: 'some-database-label',
|
|
||||||
}, [{id: 'level3.1'}]);
|
|
||||||
pgBrowser.tree.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.tree.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, {'success': 1}];
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('create an success alert box', (done) => {
|
|
||||||
restoreDialogWrapper.callback(event);
|
|
||||||
setTimeout(() => {
|
|
||||||
expect(Notify.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(Notify.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'],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
70
web/regression/javascript/schema_ui_files/restore.ui.spec.js
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
/////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// pgAdmin 4 - PostgreSQL Tools
|
||||||
|
//
|
||||||
|
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
|
||||||
|
// This software is released under the PostgreSQL License
|
||||||
|
//
|
||||||
|
//////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import '../helper/enzyme.helper';
|
||||||
|
import { createMount } from '@material-ui/core/test-utils';
|
||||||
|
import pgAdmin from 'sources/pgadmin';
|
||||||
|
import SchemaView from '../../../pgadmin/static/js/SchemaView';
|
||||||
|
import RestoreSchema, {getRestoreSaveOptSchema, getRestoreQueryOptionSchema, getRestoreDisableOptionSchema, getRestoreMiscellaneousSchema, getRestoreTypeObjSchema, getRestoreSectionSchema} from '../../../pgadmin/tools/restore/static/js/restore.ui';
|
||||||
|
|
||||||
|
describe('RestoreSchema', ()=>{
|
||||||
|
let mount;
|
||||||
|
beforeAll(()=>{
|
||||||
|
mount = createMount();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
mount.cleanUp();
|
||||||
|
});
|
||||||
|
let restoreSchemaObj = new RestoreSchema(
|
||||||
|
()=>getRestoreSectionSchema({selectedNodeType: 'table'}),
|
||||||
|
()=>getRestoreTypeObjSchema({selectedNodeType: 'table'}),
|
||||||
|
()=>getRestoreSaveOptSchema({nodeInfo: {server: {version: 11000}}}),
|
||||||
|
()=>getRestoreQueryOptionSchema({nodeInfo: {server: {version: 11000}}}),
|
||||||
|
()=>getRestoreDisableOptionSchema({nodeInfo: {server: {version: 11000}}}),
|
||||||
|
()=>getRestoreMiscellaneousSchema({nodeInfo: {server: {version: 11000}}}),
|
||||||
|
{
|
||||||
|
role: ()=>[],
|
||||||
|
encoding: ()=>[],
|
||||||
|
},
|
||||||
|
{server: {version: 11000}},
|
||||||
|
pgAdmin.pgBrowser
|
||||||
|
);
|
||||||
|
|
||||||
|
it('restore dialog', ()=>{
|
||||||
|
mount(<SchemaView
|
||||||
|
formType='dialog'
|
||||||
|
schema={restoreSchemaObj}
|
||||||
|
viewHelperProps={{
|
||||||
|
mode: 'create',
|
||||||
|
}}
|
||||||
|
onSave={()=>{}}
|
||||||
|
onClose={()=>{}}
|
||||||
|
onHelp={()=>{}}
|
||||||
|
onDataChange={()=>{}}
|
||||||
|
confirmOnCloseReset={false}
|
||||||
|
hasSQL={false}
|
||||||
|
disableSqlHelp={false}
|
||||||
|
disableDialogHelp={false}
|
||||||
|
/>);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('restore validate', () => {
|
||||||
|
let state = { file: undefined }; //validating for empty file
|
||||||
|
let setError = jasmine.createSpy('setError');
|
||||||
|
|
||||||
|
restoreSchemaObj.validate(state, setError);
|
||||||
|
expect(setError).toHaveBeenCalledWith('file', 'Please provide a filename.');
|
||||||
|
|
||||||
|
state.file = '/home/dir/restore.sql'; //validating for valid file name
|
||||||
|
restoreSchemaObj.validate(state, setError);
|
||||||
|
expect(setError).toHaveBeenCalledWith('file', null);
|
||||||
|
});
|
||||||
|
});
|