mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2026-10-26 06:30:06 -05:00
Added Macro support. Fixes #1402
This commit is contained in:
1 parent
952197f130
commit
4616a74029
17 files changed
+1429
-14
No files matched your search
@@ -9,10 +9,10 @@
|
||||
|
||||
define([
|
||||
'sources/gettext', 'underscore', 'jquery', 'backbone', 'backform', 'backgrid', 'alertify',
|
||||
'moment', 'bignumber', 'sources/utils', 'sources/keyboard_shortcuts', 'sources/select2/configure_show_on_scroll',
|
||||
'moment', 'bignumber', 'codemirror', 'sources/utils', 'sources/keyboard_shortcuts', 'sources/select2/configure_show_on_scroll',
|
||||
'bootstrap.datetimepicker', 'backgrid.filter', 'bootstrap.toggle',
|
||||
], function(
|
||||
gettext, _, $, Backbone, Backform, Backgrid, Alertify, moment, BigNumber,
|
||||
gettext, _, $, Backbone, Backform, Backgrid, Alertify, moment, BigNumber, CodeMirror,
|
||||
commonUtils, keyboardShortcuts, configure_show_on_scroll
|
||||
) {
|
||||
/*
|
||||
@@ -44,7 +44,7 @@ define([
|
||||
_.extend(Backgrid.InputCellEditor.prototype.events, {
|
||||
'keydown': function(e) {
|
||||
let preferences = pgBrowser.get_preferences_for_module('browser');
|
||||
if(keyboardShortcuts.validateShortcutKeys(preferences.add_grid_row,e)) {
|
||||
if(preferences && keyboardShortcuts.validateShortcutKeys(preferences.add_grid_row,e)) {
|
||||
pgBrowser.keyboardNavigation.bindAddGridRow();
|
||||
} else {
|
||||
Backgrid.InputCellEditor.prototype.saveOrCancel.apply(this, arguments);
|
||||
@@ -324,7 +324,7 @@ define([
|
||||
events: {
|
||||
'keydown': function (event) {
|
||||
let preferences = pgBrowser.get_preferences_for_module('browser');
|
||||
if(keyboardShortcuts.validateShortcutKeys(preferences.add_grid_row,event)) {
|
||||
if(preferences && keyboardShortcuts.validateShortcutKeys(preferences.add_grid_row,event)) {
|
||||
pgBrowser.keyboardNavigation.bindAddGridRow();
|
||||
}
|
||||
},
|
||||
@@ -606,6 +606,96 @@ define([
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
Backgrid.Extension.ClearCell = Backgrid.Cell.extend({
|
||||
defaults: _.defaults({
|
||||
defaultClearMsg: gettext('Are you sure you wish to clear this row?'),
|
||||
defaultClearTitle: gettext('Clear Row'),
|
||||
}, Backgrid.Cell.prototype.defaults),
|
||||
|
||||
/** @property */
|
||||
className: 'clear-cell',
|
||||
events: {
|
||||
'click': 'clearRow',
|
||||
},
|
||||
clearRow: function(e) {
|
||||
e.preventDefault();
|
||||
if (_.isEmpty(e.currentTarget.innerHTML)) return false;
|
||||
var that = this;
|
||||
// We will check if row is deletable or not
|
||||
|
||||
var clear_msg = !_.isUndefined(this.column.get('customClearMsg')) ?
|
||||
this.column.get('customClearMsg') : that.defaults.defaultClearMsg;
|
||||
var clear_title = !_.isUndefined(this.column.get('customClearTitle')) ?
|
||||
this.column.get('customClearTitle') : that.defaults.defaultClearTitle;
|
||||
Alertify.confirm(
|
||||
clear_title,
|
||||
clear_msg,
|
||||
function() {
|
||||
that.model.set('name', null);
|
||||
that.model.set('sql', null);
|
||||
},
|
||||
function() {
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
},
|
||||
exitEditMode: function() {
|
||||
this.$el.removeClass('editor');
|
||||
},
|
||||
initialize: function() {
|
||||
Backgrid.Cell.prototype.initialize.apply(this, arguments);
|
||||
},
|
||||
render: function() {
|
||||
var self = this;
|
||||
this.$el.empty();
|
||||
$(this.$el).attr('tabindex', 0);
|
||||
if (this.model.get('name') !== null && this.model.get('sql') !== null)
|
||||
this.$el.html('<i aria-label="' + gettext('Clear row') + '" class=\'fa fa-eraser\' title=\'' + gettext('Clear row') + '\'></i>');
|
||||
// Listen for Tab/Shift-Tab key
|
||||
this.$el.on('keydown', function(e) {
|
||||
// with keyboard navigation on space key, mark row for deletion
|
||||
if (e.keyCode == 32) {
|
||||
self.$el.click();
|
||||
}
|
||||
var gotoCell;
|
||||
if (e.keyCode == 9 || e.keyCode == 16) {
|
||||
// go to Next Cell & if Shift is also pressed go to Previous Cell
|
||||
gotoCell = e.shiftKey ? self.$el.prev() : self.$el.next();
|
||||
}
|
||||
|
||||
if (gotoCell) {
|
||||
let command = new Backgrid.Command({
|
||||
key: 'Tab',
|
||||
keyCode: 9,
|
||||
which: 9,
|
||||
shiftKey: e.shiftKey,
|
||||
});
|
||||
setTimeout(function() {
|
||||
// When we have Editable Cell
|
||||
if (gotoCell.hasClass('editable')) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
self.model.trigger('backgrid:edited', self.model,
|
||||
self.column, command);
|
||||
}
|
||||
else {
|
||||
// When we have Non-Editable Cell
|
||||
self.model.trigger('backgrid:edited', self.model,
|
||||
self.column, command);
|
||||
}
|
||||
}, 20);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
this.delegateEvents();
|
||||
return this;
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
Backgrid.Extension.CustomHeaderCell = Backgrid.HeaderCell.extend({
|
||||
initialize: function() {
|
||||
// Here, we will add custom classes to header cell
|
||||
@@ -2081,6 +2171,84 @@ define([
|
||||
},
|
||||
});
|
||||
|
||||
Backgrid.Extension.SqlCell = Backgrid.Extension.TextareaCell.extend({
|
||||
className: 'sql-cell',
|
||||
defaults: {
|
||||
lineWrapping: true,
|
||||
},
|
||||
template: _.template([
|
||||
'<div data-toggle="tooltip" data-placement="top" data-html="true" title="<%- val %>"><textarea aria-label="' + gettext('SQL') +'" + style="display: none;"><%- val %></textarea><div>',
|
||||
].join('\n')),
|
||||
|
||||
render: function() {
|
||||
let self = this,
|
||||
col = _.defaults(this.column.toJSON(), this.defaults),
|
||||
model = this.model,
|
||||
column = this.column,
|
||||
columnName = this.column.get('name'),
|
||||
editable = Backgrid.callByNeed(col.editable, column, model);
|
||||
|
||||
if (this.sqlCell) {
|
||||
this.sqlCell.toTextArea();
|
||||
delete this.sqlCell;
|
||||
this.sqlCell = null;
|
||||
}
|
||||
|
||||
this.$el.empty();
|
||||
this.$el.append(this.template({
|
||||
val:this.formatter.fromRaw(model.get(columnName), model),
|
||||
})
|
||||
);
|
||||
this.$el.addClass(columnName);
|
||||
this.updateStateClassesMaybe();
|
||||
this.delegateEvents();
|
||||
|
||||
setTimeout(function() {
|
||||
self.sqlCell = CodeMirror.fromTextArea(
|
||||
(self.$el.find('textarea')[0]), {
|
||||
mode: 'text/x-pgsql',
|
||||
readOnly: !editable,
|
||||
singleCursorHeightPerLine: true,
|
||||
screenReaderLabel: columnName,
|
||||
});
|
||||
});
|
||||
|
||||
return this;
|
||||
},
|
||||
enterEditMode: function () {
|
||||
if (!this.$el.hasClass('editor')) this.$el.addClass('editor');
|
||||
this.sqlCell.focus();
|
||||
this.sqlCell.on('blur', this.exitEditMode.bind(this));
|
||||
},
|
||||
exitEditMode: function () {
|
||||
this.$el.removeClass('editor');
|
||||
this.saveOrCancel.apply(this, arguments);
|
||||
},
|
||||
saveOrCancel: function() {
|
||||
var model = this.model;
|
||||
var column = this.column;
|
||||
if (this.sqlCell) {
|
||||
var val = this.sqlCell.getTextArea().value;
|
||||
var newValue = this.sqlCell.getValue();
|
||||
if (_.isUndefined(newValue)) {
|
||||
model.trigger('backgrid:error', model, column, val);
|
||||
}
|
||||
else {
|
||||
model.set(column.get('name'), newValue);
|
||||
}
|
||||
}
|
||||
},
|
||||
remove: function() {
|
||||
if (this.sqlCell) {
|
||||
$(this.$el.find('[data-toggle="tooltip"]')).tooltip('dispose');
|
||||
this.sqlCell.toTextArea();
|
||||
delete this.sqlCell;
|
||||
this.sqlCell = null;
|
||||
}
|
||||
return Backgrid.Extension.TextareaCell.prototype.remove.apply(this, arguments);
|
||||
},
|
||||
});
|
||||
|
||||
return Backgrid;
|
||||
|
||||
});
|
||||
@@ -324,15 +324,38 @@ function keyboardShortcutsQueryTool(
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Macros
|
||||
let macroId = this.validateMacros(sqlEditorController, event);
|
||||
|
||||
if (macroId !== false) {
|
||||
this._stopEventPropagation(event);
|
||||
queryToolActions.executeMacro(sqlEditorController, macroId);
|
||||
}
|
||||
}
|
||||
|
||||
return panel_type;
|
||||
}
|
||||
|
||||
function validateMacros(sqlEditorController, event) {
|
||||
let keyCode = event.which || event.keyCode;
|
||||
|
||||
let macro = sqlEditorController.macros.filter(mc =>
|
||||
mc.alt == event.altKey &&
|
||||
mc.control == event.ctrlKey &&
|
||||
mc.key_code == keyCode);
|
||||
|
||||
if (macro.length == 1) {
|
||||
return macro[0].id;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export {
|
||||
keyboardShortcutsDebugger as processEventDebugger,
|
||||
keyboardShortcutsQueryTool as processEventQueryTool,
|
||||
focusDockerPanel, validateShortcutKeys,
|
||||
focusDockerPanel, validateShortcutKeys, validateMacros,
|
||||
_stopEventPropagation, isMac, isKeyCtrlAlt, isKeyAltShift, isKeyCtrlShift,
|
||||
isKeyCtrlAltShift, isAltShiftBoth, isCtrlShiftBoth, isCtrlAltBoth,
|
||||
shortcut_key, shortcut_title, shortcut_accesskey_title,
|
||||
|
||||
@@ -0,0 +1,325 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2020, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import gettext from 'sources/gettext';
|
||||
import url_for from 'sources/url_for';
|
||||
import $ from 'jquery';
|
||||
import Alertify from 'pgadmin.alertifyjs';
|
||||
import pgAdmin from 'sources/pgadmin';
|
||||
import Backform from 'pgadmin.backform';
|
||||
import macroModel from 'sources/sqleditor/macro_model';
|
||||
import axios from 'axios';
|
||||
|
||||
let MacroDialog = {
|
||||
'dialog': function(handler) {
|
||||
let title = gettext('Manage Macros');
|
||||
|
||||
// Check the alertify dialog already loaded then delete it to clear
|
||||
// the cache
|
||||
if (Alertify.macroDialog) {
|
||||
delete Alertify.macroDialog;
|
||||
}
|
||||
|
||||
// Create Dialog
|
||||
Alertify.dialog('macroDialog', function factory() {
|
||||
let $container = $('<div class=\'macro_dialog\'></div>');
|
||||
return {
|
||||
main: function() {
|
||||
this.set('title', '<i class="fa fa-scroll sql-icon-lg" aria-hidden="true" role="img"></i> ' + gettext('Manage Macros'));
|
||||
},
|
||||
build: function() {
|
||||
this.elements.content.appendChild($container.get(0));
|
||||
Alertify.pgDialogBuild.apply(this);
|
||||
},
|
||||
setup: function() {
|
||||
return {
|
||||
buttons: [{
|
||||
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('Help'),
|
||||
'aria-label': gettext('Help'),
|
||||
url: url_for('help.static', {
|
||||
'filename': 'querytool.html',
|
||||
}),
|
||||
},
|
||||
}, {
|
||||
text: gettext('Cancel'),
|
||||
key: 27,
|
||||
className: 'btn btn-secondary fa fa-times pg-alertify-button',
|
||||
'data-btn-name': 'cancel',
|
||||
}, {
|
||||
text: gettext('Save'),
|
||||
className: 'btn btn-primary fa fa-save pg-alertify-button',
|
||||
'data-btn-name': 'ok',
|
||||
}],
|
||||
// Set options for dialog
|
||||
options: {
|
||||
title: title,
|
||||
//disable both padding and overflow control.
|
||||
padding: !1,
|
||||
overflow: !1,
|
||||
model: 0,
|
||||
resizable: true,
|
||||
maximizable: true,
|
||||
pinnable: false,
|
||||
closableByDimmer: false,
|
||||
modal: false,
|
||||
autoReset: false,
|
||||
},
|
||||
};
|
||||
},
|
||||
hooks: {
|
||||
// triggered when the dialog is closed
|
||||
onclose: function() {
|
||||
if (this.view) {
|
||||
this.macroCollectionModel.stopSession();
|
||||
this.view.model.stopSession();
|
||||
this.view.remove({
|
||||
data: true,
|
||||
internal: true,
|
||||
silent: true,
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
prepare: function() {
|
||||
let self = this;
|
||||
$container.html('');
|
||||
// Status bar
|
||||
this.statusBar = $(
|
||||
'<div class=\'pg-prop-status-bar 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> ' +
|
||||
' </div> ' +
|
||||
'</div>').appendTo($container);
|
||||
|
||||
// To show progress on filter Saving/Updating on AJAX
|
||||
this.showFilterProgress = $(
|
||||
`<div id="show_filter_progress" class="pg-sp-container sql-editor-busy-fetching d-none">
|
||||
<div class="pg-sp-content">
|
||||
<div class="row"><div class="col-12 pg-sp-icon sql-editor-busy-icon"></div></div>
|
||||
<div class="row"><div class="col-12 pg-sp-text sql-editor-busy-text">` + gettext('Loading data...') + `</div></div>
|
||||
</div>
|
||||
</div>`
|
||||
).appendTo($container);
|
||||
|
||||
self.macroCollectionModel = macroModel(handler.transId);
|
||||
|
||||
let fields = Backform.generateViewSchema(
|
||||
null, self.macroCollectionModel, 'edit', null, null, true
|
||||
);
|
||||
|
||||
let ManageMacroDialog = Backform.Dialog.extend({
|
||||
template: {
|
||||
'panel': _.template(
|
||||
'<div role="tabpanel" tabindex="-1" class="tab-pane <%=label%> <%=tabPanelCodeClass%> pg-el-sm-12 pg-el-md-12 pg-el-lg-12 pg-el-12 fade" id="<%=cId%>"></div>'
|
||||
),
|
||||
},
|
||||
render: function() {
|
||||
this.cleanup();
|
||||
|
||||
var m = this.model,
|
||||
controls = this.controls,
|
||||
tmpls = this.template,
|
||||
dialog_obj = this,
|
||||
idx = (this.tabIndex * 100),
|
||||
evalF = function(f, d, model) {
|
||||
return (_.isFunction(f) ? !!f.apply(d, [model]) : !!f);
|
||||
};
|
||||
|
||||
this.$el
|
||||
.empty()
|
||||
.attr('role', 'tabpanel')
|
||||
.attr('class', _.result(this, 'tabPanelClassName'));
|
||||
m.panelEl = this.$el;
|
||||
|
||||
var tabContent = $('<div class="tab-content pg-el-sm-12 pg-el-md-12 pg-el-lg-12 pg-el-12 macro-tab"></div>')
|
||||
.appendTo(this.$el);
|
||||
|
||||
_.each(this.schema, function(o) {
|
||||
idx++;
|
||||
if (!o.version_compatible || !evalF(o.visible, o, m)) {
|
||||
return;
|
||||
}
|
||||
var el = $((tmpls['panel'])(_.extend(o, {
|
||||
'tabIndex': idx,
|
||||
'tabPanelCodeClass': o.tabPanelCodeClass ? o.tabPanelCodeClass : '',
|
||||
})))
|
||||
.appendTo(tabContent)
|
||||
.removeClass('collapse').addClass('collapse');
|
||||
|
||||
o.fields.each(function(f) {
|
||||
var cntr = new(f.get('control'))({
|
||||
field: f,
|
||||
model: m,
|
||||
dialog: dialog_obj,
|
||||
tabIndex: idx,
|
||||
});
|
||||
el.append(cntr.render().$el);
|
||||
controls.push(cntr);
|
||||
});
|
||||
});
|
||||
|
||||
tabContent.find('.tab-pane').first().addClass('active show');
|
||||
|
||||
return this;
|
||||
},
|
||||
});
|
||||
|
||||
let view = self.view = new ManageMacroDialog({
|
||||
el: '<div></div>',
|
||||
model: self.macroCollectionModel,
|
||||
schema: fields,
|
||||
});
|
||||
|
||||
self.macroCollectionModel.fetch({
|
||||
success: function() {
|
||||
|
||||
// We got the latest attributes of the object. Render the view
|
||||
// now.
|
||||
$container.append(self.view.render().$el);
|
||||
|
||||
// Enable/disable save button and show/hide statusbar based on session
|
||||
self.view.listenTo(self.view.model, 'pgadmin-session:start', function() {
|
||||
self.view.listenTo(self.view.model, 'pgadmin-session:invalid', function(msg) {
|
||||
self.statusBar.removeClass('d-none');
|
||||
$(self.statusBar.find('.alert-text')).html(msg);
|
||||
// Disable Okay button
|
||||
self.__internal.buttons[2].element.disabled = true;
|
||||
});
|
||||
|
||||
view.listenTo(self.view.model, 'pgadmin-session:valid', function() {
|
||||
self.statusBar.addClass('d-none');
|
||||
$(self.statusBar.find('.alert-text')).html('');
|
||||
// Enable Okay button
|
||||
self.__internal.buttons[2].element.disabled = false;
|
||||
});
|
||||
});
|
||||
|
||||
view.listenTo(self.view.model, 'pgadmin-session:stop', function() {
|
||||
view.stopListening(self.view.model, 'pgadmin-session:invalid');
|
||||
view.stopListening(self.view.model, 'pgadmin-session:valid');
|
||||
});
|
||||
|
||||
// Starts monitoring changes to model
|
||||
self.view.model.startNewSession();
|
||||
|
||||
}});
|
||||
|
||||
$(this.elements.body.childNodes[0]).addClass(
|
||||
'alertify_tools_dialog_properties obj_properties'
|
||||
);
|
||||
|
||||
|
||||
|
||||
},
|
||||
// Callback functions when click on the buttons of the Alertify dialogs
|
||||
callback: function(e) {
|
||||
let self = this;
|
||||
|
||||
if (e.button.element.name == 'dialog_help') {
|
||||
e.cancel = true;
|
||||
pgAdmin.Browser.showHelp(e.button.element.name, e.button.element.getAttribute('url'),
|
||||
null, null);
|
||||
return;
|
||||
} else if (e.button['data-btn-name'] === 'ok') {
|
||||
e.cancel = true; // Do not close dialog
|
||||
|
||||
let data = self.view.model.get('macro').toJSON(true);
|
||||
|
||||
if (data == undefined || data == null) {
|
||||
self.close();
|
||||
return;
|
||||
}
|
||||
|
||||
axios.put(
|
||||
url_for('sqleditor.set_macros', {
|
||||
'trans_id': handler.transId,
|
||||
}),
|
||||
data
|
||||
).then(function (result) {
|
||||
// Hide Progress ...
|
||||
$(
|
||||
self.showFilterProgress[0]
|
||||
).addClass('d-none');
|
||||
|
||||
let macroResponse = result;
|
||||
|
||||
if (macroResponse.status) {
|
||||
setTimeout(
|
||||
function() {
|
||||
// Update Macro Menu
|
||||
let macros = self.view.model.get('macro').toJSON().filter(m => m.name !== undefined || m.name !== null);
|
||||
handler.macros = macros;
|
||||
var str = `
|
||||
<li>
|
||||
<a class="dropdown-item" id="btn-manage-macros" href="#" tabindex="0">
|
||||
<span> Manage Macros... </span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="dropdown-divider"></li>`;
|
||||
_.each(macros, function(m) {
|
||||
if (m.name) {
|
||||
str += `<li>
|
||||
<a class="dropdown-item btn-macro" data-macro-id="`+ m.id +`" href="#" tabindex="0">
|
||||
<span>` + m.name + `</span>
|
||||
<span> (` + m.key_label + `) </span>
|
||||
</a>
|
||||
</li>`;
|
||||
}
|
||||
});
|
||||
|
||||
$($.find('div.btn-group.mr-1.user_macros ul.dropdown-menu')).html($(str));
|
||||
|
||||
self.close(); // Close the dialog now
|
||||
Alertify.success(gettext('Macro updated successfully'));
|
||||
}, 10
|
||||
);
|
||||
} else {
|
||||
Alertify.alert(
|
||||
gettext('Validation Error'),
|
||||
macroResponse.result
|
||||
);
|
||||
}
|
||||
|
||||
}).catch(function (error) {
|
||||
// Hide Progress ...
|
||||
$(
|
||||
self.showFilterProgress[0]
|
||||
).addClass('d-none');
|
||||
|
||||
setTimeout(
|
||||
function() {
|
||||
Alertify.error(error.response.data.errormsg);
|
||||
}, 10
|
||||
);
|
||||
});
|
||||
|
||||
} else {
|
||||
self.close();
|
||||
}
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
Alertify.macroDialog(title).resizeTo(pgAdmin.Browser.stdW.calc(pgAdmin.Browser.stdW.lg),
|
||||
pgAdmin.Browser.stdH.calc(pgAdmin.Browser.stdH.lg));
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = MacroDialog;
|
||||
@@ -0,0 +1,224 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2020, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import gettext from 'sources/gettext';
|
||||
import pgAdmin from 'sources/pgadmin';
|
||||
import Backform from 'pgadmin.backform';
|
||||
import Backgrid from 'pgadmin.backgrid';
|
||||
import url_for from 'sources/url_for';
|
||||
import $ from 'jquery';
|
||||
import _ from 'underscore';
|
||||
import Alertify from 'pgadmin.alertifyjs';
|
||||
|
||||
export default function macroModel(transId) {
|
||||
|
||||
let MacroModel = pgAdmin.Browser.DataModel.extend({
|
||||
idAttribute: 'id',
|
||||
defaults: {
|
||||
id: undefined,
|
||||
key: undefined,
|
||||
name: undefined,
|
||||
sql: undefined,
|
||||
key_label: undefined,
|
||||
},
|
||||
schema: [{
|
||||
id: 'key_label',
|
||||
name: 'key_label',
|
||||
label: gettext('Key'),
|
||||
type: 'text',
|
||||
cell: 'string',
|
||||
editable: false,
|
||||
cellHeaderClasses: 'width_percent_10',
|
||||
headerCell: Backgrid.Extension.CustomHeaderCell,
|
||||
disabled: false,
|
||||
}, {
|
||||
id: 'name',
|
||||
name: 'name',
|
||||
label: gettext('Name'),
|
||||
cell: 'string',
|
||||
type: 'text',
|
||||
editable: true,
|
||||
cellHeaderClasses: 'width_percent_20',
|
||||
headerCell: Backgrid.Extension.CustomHeaderCell,
|
||||
disabled: false,
|
||||
}, {
|
||||
id: 'sql',
|
||||
name: 'sql',
|
||||
label: gettext('SQL'),
|
||||
cell: Backgrid.Extension.SqlCell,
|
||||
type: 'multiline',
|
||||
control: Backform.SqlCodeControl,
|
||||
editable: true,
|
||||
cellHeaderClasses: 'width_percent_70',
|
||||
headerCell: Backgrid.Extension.CustomHeaderCell,
|
||||
disabled: false,
|
||||
},
|
||||
],
|
||||
validate: function() {
|
||||
let msg = null;
|
||||
this.errorModel.clear();
|
||||
if (_.isEmpty(this.get('name')) && !(_.isEmpty(this.get('sql')))) {
|
||||
msg = gettext('Please enter macro name.');
|
||||
this.errorModel.set('name', msg);
|
||||
return msg;
|
||||
} else if (_.isEmpty(this.get('sql')) && !(_.isEmpty(this.get('name')))) {
|
||||
msg = gettext('Please enter macro sql.');
|
||||
this.errorModel.set('sql', msg);
|
||||
return msg;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
});
|
||||
|
||||
let MacroCollectionModel = pgAdmin.Browser.DataModel.extend({
|
||||
defaults: {
|
||||
macro: undefined,
|
||||
},
|
||||
urlRoot: url_for('sqleditor.get_macros', {'trans_id': transId}),
|
||||
schema: [{
|
||||
id: 'macro',
|
||||
name: 'macro',
|
||||
label: gettext('Macros'),
|
||||
model: MacroModel,
|
||||
editable: true,
|
||||
type: 'collection',
|
||||
control: Backform.SubNodeCollectionControl.extend({
|
||||
showGridControl: function(data) {
|
||||
var self = this,
|
||||
gridBody = $('<div class=\'pgadmin-control-group backgrid form-group pg-el-12 object subnode\'></div>');
|
||||
|
||||
var subnode = data.subnode.schema ? data.subnode : data.subnode.prototype,
|
||||
gridSchema = Backform.generateGridColumnsFromModel(
|
||||
data.node_info, subnode, this.field.get('mode'), data.columns, data.schema_node
|
||||
);
|
||||
|
||||
// Clean up existing grid if any (in case of re-render)
|
||||
if (self.grid) {
|
||||
self.grid.remove();
|
||||
}
|
||||
|
||||
// Set visibility of Add button
|
||||
if (data.disabled || data.canAdd == false) {
|
||||
$(gridBody).find('button.add').remove();
|
||||
}
|
||||
|
||||
// Insert Clear Cell into Grid
|
||||
gridSchema.columns.unshift({
|
||||
name: 'pg-backform-clear',
|
||||
label: '<i aria-label="' + gettext('Clear row') + '" class="fa fa-eraser" title="' + gettext('Clear row') + '"></i>',
|
||||
cell: Backgrid.Extension.ClearCell,
|
||||
editable: false,
|
||||
cell_priority: -1,
|
||||
sortable: false,
|
||||
headerCell: Backgrid.Extension.CustomHeaderCell.extend({
|
||||
className: 'header-icon-cell',
|
||||
events: {
|
||||
'click': 'clearrAll',
|
||||
},
|
||||
clearrAll: function(e) {
|
||||
e.preventDefault();
|
||||
var that = this;
|
||||
// We will check if row is deletable or not
|
||||
|
||||
Alertify.confirm(
|
||||
gettext('Clear All Rows'),
|
||||
gettext('Are you sure you wish to clear all rows?'),
|
||||
function() {
|
||||
_.each(that.collection.toJSON(), function(m) {
|
||||
that.collection.get(m.id).set({'name': null, 'sql': null});
|
||||
});
|
||||
},
|
||||
function() {
|
||||
return true;
|
||||
}
|
||||
);
|
||||
},
|
||||
render: function() {
|
||||
this.$el.empty();
|
||||
var column = this.column;
|
||||
var label = $('<button type="button" title="' + gettext('Clear row') + '" aria-label="Clear row" aria-expanded="false" tabindex="0">').html(column.get('label')).append('<span class=\'sort-caret\' aria-hidden=\'true\'></span>');
|
||||
|
||||
this.$el.append(label);
|
||||
this.$el.addClass(column.get('name'));
|
||||
this.$el.addClass(column.get('direction'));
|
||||
this.$el.attr('role', 'columnheader');
|
||||
this.$el.attr('aria-label', 'columnheader');
|
||||
this.$el.attr('alt', 'columnheader');
|
||||
this.delegateEvents();
|
||||
return this;
|
||||
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
var collection = self.model.get(data.name);
|
||||
|
||||
if (!collection) {
|
||||
collection = new(pgAdmin.Browser.Node.Collection)(null, {
|
||||
handler: self.model.handler || self.model,
|
||||
model: data.model,
|
||||
top: self.model.top || self.model,
|
||||
silent: true,
|
||||
});
|
||||
self.model.set(data.name, collection, {
|
||||
silent: true,
|
||||
});
|
||||
}
|
||||
|
||||
var cellEditing = function(args) {
|
||||
var ctx = this,
|
||||
cell = args[0];
|
||||
// Search for any other rows which are open.
|
||||
this.each(function(m) {
|
||||
// Check if row which we are about to close is not current row.
|
||||
if (cell.model != m) {
|
||||
var idx = ctx.indexOf(m);
|
||||
if (idx > -1) {
|
||||
var row = grid.body.rows[idx],
|
||||
rowEditCell = row.$el.find('.subnode-edit-in-process').parent();
|
||||
// Only close row if it's open.
|
||||
if (rowEditCell.length > 0) {
|
||||
var event = new Event('click');
|
||||
rowEditCell[0].dispatchEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
// Listen for any row which is about to enter in edit mode.
|
||||
collection.on('enteringEditMode', cellEditing, collection);
|
||||
|
||||
// Initialize a new Grid instance
|
||||
var grid = self.grid = new Backgrid.Grid({
|
||||
columns: gridSchema.columns,
|
||||
collection: collection,
|
||||
row: this.row,
|
||||
className: 'backgrid table presentation table-bordered table-noouter-border table-hover',
|
||||
});
|
||||
|
||||
// Render subNode grid
|
||||
var subNodeGrid = grid.render().$el;
|
||||
|
||||
var $dialog = gridBody.append(subNodeGrid);
|
||||
|
||||
return $dialog;
|
||||
},
|
||||
}),
|
||||
columns: ['key_label', 'name', 'sql'],
|
||||
visible: true,
|
||||
}],
|
||||
validate: function() {
|
||||
return null;
|
||||
},
|
||||
});
|
||||
|
||||
let model = new MacroCollectionModel();
|
||||
return model;
|
||||
}
|
||||
@@ -39,6 +39,11 @@ let queryToolActions = {
|
||||
$('.sql-editor-message').html('');
|
||||
},
|
||||
|
||||
executeMacro: function (sqlEditorController, MacroId) {
|
||||
this._clearMessageTab();
|
||||
sqlEditorController.check_data_changes_to_execute_query(null, false, MacroId);
|
||||
},
|
||||
|
||||
executeQuery: function (sqlEditorController) {
|
||||
this._clearMessageTab();
|
||||
sqlEditorController.check_data_changes_to_execute_query();
|
||||
|
||||
@@ -359,3 +359,31 @@ table tr th button {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.backgrid .sql-cell .CodeMirror-scroll {
|
||||
overflow: hidden !important;
|
||||
}
|
||||
|
||||
.backgrid .sql-cell .cm-s-default {
|
||||
height: 50px !important;
|
||||
}
|
||||
|
||||
.backgrid .sql-cell .CodeMirror-hscrollbar > div {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.backgrid .sql-cell .CodeMirror-hscrollbar {
|
||||
overflow-x: hidden !important;
|
||||
}
|
||||
|
||||
.backgrid .sql-cell .CodeMirror-vscrollbar {
|
||||
overflow-y: hidden !important;
|
||||
}
|
||||
|
||||
.backgrid .sql-cell .CodeMirror-sizer {
|
||||
padding-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.backgrid .sql-cell .CodeMirror-scrollbar-filler {
|
||||
display: none !important;
|
||||
}
|
||||
Reference in new issue
Block a user