diff --git a/docs/en_US/debugger.rst b/docs/en_US/debugger.rst index 99fcaa85c..6c646100f 100644 --- a/docs/en_US/debugger.rst +++ b/docs/en_US/debugger.rst @@ -81,6 +81,8 @@ Use the fields on the *Debugger* dialog to provide a value for each parameter: Provide values required by the program, and click the *Debug* button to start stepping through the program. +The values of the arguments provided here are saved. The values will be pre-filled +next time the dialog opens. To clear the values, use the *Clear All* button. .. image:: images/debug_step_in.png :alt: Debugger step-in demo diff --git a/docs/en_US/images/debug_params.png b/docs/en_US/images/debug_params.png old mode 100755 new mode 100644 index 8915fae49..dcc6c630f Binary files a/docs/en_US/images/debug_params.png and b/docs/en_US/images/debug_params.png differ diff --git a/docs/en_US/release_notes_4_19.rst b/docs/en_US/release_notes_4_19.rst index bd622de2c..b4866abcc 100644 --- a/docs/en_US/release_notes_4_19.rst +++ b/docs/en_US/release_notes_4_19.rst @@ -28,6 +28,7 @@ Bug fixes | `Issue #4996 `_ - Improve the style of the highlighted code after query execution for Dark mode. | `Issue #5058 `_ - Ensure that AlertifyJS should not be visible as a title for alert dialog. | `Issue #5077 `_ - Changed background pattern for geometry viewer to use #fff for all themes. +| `Issue #5101 `_ - Fix an issue where debugger not showing all arguments anymore after hitting SQL error while debugging. | `Issue #5107 `_ - Set proper focus on tab navigation for file manager dialog. | `Issue #5115 `_ - Fix an issue where command and statements were parsed incorrectly for Rules. | `Issue #5142 `_ - Ensure that all the transactions should be canceled before closing the connections when a server is disconnected using pgAdmin. diff --git a/web/pgadmin/static/js/backgrid.pgadmin.js b/web/pgadmin/static/js/backgrid.pgadmin.js index 4ce46d0bf..bb249268e 100644 --- a/web/pgadmin/static/js/backgrid.pgadmin.js +++ b/web/pgadmin/static/js/backgrid.pgadmin.js @@ -1916,6 +1916,58 @@ define([ }, }); + Backgrid.BooleanCell = Backgrid.BooleanCell.extend({ + className: 'boolean-cell', + + enterEditMode: function() { + this.$el.addClass('editor'); + $(this.$el.find('input[type=checkbox]')).trigger('focus'); + }, + + exitEditMode: function() { + this.$el.removeClass('editor'); + }, + + events: { + 'change input': 'onChange', + 'blur input': 'exitEditMode', + 'keydown': 'onKeyDown', + }, + + onChange: function(e) { + var model = this.model, + column = this.column, + val = this.formatter.toRaw(this.$input.prop('checked'), model); + + this.enterEditMode(); + // on bootstrap change we also need to change model's value + model.set(column.get('name'), val); + model.trigger('backgrid:edited', model, column, new Backgrid.Command(e)); + }, + + render: function () { + this.$el.empty(); + var model = this.model, column = this.column; + var editable = Backgrid.callByNeed(column.editable(), column, model); + var align_center = column.get('align_center') || false; + let checked = this.formatter.fromRaw(model.get(column.get('name')), model); + let id = `column.get('name')_${_.uniqueId()}`; + + this.$el.empty(); + this.$el.append( + $(`
+ + +
`) + ); + this.$input = this.$el.find('input'); + this.delegateEvents(); + return this; + }, + }); + return Backgrid; }); diff --git a/web/pgadmin/tools/debugger/__init__.py b/web/pgadmin/tools/debugger/__init__.py index e75e2eb70..2336d538d 100644 --- a/web/pgadmin/tools/debugger/__init__.py +++ b/web/pgadmin/tools/debugger/__init__.py @@ -241,7 +241,7 @@ class DebuggerModule(PgAdminModule): 'debugger.start_execution', 'debugger.set_breakpoint', 'debugger.clear_all_breakpoint', 'debugger.deposit_value', 'debugger.select_frame', 'debugger.get_arguments', - 'debugger.set_arguments', + 'debugger.set_arguments', 'debugger.clear_arguments', 'debugger.poll_end_execution_result', 'debugger.poll_result' ] @@ -1797,9 +1797,10 @@ def set_arguments_sqlite(sid, did, scid, func_id): db.session.add(debugger_func_args) - db.session.commit() + db.session.commit() except Exception as e: + db.session.rollback() current_app.logger.exception(e) return make_json_response( status=410, @@ -1810,6 +1811,51 @@ def set_arguments_sqlite(sid, did, scid, func_id): return make_json_response(data={'status': True, 'result': 'Success'}) +@blueprint.route( + '/clear_arguments////', + methods=['POST'], endpoint='clear_arguments' +) +@login_required +def clear_arguments_sqlite(sid, did, scid, func_id): + """ + clear_arguments_sqlite(sid, did, scid, func_id) + + This method is responsible for clearing function arguments + from sqlite database + + Parameters: + sid + - Server Id + did + - Database Id + scid + - Schema Id + func_id + - Function Id + """ + + try: + db.session.query(DebuggerFunctionArguments) \ + .filter(DebuggerFunctionArguments.server_id == sid, + DebuggerFunctionArguments.database_id == did, + DebuggerFunctionArguments.schema_id == scid, + DebuggerFunctionArguments.function_id == func_id) \ + .delete() + + db.session.commit() + + except Exception as e: + db.session.rollback() + current_app.logger.exception(e) + return make_json_response( + status=410, + success=0, + errormsg=str(e) + ) + + return make_json_response(data={'status': True, 'result': 'Success'}) + + def convert_data_to_dict(conn, result): """ This function helps us to convert result set into dict diff --git a/web/pgadmin/tools/debugger/static/js/debugger_ui.js b/web/pgadmin/tools/debugger/static/js/debugger_ui.js index cab459476..91f97a471 100644 --- a/web/pgadmin/tools/debugger/static/js/debugger_ui.js +++ b/web/pgadmin/tools/debugger/static/js/debugger_ui.js @@ -69,7 +69,7 @@ define([ // As we are getting this value as text from sqlite database so we need to type cast it. if (model.get('value') != undefined) { model.set({ - 'value': parseInt(model.get('value')), + 'value': isNaN(parseInt(model.get('value'))) ? null : parseInt(model.get('value')), }, { silent: true, }); @@ -176,6 +176,7 @@ define([ this.set('debug_info', debug_info); this.set('restart_debug', restart_debug); this.set('trans_id', trans_id); + this.set('is_edb_proc', is_edb_proc); // Variables to store the data sent from sqlite database var func_args_data = this.func_args_data = []; @@ -289,6 +290,7 @@ define([ label: gettext('Null?'), type: 'boolean', cell: 'boolean', + align_center: true, }, { name: 'expr', @@ -296,6 +298,7 @@ define([ type: 'boolean', cellFunction: cellExprControlFunction, editable: disableExpressionControl, + align_center: true, }, { name: 'value', @@ -304,6 +307,7 @@ define([ editable: true, cellFunction: cellFunction, headerCell: value_header, + align_center: true, }, { name: 'use_default', @@ -413,12 +417,12 @@ define([ // Need to update the func_obj variable from sqlite database if available if (func_args_data.length != 0) { for (i = 0; i < func_args_data.length; i++) { + index = func_args_data[i]['arg_id']; if (debug_info['proargmodes'] != null && - (argmode[i] == 'o' && !is_edb_proc)) { + (argmode[index] == 'o' && !is_edb_proc)) { continue; } - index = func_args_data[i]['arg_id']; values = []; if (argtype[index].indexOf('[]') != -1) { vals = func_args_data[i]['value'].split(','); @@ -565,14 +569,17 @@ define([ }); grid.render(); - $(this.elements.content).html(grid.el); + let wrap_div = document.createElement('div'); + wrap_div.classList.add('debugger-args'); + wrap_div.appendChild(grid.el); + $(this.elements.content).html(wrap_div); // For keyboard navigation in the grid // we'll set focus on checkbox from the first row if any var grid_checkbox = $(grid.el).find('input:checkbox').first(); if (grid_checkbox.length) { setTimeout(function() { - grid_checkbox.trigger('click'); + grid_checkbox.trigger('focus'); }, 250); } @@ -585,6 +592,9 @@ define([ setup: function() { return { buttons: [{ + text: gettext('Clear All'), + className: 'btn btn-secondary pull-left fa fa-eraser pg-alertify-button', + },{ text: gettext('Cancel'), key: 27, className: 'btn btn-secondary fa fa-times pg-alertify-button', @@ -899,6 +909,69 @@ define([ return false; } + + if (e.button.text === gettext('Clear All')) { + let self = this; + let baseUrl = null; + + if (self.setting('restart_debug') == 0) { + let selected_item = pgBrowser.tree.selected(); + let item_data = pgBrowser.tree.itemData(selected_item); + if (!item_data) + return; + + let node = pgBrowser.Nodes[item_data._type]; + let treeInfo = node.getTreeNodeHierarchy.call(node, selected_item); + + let f_id; + if (item_data._type == 'function') { + f_id = item_data._id; + } else if (item_data._type == 'procedure') { + f_id = item_data._id; + } else if (item_data._type == 'edbfunc') { + f_id = item_data._id; + } else if (item_data._type == 'edbproc') { + f_id = item_data._id; + } + + baseUrl = url_for('debugger.clear_arguments', { + 'sid': treeInfo.server._id, + 'did': treeInfo.database._id, + 'scid': treeInfo.schema._id, + 'func_id': f_id, + }); + } else { + baseUrl = url_for('debugger.clear_arguments', { + 'sid': self.setting('debug_info').server_id, + 'did': self.setting('debug_info').database_id, + 'scid': self.setting('debug_info').schema_id, + 'func_id': self.setting('debug_info').function_id, + }); + } + $.ajax({ + url: baseUrl, + method: 'POST', + data: { + 'data': JSON.stringify(args_value_list), + }, + }).done(function() { + /* Disable debug button */ + self.__internal.buttons[2].element.disabled = true; + self.main(self.setting('title'), self.setting('debug_info'), + self.setting('restart_debug'), self.setting('is_edb_proc'), + self.setting('trans_id') + ); + self.prepare(); + }).fail(function(e) { + Alertify.alert( + gettext('Clear failed'), + e.responseJSON.errormsg + ); + }); + + e.cancel = true; + return true; + } }, build: function() { Alertify.pgDialogBuild.apply(this); @@ -914,9 +987,9 @@ define([ enable the debug button otherwise disable the debug button. */ if (this.func_args_data.length == 0) { - this.__internal.buttons[1].element.disabled = true; + this.__internal.buttons[2].element.disabled = true; } else { - this.__internal.buttons[1].element.disabled = false; + this.__internal.buttons[2].element.disabled = false; } /* @@ -933,7 +1006,7 @@ define([ for (var i = 0; i < this.collection.length; i++) { if (this.collection.models[i].get('is_null')) { - obj.__internal.buttons[1].element.disabled = false; + obj.__internal.buttons[2].element.disabled = false; enable_btn = true; continue; } @@ -944,15 +1017,15 @@ define([ enable_btn = true; if (this.collection.models[i].get('use_default')) { - obj.__internal.buttons[1].element.disabled = false; + obj.__internal.buttons[2].element.disabled = false; } else { - obj.__internal.buttons[1].element.disabled = true; + obj.__internal.buttons[2].element.disabled = true; break; } } } if (!enable_btn) - obj.__internal.buttons[1].element.disabled = false; + obj.__internal.buttons[2].element.disabled = false; }; })(this) ); @@ -960,7 +1033,7 @@ define([ this.grid.listenTo(this.debuggerInputArgsColl, 'backgrid:error', (function(obj) { return function() { - obj.__internal.buttons[1].element.disabled = true; + obj.__internal.buttons[2].element.disabled = true; }; })(this) ); diff --git a/web/pgadmin/tools/debugger/static/scss/_debugger.scss b/web/pgadmin/tools/debugger/static/scss/_debugger.scss index 4fa35195f..30ace0af7 100644 --- a/web/pgadmin/tools/debugger/static/scss/_debugger.scss +++ b/web/pgadmin/tools/debugger/static/scss/_debugger.scss @@ -16,3 +16,10 @@ -ms-user-select: text; user-select: text; } + +.debugger-args { + display: block; + width: 100%; + height: 100%; + overflow: auto; +}