diff --git a/web/pgadmin/tools/debugger/__init__.py b/web/pgadmin/tools/debugger/__init__.py
index 05ae5625c..275fccb69 100644
--- a/web/pgadmin/tools/debugger/__init__.py
+++ b/web/pgadmin/tools/debugger/__init__.py
@@ -12,6 +12,7 @@
import simplejson as json
import random
import re
+import copy
from flask import url_for, Response, render_template, request, \
current_app
@@ -266,31 +267,6 @@ def index():
)
-@blueprint.route("/js/debugger_ui.js")
-@login_required
-def script_debugger_js():
- """render the debugger UI javascript file"""
- return Response(
- response=render_template("debugger/js/debugger_ui.js", _=gettext),
- status=200,
- mimetype=MIMETYPE_APP_JS
- )
-
-
-@blueprint.route("/js/debugger.js")
-@login_required
-def script_debugger_direct_js():
- """
- Render the javascript file required send and receive the response
- from server for debugging
- """
- return Response(
- response=render_template("debugger/js/debugger.js", _=gettext),
- status=200,
- mimetype=MIMETYPE_APP_JS
- )
-
-
def execute_dict_search_path(conn, sql, search_path):
sql = "SET search_path={0};".format(search_path) + sql
status, res = conn.execute_dict(sql)
@@ -1110,6 +1086,21 @@ def start_debugger_listener(trans_id):
else:
arg_type = de_inst.function_data['args_type'].split(",")
+ debugger_args_values = []
+ if de_inst.function_data['args_value']:
+ debugger_args_values = copy.deepcopy(
+ de_inst.function_data['args_value'])
+ for arg in debugger_args_values:
+ if arg['type'].endswith('[]'):
+ if arg['value'] and arg['value'] != 'NULL':
+ val_list = arg['value'][1:-1].split(',')
+ debugger_args_data = []
+ for _val in val_list:
+ debugger_args_data.append({
+ 'value': _val
+ })
+ arg['value'] = debugger_args_data
+
# Below are two different template to execute and start executer
if manager.server_type != 'pg' and manager.version < 90300:
str_query = render_template(
@@ -1118,7 +1109,7 @@ def start_debugger_listener(trans_id):
is_func=de_inst.function_data['is_func'],
lan_name=de_inst.function_data['language'],
ret_type=de_inst.function_data['return_type'],
- data=de_inst.function_data['args_value'],
+ data=debugger_args_values,
arg_type=arg_type,
args_mode=arg_mode
)
@@ -1128,7 +1119,7 @@ def start_debugger_listener(trans_id):
func_name=func_name,
is_func=de_inst.function_data['is_func'],
ret_type=de_inst.function_data['return_type'],
- data=de_inst.function_data['args_value'],
+ data=debugger_args_values,
is_ppas_database=de_inst.function_data['is_ppas_database']
)
@@ -1797,18 +1788,10 @@ def get_array_string(data, i):
:return: Array string.
"""
array_string = ''
- if data[i]['value'].__class__.__name__ in (
- 'list') and data[i]['value']:
- for k in range(0, len(data[i]['value'])):
- if data[i]['value'][k]['value'] is None:
- array_string += 'NULL'
- else:
- array_string += str(data[i]['value'][k]['value'])
- if k != (len(data[i]['value']) - 1):
- array_string += ','
- elif data[i]['value'].__class__.__name__ in (
- 'list') and not data[i]['value']:
- array_string = ''
+
+ if data[i]['value']:
+ array_string = data[i]['value'][1:-1].split(',')
+ array_string = ','.join(array_string)
else:
array_string = data[i]['value']
@@ -1853,7 +1836,8 @@ def set_arguments_sqlite(sid, did, scid, func_id):
# handle the Array list sent from the client
array_string = ''
- if 'value' in data[i]:
+ if 'is_array_value' in data[i] and 'value' in data[i] and data[i][
+ 'is_array_value']:
array_string = get_array_string(data, i)
# Check if data is already available in database then update the
diff --git a/web/pgadmin/tools/debugger/static/js/DebuggerConstants.js b/web/pgadmin/tools/debugger/static/js/DebuggerConstants.js
index 64e7c2e37..379409f73 100644
--- a/web/pgadmin/tools/debugger/static/js/DebuggerConstants.js
+++ b/web/pgadmin/tools/debugger/static/js/DebuggerConstants.js
@@ -14,6 +14,7 @@ export const DEBUGGER_EVENTS = {
TRIGGER_CONTINUE_DEBUGGING: 'TRIGGER_CONTINUE_DEBUGGING',
TRIGGER_STEPOVER_DEBUGGING: 'TRIGGER_STEPOVER_DEBUGGING',
TRIGGER_STEINTO_DEBUGGING: 'TRIGGER_STEINTO_DEBUGGING',
+ TRIGGER_RESET_LAYOUT: 'TRIGGER_RESET_LAYOUT',
SET_STACK: 'SET_STACK',
SET_MESSAGES: 'SET_MESSAGES',
diff --git a/web/pgadmin/tools/debugger/static/js/DebuggerModule.js b/web/pgadmin/tools/debugger/static/js/DebuggerModule.js
index cc5016a6e..56a111979 100644
--- a/web/pgadmin/tools/debugger/static/js/DebuggerModule.js
+++ b/web/pgadmin/tools/debugger/static/js/DebuggerModule.js
@@ -431,7 +431,6 @@ export default class Debugger {
setDebuggerTitle(panel, browser_preferences, label, newTreeInfo.schema.label, db_label, null, self.pgBrowser);
panel.focus();
-
// Register Panel Closed event
panel.on(self.wcDocker.EVENT.CLOSED, function () {
var closeUrl = url_for('debugger.close', {
diff --git a/web/pgadmin/tools/debugger/static/js/components/DebuggerArgs.ui.js b/web/pgadmin/tools/debugger/static/js/components/DebuggerArgs.ui.js
index ef889f643..b2c41a954 100644
--- a/web/pgadmin/tools/debugger/static/js/components/DebuggerArgs.ui.js
+++ b/web/pgadmin/tools/debugger/static/js/components/DebuggerArgs.ui.js
@@ -20,9 +20,9 @@ class ArgementsCollectionSchema extends BaseUISchema {
value: undefined,
use_default: false,
default_value: undefined,
+ isArrayType: false,
+ isValid: true
});
-
- this.isValid = true;
}
get baseFields() {
@@ -63,11 +63,43 @@ class ArgementsCollectionSchema extends BaseUISchema {
label: gettext('Value'),
type: 'text',
cell: (state) => {
- let dtype = 'text';
- if(state.type == 'date') {
- dtype = 'datetimepicker';
- } else if(state.type == 'numeric') {
- dtype = 'numeric';
+ let dtype = '';
+ state.isArrayType = false;
+ if(state.type.indexOf('[]') != -1) {
+ state.isArrayType = true;
+ dtype = 'text';
+ } else {
+ switch (state.type) {
+ case 'boolean':
+ dtype = 'checkbox';
+ break;
+ case 'integer':
+ case 'smallint':
+ case 'bigint':
+ case 'serial':
+ case 'smallserial':
+ case 'bigserial':
+ case 'oid':
+ case 'cid':
+ case 'xid':
+ case 'tid':
+ dtype = 'int';
+ break;
+ case 'real':
+ case 'numeric':
+ case 'double precision':
+ case 'decimal':
+ dtype = 'numeric';
+ break;
+ case 'string':
+ dtype = 'text';
+ break;
+ case 'date':
+ dtype = 'datetimepicker';
+ break;
+ default:
+ dtype = 'text';
+ }
}
return {
@@ -77,7 +109,7 @@ class ArgementsCollectionSchema extends BaseUISchema {
placeholder: gettext('YYYY-MM-DD'),
autoOk: true, pickerType: 'Date', ampm: false,
})
- }
+ },
};
},
editable: true,
@@ -101,6 +133,27 @@ class ArgementsCollectionSchema extends BaseUISchema {
];
}
+ isValidArray(val) {
+ val = val?.trim();
+ return !(val != '' && (val.charAt(0) != '{' || val.charAt(val.length - 1) != '}'));
+ }
+
+ validate(state, setError) {
+ if(state.isArrayType && state.value && state.value != '') {
+ let isValid = this.isValidArray(state.value);
+ state.isValid = isValid;
+ if(isValid) {
+ setError('value', null);
+ } else {
+ setError('value', 'Arrays must start with "{" and end with "}"');
+ return true;
+ }
+ } else {
+ state.isValid = true;
+ }
+ return false;
+ }
+
}
export class DebuggerArgumentSchema extends BaseUISchema {
diff --git a/web/pgadmin/tools/debugger/static/js/components/DebuggerArgumentComponent.jsx b/web/pgadmin/tools/debugger/static/js/components/DebuggerArgumentComponent.jsx
index f553aa840..29d0a3f20 100644
--- a/web/pgadmin/tools/debugger/static/js/components/DebuggerArgumentComponent.jsx
+++ b/web/pgadmin/tools/debugger/static/js/components/DebuggerArgumentComponent.jsx
@@ -7,7 +7,6 @@
//
//////////////////////////////////////////////////////////////
-import _ from 'lodash';
import PropTypes from 'prop-types';
import React, { useEffect, useRef } from 'react';
@@ -22,6 +21,7 @@ import url_for from 'sources/url_for';
import gettext from 'sources/gettext';
import * as commonUtils from 'sources/utils';
import pgAdmin from 'sources/pgadmin';
+import Loader from 'sources/components/Loader';
import Alertify from 'pgadmin.alertifyjs';
import SchemaView from '../../../../../static/js/SchemaView';
@@ -76,6 +76,7 @@ export default function DebuggerArgumentComponent({ debuggerInfo, restartDebug,
const debuggerArgsData = useRef([]);
const [loadArgs, setLoadArgs] = React.useState(0);
const [isDisableDebug, setIsDisableDebug] = React.useState(true);
+ const [loaderText, setLoaderText] = React.useState('');
const debuggerFinalArgs = useRef([]);
const InputArgIds = useRef([]);
const wcDocker = window.wcDocker;
@@ -246,7 +247,7 @@ export default function DebuggerArgumentComponent({ debuggerInfo, restartDebug,
}
function setFuncObj(funcArgsData, argMode, argType, argName, defValList, isUnnamedParam=false) {
- let index, values, vals, funcObj=[];
+ let index, values, funcObj=[];
for(const argData of funcArgsData) {
index = argData['arg_id'];
if (debuggerInfo['proargmodes'] != null &&
@@ -255,13 +256,8 @@ export default function DebuggerArgumentComponent({ debuggerInfo, restartDebug,
}
values = [];
- if (argType[index].indexOf('[]') != -1) {
- vals = argData['value'].split(',');
- _.each(vals, function (val) {
- values.push({
- 'value': val,
- });
- });
+ if (argType[index].indexOf('[]') != -1 && argData['value'].length > 0) {
+ values = `{${argData['value']}}`;
} else {
values = argData['value'];
}
@@ -451,6 +447,7 @@ export default function DebuggerArgumentComponent({ debuggerInfo, restartDebug,
});
function clearArgs() {
+ setLoaderText('Loading...');
setLoadArgs(0);
let base_url = null;
@@ -486,11 +483,13 @@ export default function DebuggerArgumentComponent({ debuggerInfo, restartDebug,
/* setTimeout required to get updated argruments as 'Clear All' will delete all saved arguments form sqlite db. */
setTimeout(() => {
/* Reload the debugger arguments */
+ setLoaderText('');
setLoadArgs(Math.floor(Math.random() * 1000));
/* Disable debug button */
setIsDisableDebug(true);
}, 100);
}).catch(function (er) {
+ setLoaderText('');
Notify.alert(
gettext('Clear failed'),
er.responseJSON.errormsg
@@ -500,17 +499,23 @@ export default function DebuggerArgumentComponent({ debuggerInfo, restartDebug,
function setDebuggingArgs(argsList, argSet) {
if (argsList.length === 0) {
- debuggerFinalArgs.current.changed.forEach(changedArg => {
- argSet.push(changedArg.name);
- argsList.push(changedArg);
- });
-
+ // Add all parameters
debuggerArgsData.current.aregsCollection.forEach(arg => {
if (!argSet.includes(arg.name)) {
argSet.push(arg.name);
argsList.push(arg);
}
});
+
+ // Update values if any change in the args.
+ debuggerFinalArgs.current.changed.forEach(changedArg => {
+ argsList.forEach((el, _index) => {
+ if(changedArg.name == el.name) {
+ argsList[_index] = changedArg;
+ }
+ });
+ });
+
}
}
@@ -567,6 +572,7 @@ export default function DebuggerArgumentComponent({ debuggerInfo, restartDebug,
'is_expression': arg.expr ? 1 : 0,
'use_default': arg.use_default ? 1 : 0,
'value': arg.value,
+ 'is_array_value': arg?.isArrayType,
});
} else {
// Below will format the data to be stored in sqlite database
@@ -580,6 +586,7 @@ export default function DebuggerArgumentComponent({ debuggerInfo, restartDebug,
'is_expression': arg.expr ? 1 : 0,
'use_default': arg.use_default ? 1 : 0,
'value': debuggerInfo.value,
+ 'is_array_value': arg?.isArrayType,
});
}
@@ -684,6 +691,7 @@ export default function DebuggerArgumentComponent({ debuggerInfo, restartDebug,
function startDebugging() {
var self = this;
+ setLoaderText('Starting debugger.');
/* Initialize the target once the debug button is clicked and create asynchronous connection
and unique transaction ID If the debugging is started again then treeInfo is already stored. */
var [treeInfo, d] = getSelectedNodeData();
@@ -693,7 +701,7 @@ export default function DebuggerArgumentComponent({ debuggerInfo, restartDebug,
var sqliteFuncArgsList = [];
var intCount = 0;
- let argsList = debuggerFinalArgs.current?.changed ? [] : debuggerArgsData.current.aregsCollection;
+ let argsList = []; //debuggerFinalArgs.current?.changed ? [] : debuggerArgsData.current.aregsCollection;
let argSet = [];
setDebuggingArgs(argsList, argSet);
@@ -789,6 +797,7 @@ export default function DebuggerArgumentComponent({ debuggerInfo, restartDebug,
})
.then(function () {/*This is intentional (SonarQube)*/ })
.catch((error) => {
+ setLoaderText('');
Notify.alert(
gettext('Error occured: '),
gettext(error.response.data)
@@ -796,9 +805,10 @@ export default function DebuggerArgumentComponent({ debuggerInfo, restartDebug,
});
/* Close the debugger modal dialog */
props.closeModal();
-
+ setLoaderText('');
})
.catch(function (error) {
+ setLoaderText('');
Notify.alert(
gettext('Debugger Target Initialization Error'),
gettext(error.response.data)
@@ -825,7 +835,7 @@ export default function DebuggerArgumentComponent({ debuggerInfo, restartDebug,
gettext(error.response.data)
);
});
-
+ setLoaderText('');
// Set the new input arguments given by the user during debugging
var _Url = url_for('debugger.set_arguments', {
'sid': debuggerInfo.server_id,
@@ -840,6 +850,7 @@ export default function DebuggerArgumentComponent({ debuggerInfo, restartDebug,
})
.then(function () {/*This is intentional (SonarQube)*/ })
.catch(function (error) {
+ setLoaderText('');
Notify.alert(
gettext('Debugger Listener Startup Set Arguments Error'),
gettext(error.response.data)
@@ -855,34 +866,43 @@ export default function DebuggerArgumentComponent({ debuggerInfo, restartDebug,
{
loadArgs > 0 &&
- {
- let isValid = false;
- let skipStep = false;
- if('_sessData' in debuggerArgsSchema.current) {
- isValid = true;
- debuggerArgsSchema.current._sessData.aregsCollection.forEach((data)=> {
+ <>
+
+ {
+ let isValid = false;
+ let skipStep = false;
+ if('_sessData' in debuggerArgsSchema.current) {
+ isValid = true;
+ debuggerArgsSchema.current._sessData.aregsCollection.forEach((data)=> {
- if(skipStep) {return;}
+ if(skipStep) {return;}
- if((data.is_null || data.use_default || data?.value?.toString()?.length > 0) && isValid) {
- isValid = true;
- } else {
- isValid = false;
- skipStep = true;
- }
- });
- }
- setIsDisableDebug(!isValid);
- debuggerFinalArgs.current = changedData.aregsCollection;
- }}
- />
+ if((data.is_null || data.use_default || data?.value?.toString()?.length > 0) && isValid) {
+ isValid = true;
+ } else {
+ isValid = false;
+ skipStep = true;
+ }
+
+ if(!data.isValid) {
+ isValid = false;
+ skipStep = true;
+ }
+
+ });
+ }
+ setIsDisableDebug(!isValid);
+ debuggerFinalArgs.current = changedData.aregsCollection;
+ }}
+ />
+ >
}
@@ -895,7 +915,7 @@ export default function DebuggerArgumentComponent({ debuggerInfo, restartDebug,
{ props.closeModal(); }} startIcon={ { props.closeModal(); }} />}>
{gettext('Cancel')}
- }
+ }
disabled={isDisableDebug}
onClick={() => { startDebugging(); }}>
{gettext('Debug')}
diff --git a/web/pgadmin/tools/debugger/static/js/components/DebuggerComponent.jsx b/web/pgadmin/tools/debugger/static/js/components/DebuggerComponent.jsx
index 7d535d3db..291c1256d 100644
--- a/web/pgadmin/tools/debugger/static/js/components/DebuggerComponent.jsx
+++ b/web/pgadmin/tools/debugger/static/js/components/DebuggerComponent.jsx
@@ -1132,6 +1132,11 @@ export default function DebuggerComponent({ pgAdmin, selectedNodeInfo, panel, ev
LayoutHelper.focus(docker.current, panelId);
});
+ eventBus.current.registerListener(
+ DEBUGGER_EVENTS.TRIGGER_RESET_LAYOUT, () => {
+ docker.current?.resetLayout();
+ });
+
}, []);
diff --git a/web/pgadmin/tools/debugger/static/js/components/ToolBar.jsx b/web/pgadmin/tools/debugger/static/js/components/ToolBar.jsx
index 1516412d7..6718a0541 100644
--- a/web/pgadmin/tools/debugger/static/js/components/ToolBar.jsx
+++ b/web/pgadmin/tools/debugger/static/js/components/ToolBar.jsx
@@ -17,6 +17,7 @@ import FiberManualRecordIcon from '@material-ui/icons/FiberManualRecord';
import NotInterestedIcon from '@material-ui/icons/NotInterested';
import StopIcon from '@material-ui/icons/Stop';
import HelpIcon from '@material-ui/icons/HelpRounded';
+import RotateLeftRoundedIcon from '@material-ui/icons/RotateLeftRounded';
import gettext from 'sources/gettext';
import { shortcut_key } from 'sources/keyboard_shortcuts';
@@ -87,6 +88,10 @@ export function ToolBar() {
window.open(url, 'pgadmin_help');
};
+ const onResetLayout=() => {
+ eventBus.fireEvent(DEBUGGER_EVENTS.TRIGGER_RESET_LAYOUT);
+ };
+
useEffect(() => {
eventBus.registerListener(DEBUGGER_EVENTS.DISABLE_MENU, () => {
setDisableButton('start', true);
@@ -123,18 +128,22 @@ export function ToolBar() {
accesskey={shortcut_key(preferences?.btn_start)} />
- }
+ }
accesskey={shortcut_key(preferences?.btn_toggle_breakpoint)} onClick={() => { toggleBreakpoint(); }} />
}
accesskey={shortcut_key(preferences?.btn_clear_breakpoints)} onClick={() => { clearAllBreakpoint(); }} />
- } disabled={buttonsDisabled['stop']} onClick={() => { stop(); }}
+ } disabled={buttonsDisabled['stop']} onClick={() => { stop(); }}
accesskey={shortcut_key(preferences?.btn_stop)} />
} onClick={onHelpClick} />
+
+ }
+ onClick={onResetLayout} />
+
);
}
diff --git a/web/pgadmin/tools/debugger/static/js/debugger_utils.js b/web/pgadmin/tools/debugger/static/js/debugger_utils.js
index dc10091dc..f1f99d1bd 100644
--- a/web/pgadmin/tools/debugger/static/js/debugger_utils.js
+++ b/web/pgadmin/tools/debugger/static/js/debugger_utils.js
@@ -83,7 +83,12 @@ function getAppropriateLabel(treeInfo) {
return treeInfo.trigger_function.label;
} else if (treeInfo.trigger) {
return treeInfo.trigger.label;
- } else {
+ } else if(treeInfo.edbfunc) {
+ return treeInfo.edbfunc.label;
+ } else if(treeInfo.edbproc) {
+ return treeInfo.edbproc.label;
+ }
+ else {
return treeInfo.procedure.label;
}
}
diff --git a/web/webpack.config.js b/web/webpack.config.js
index 533a2682e..210627608 100644
--- a/web/webpack.config.js
+++ b/web/webpack.config.js
@@ -378,11 +378,11 @@ module.exports = [{
codemirror: sourceDir + '/bundle/codemirror.js',
slickgrid: sourceDir + '/bundle/slickgrid.js',
sqleditor: './pgadmin/tools/sqleditor/static/js/index.js',
- debugger: './pgadmin/tools/debugger/static/js/index.js',
schema_diff: './pgadmin/tools/schema_diff/static/js/schema_diff_hook.js',
erd_tool: './pgadmin/tools/erd/static/js/erd_tool_hook.js',
psql_tool: './pgadmin/tools/psql/static/js/index.js',
file_utils: './pgadmin/misc/file_manager/static/js/utility.js',
+ debugger: './pgadmin/tools/debugger/static/js/index.js',
'pgadmin.style': pgadminCssStyles,
pgadmin: pgadminScssStyles,
style: './pgadmin/static/css/style.css',