define([ 'sources/gettext', 'sources/url_for', 'jquery', 'underscore', 'underscore.string', 'pgadmin.alertifyjs', 'sources/pgadmin', 'pgadmin.browser', 'backbone', 'backgrid', 'backform', 'pgadmin.backform', 'pgadmin.backgrid', 'pgadmin.browser.node.ui', ], function( gettext, url_for, $, _, S, Alertify, pgAdmin, pgBrowser, Backbone, Backgrid, Backform ) { pgAdmin = pgAdmin || window.pgAdmin || {}; var pgTools = pgAdmin.Tools = pgAdmin.Tools || {}; // Return back, this has been called more than once if (pgAdmin.Tools.maintenance) return pgAdmin.Tools.maintenance; Backform.CustomSwitchControl = Backform.SwitchControl.extend({ template: _.template([ '', '
', '
', ' ', '
', '
', '<% if (helpMessage && helpMessage.length) { %>', ' <%=helpMessage%>', '<% } %>', ].join('\n')), className: 'pgadmin-control-group form-group col-xs-6', }); // Main model for Maintenance functionality var MaintenanceModel = Backbone.Model.extend({ defaults: { op: 'VACUUM', vacuum_full: false, vacuum_freeze: false, vacuum_analyze: false, verbose: true, }, initialize: function() { var node_info = arguments[1]['node_info']; // If node is Unique or Primary key then set op to reindex if ('primary_key' in node_info || 'unique_constraint' in node_info || 'index' in node_info) { this.set('op', 'REINDEX'); this.set('verbose', false); } }, schema: [{ id: 'op', label: gettext('Maintenance operation'), cell: 'string', type: 'text', group: gettext('Options'), options: [{ 'label': 'VACUUM', 'value': 'VACUUM', }, { 'label': 'ANALYZE', 'value': 'ANALYZE', }, { 'label': 'REINDEX', 'value': 'REINDEX', }, { 'label': 'CLUSTER', 'value': 'CLUSTER', }, ], control: Backform.RadioControl.extend({ template: _.template([ '', '
', ' <% for (var i=0; i < options.length; i++) { %>', ' <% var option = options[i]; %>', ' ', ' <% } %>', '
', ].join('\n')), }), select2: { allowClear: false, width: '100%', placeholder: gettext('Select from list...'), }, }, { type: 'nested', control: 'fieldset', label: gettext('Vacuum'), group: gettext('Options'), schema: [{ id: 'vacuum_full', group: gettext('Vacuum'), disabled: 'isDisabled', control: Backform.CustomSwitchControl, label: gettext('FULL'), deps: ['op'], }, { id: 'vacuum_freeze', deps: ['op'], disabled: 'isDisabled', control: Backform.CustomSwitchControl, label: gettext('FREEZE'), group: gettext('Vacuum'), }, { id: 'vacuum_analyze', deps: ['op'], disabled: 'isDisabled', control: Backform.CustomSwitchControl, label: gettext('ANALYZE'), group: gettext('Vacuum'), }], }, { id: 'verbose', group: gettext('Options'), deps: ['op'], control: Backform.CustomSwitchControl, label: gettext('Verbose Messages'), disabled: 'isDisabled', }, ], // Enable/Disable the items based on the user maintenance operation // selection. isDisabled: function(m) { var node_info = this.node_info; switch (this.name) { case 'vacuum_full': case 'vacuum_freeze': case 'vacuum_analyze': return (m.get('op') != 'VACUUM'); case 'verbose': if ('primary_key' in node_info || 'unique_constraint' in node_info || 'index' in node_info) { if (m.get('op') == 'REINDEX') { setTimeout(function() { m.set('verbose', false); }, 10); return true; } } return m.get('op') == 'REINDEX'; default: return false; } }, }); pgTools.maintenance = { init: function() { // We do not want to initialize the module multiple times. if (this.initialized) return; this.initialized = true; var maintenance_supported_nodes = [ 'database', 'table', 'primary_key', 'unique_constraint', 'index', 'partition', ]; /** Enable/disable Maintenance menu in tools based on node selected. Maintenance menu will be enabled only when user select table and database node. */ var menu_enabled = function(itemData, item) { var t = pgBrowser.tree, i = item, d = itemData; var parent_item = t.hasParent(i) ? t.parent(i) : null, parent_data = parent_item ? t.itemData(parent_item) : null; if (!_.isUndefined(d) && !_.isNull(d) && !_.isNull(parent_data)) { if (_.indexOf(maintenance_supported_nodes, d._type) !== -1 && parent_data._type != 'catalog') { if (d._type == 'database' && d.allowConn) return true; else if (d._type != 'database') return true; else return false; } else return false; } else return false; }; var menus = [{ name: 'maintenance', module: this, applies: ['tools'], callback: 'callback_maintenance', priority: 10, label: gettext('Maintenance...'), icon: 'fa fa-wrench', enable: menu_enabled, }]; // Add supported menus into the menus list for (var idx = 0; idx < maintenance_supported_nodes.length; idx++) { menus.push({ name: 'maintenance_context_' + maintenance_supported_nodes[idx], node: maintenance_supported_nodes[idx], module: this, applies: ['context'], callback: 'callback_maintenance', priority: 10, label: gettext('Maintenance...'), icon: 'fa fa-wrench', enable: menu_enabled, }); } pgBrowser.add_menus(menus); }, /* Open the dialog for the maintenance functionality */ callback_maintenance: function(args, item) { var i = item || pgBrowser.tree.selected(), server_data = null; while (i) { var node_data = pgBrowser.tree.itemData(i); if (node_data._type == 'server') { server_data = node_data; break; } if (pgBrowser.tree.hasParent(i)) { i = $(pgBrowser.tree.parent(i)); } else { Alertify.alert(gettext('Please select server or child node from tree.')); break; } } if (!server_data) { return; } var module = 'paths', preference_name = 'pg_bin_dir', msg = gettext('Please configure the PostgreSQL Binary Path in the Preferences dialog.'); if ((server_data.type && server_data.type == 'ppas') || server_data.server_type == 'ppas') { preference_name = 'ppas_bin_dir'; msg = gettext('Please configure the EDB Advanced Server Binary Path in the Preferences dialog.'); } var preference = pgBrowser.get_preference(module, preference_name); if (preference) { if (!preference.value) { Alertify.alert(gettext('Configuration required'), msg); return; } } else { Alertify.alert(S(gettext('Failed to load preference %s of module %s')).sprintf(preference_name, module).value()); return; } var self = this, t = pgBrowser.tree; i = item || t.selected(); var d = i && i.length == 1 ? t.itemData(i) : undefined; if (!d) return; if (!Alertify.MaintenanceDialog) { Alertify.dialog('MaintenanceDialog', function factory() { return { main: function(title) { this.set('title', title); }, setup: function() { return { buttons: [{ text: '', className: 'btn btn-default pull-left fa fa-lg fa-info', attrs: { name: 'object_help', type: 'button', url: 'maintenance.html', label: gettext('Maintenance'), }, }, { text: '', key: 112, className: 'btn btn-default pull-left fa fa-lg fa-question', attrs: { name: 'dialog_help', type: 'button', label: gettext('Maintenance'), url: url_for( 'help.static', { 'filename': 'maintenance_dialog.html', } ), }, }, { text: gettext('OK'), key: 13, className: 'btn btn-primary fa fa-lg fa-save pg-alertify-button', 'data-btn-name': 'ok', }, { text: gettext('Cancel'), key: 27, className: 'btn btn-danger fa fa-lg fa-times pg-alertify-button', 'data-btn-name': 'cancel', }], options: { modal: 0, pinnable: false, }, }; }, // Callback functions when click on the buttons of the Alertify dialogs callback: function(e) { var i = pgBrowser.tree.selected(), d = i && i.length == 1 ? pgBrowser.tree.itemData(i) : undefined, node = d && pgBrowser.Nodes[d._type]; if (e.button.element.name == 'dialog_help' || e.button.element.name == 'object_help') { e.cancel = true; pgBrowser.showHelp(e.button.element.name, e.button.element.getAttribute('url'), node, i, e.button.element.getAttribute('label')); return; } if (e.button['data-btn-name'] === 'ok') { var schema = undefined, table = undefined, primary_key = undefined, unique_constraint = undefined, index = undefined; if (!d) return; var treeInfo = node.getTreeNodeHierarchy.apply(node, [i]); if (treeInfo.schema != undefined) { schema = treeInfo.schema._label; } if (treeInfo.partition != undefined) { table = treeInfo.partition._label; } else if (treeInfo.table != undefined) { table = treeInfo.table._label; } if (treeInfo.primary_key != undefined) { primary_key = treeInfo.primary_key._label; } else if (treeInfo.unique_constraint != undefined) { unique_constraint = treeInfo.unique_constraint._label; } else if (treeInfo.index != undefined) { index = treeInfo.index._label; } this.view.model.set({ 'database': treeInfo.database._label, 'schema': schema, 'table': table, 'primary_key': primary_key, 'unique_constraint': unique_constraint, 'index': index, }); $.ajax({ url: url_for( 'maintenance.create_job', { 'sid': treeInfo.server._id, 'did': treeInfo.database._id, }), method: 'POST', data: { 'data': JSON.stringify(this.view.model.toJSON()), }, success: function(res) { if (res.data && res.data.status) { //Do nothing as we are creating the job and exiting from the main dialog Alertify.success(res.data.info); pgBrowser.Events.trigger('pgadmin-bgprocess:created', self); } else { Alertify.error(res.data.errmsg); } }, error: function() { Alertify.alert( gettext('Maintenance job creation failed.') ); }, }); } }, build: function() { Alertify.pgDialogBuild.apply(this); }, hooks: { onclose: function() { if (this.view) { this.view.remove({ data: true, internal: true, silent: true, }); } }, }, prepare: function() { // Main maintenance tool dialog container var $container = $('
'); var t = pgBrowser.tree, i = t.selected(), d = i && i.length == 1 ? t.itemData(i) : undefined, node = d && pgBrowser.Nodes[d._type]; if (!d) return; var treeInfo = node.getTreeNodeHierarchy.apply(node, [i]); var newModel = new MaintenanceModel({}, { node_info: treeInfo, }), fields = Backform.generateViewSchema( treeInfo, newModel, 'create', node, treeInfo.server, true ); var view = this.view = new Backform.Dialog({ el: $container, model: newModel, schema: fields, }); $(this.elements.body.childNodes[0]).addClass('alertify_tools_dialog_properties obj_properties'); view.render(); // If node is Index, Unique or Primary key then disable vacuum & analyze button if (d._type == 'primary_key' || d._type == 'unique_constraint' || d._type == 'index') { var vacuum_analyze_btns = $container.find( '.pgadmin-controls label:lt(2)' ).removeClass('active').addClass('disabled'); // Find reindex button element & add active class to it var reindex_btn = vacuum_analyze_btns[1].nextElementSibling; $(reindex_btn).addClass('active'); } this.elements.content.appendChild($container.get(0)); }, }; }); } // Open the Alertify dialog Alertify.MaintenanceDialog('Maintenance...').set('resizable', true).resizeTo('60%', '80%'); }, }; return pgAdmin.Tools.maintenance; });