Enable the start debugging button once execution is completed. Fixes #7517

This commit is contained in:
Nikhil Mohite
2022-07-01 12:41:06 +05:30
committed by Akshay Joshi
parent 7d0ed90796
commit 9c745db413
7 changed files with 89 additions and 68 deletions

View File

@@ -18,3 +18,5 @@ Housekeeping
Bug fixes Bug fixes
********* *********
| `Issue #7517 <https://redmine.postgresql.org/issues/7517>`_ - Enable the start debugging button once execution is completed.

View File

@@ -985,7 +985,7 @@ def start_debugger_listener(trans_id):
# If user again start the same debug function with different arguments # If user again start the same debug function with different arguments
# then we need to save that values to session variable and database. # then we need to save that values to session variable and database.
if request.method == 'POST': if request.method == 'POST':
data = json.loads(request.values['data'], encoding='utf-8') data = json.loads(request.data, encoding='utf-8')
if data: if data:
de_inst.function_data['args_value'] = data de_inst.function_data['args_value'] = data
de_inst.update_session() de_inst.update_session()

View File

@@ -47,8 +47,8 @@ export const MENUS = {
STEPINTO: 'step-into', STEPINTO: 'step-into',
STEPOVER: 'step-over', STEPOVER: 'step-over',
STOP: 'stop', STOP: 'stop',
CONTINUE: 'continue', START: 'start',
CLEAR_ALL_BREAKPOINT: 'clear-al-breakpoint', CLEAR_ALL_BREAKPOINT: 'clear-all-breakpoint',
TOGGLE_BREAKPOINT: 'toggle-breakpoint' TOGGLE_BREAKPOINT: 'toggle-breakpoint'
}; };

View File

@@ -69,7 +69,7 @@ const useStyles = makeStyles((theme) =>
); );
export default function DebuggerArgumentComponent({ debuggerInfo, restartDebug, isEdbProc, transId, ...props }) { export default function DebuggerArgumentComponent({ debuggerInfo, restartDebug, isEdbProc, transId, pgTreeInfo, pgData, ...props }) {
const classes = useStyles(); const classes = useStyles();
const debuggerArgsSchema = useRef(new DebuggerArgumentSchema()); const debuggerArgsSchema = useRef(new DebuggerArgumentSchema());
const api = getApiInstance(); const api = getApiInstance();
@@ -85,16 +85,13 @@ export default function DebuggerArgumentComponent({ debuggerInfo, restartDebug,
var _Url = null; var _Url = null;
if (restartDebug == 0) { if (restartDebug == 0) {
var t = pgAdmin.Browser.tree,
i = t.selected(),
d = i ? t.itemData(i) : undefined;
if (!d) if (!pgData)
return; return;
var treeInfo = t.getTreeNodeHierarchy(i); var treeInfo = pgTreeInfo;
if (d._type == 'function') { if (pgData._type == 'function') {
// Get the existing function parameters available from sqlite database // Get the existing function parameters available from sqlite database
_Url = url_for('debugger.get_arguments', { _Url = url_for('debugger.get_arguments', {
'sid': treeInfo.server._id, 'sid': treeInfo.server._id,
@@ -102,7 +99,7 @@ export default function DebuggerArgumentComponent({ debuggerInfo, restartDebug,
'scid': treeInfo.schema._id, 'scid': treeInfo.schema._id,
'func_id': treeInfo.function._id, 'func_id': treeInfo.function._id,
}); });
} else if (d._type == 'procedure') { } else if (pgData._type == 'procedure') {
// Get the existing function parameters available from sqlite database // Get the existing function parameters available from sqlite database
_Url = url_for('debugger.get_arguments', { _Url = url_for('debugger.get_arguments', {
'sid': treeInfo.server._id, 'sid': treeInfo.server._id,
@@ -110,7 +107,7 @@ export default function DebuggerArgumentComponent({ debuggerInfo, restartDebug,
'scid': treeInfo.schema._id, 'scid': treeInfo.schema._id,
'func_id': treeInfo.procedure._id, 'func_id': treeInfo.procedure._id,
}); });
} else if (d._type == 'edbfunc') { } else if (pgData._type == 'edbfunc') {
// Get the existing function parameters available from sqlite database // Get the existing function parameters available from sqlite database
_Url = url_for('debugger.get_arguments', { _Url = url_for('debugger.get_arguments', {
'sid': treeInfo.server._id, 'sid': treeInfo.server._id,
@@ -118,7 +115,7 @@ export default function DebuggerArgumentComponent({ debuggerInfo, restartDebug,
'scid': treeInfo.schema._id, 'scid': treeInfo.schema._id,
'func_id': treeInfo.edbfunc._id, 'func_id': treeInfo.edbfunc._id,
}); });
} else if (d._type == 'edbproc') { } else if (pgData._type == 'edbproc') {
// Get the existing function parameters available from sqlite database // Get the existing function parameters available from sqlite database
_Url = url_for('debugger.get_arguments', { _Url = url_for('debugger.get_arguments', {
'sid': treeInfo.server._id, 'sid': treeInfo.server._id,
@@ -452,18 +449,16 @@ export default function DebuggerArgumentComponent({ debuggerInfo, restartDebug,
let base_url = null; let base_url = null;
if (restartDebug == 0) { if (restartDebug == 0) {
let selectedItem = pgAdmin.Browser.tree.selected(); if (!pgData)
let itemData = pgAdmin.Browser.tree.itemData(selectedItem);
if (!itemData)
return; return;
let treeInfo = pgAdmin.Browser.tree.getTreeNodeHierarchy(selectedItem); let treeInfo = pgTreeInfo;
base_url = url_for('debugger.clear_arguments', { base_url = url_for('debugger.clear_arguments', {
'sid': treeInfo.server._id, 'sid': treeInfo.server._id,
'did': treeInfo.database._id, 'did': treeInfo.database._id,
'scid': treeInfo.schema._id, 'scid': treeInfo.schema._id,
'func_id': itemData._id, 'func_id': pgData._id,
}); });
} else { } else {
base_url = url_for('debugger.clear_arguments', { base_url = url_for('debugger.clear_arguments', {
@@ -587,7 +582,7 @@ export default function DebuggerArgumentComponent({ debuggerInfo, restartDebug,
'is_null': arg.is_null ? 1 : 0, 'is_null': arg.is_null ? 1 : 0,
'is_expression': arg.expr ? 1 : 0, 'is_expression': arg.expr ? 1 : 0,
'use_default': arg.use_default ? 1 : 0, 'use_default': arg.use_default ? 1 : 0,
'value': debuggerInfo.value, 'value': arg.value,
'is_array_value': arg?.isArrayType, 'is_array_value': arg?.isArrayType,
}); });
} }
@@ -675,43 +670,27 @@ export default function DebuggerArgumentComponent({ debuggerInfo, restartDebug,
return baseUrl; return baseUrl;
} }
function getSelectedNodeData() {
var treeInfo, d;
if (restartDebug == 0) {
var t = pgAdmin.Browser.tree,
i = t.selected();
d = i ? t.itemData(i) : undefined;
if (!d)
return;
treeInfo = t.getTreeNodeHierarchy(i);
}
return [treeInfo, d];
}
function startDebugging() { function startDebugging() {
var self = this; var self = this;
setLoaderText('Starting debugger.'); setLoaderText('Starting debugger.');
try { try {
/* Initialize the target once the debug button is clicked and create asynchronous connection /* 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. */ and unique transaction ID If the debugging is started again then treeInfo is already stored. */
var [treeInfo, d] = getSelectedNodeData(); var treeInfo = pgTreeInfo;
if (!d) return; if (!pgData) return;
var argsValueList = []; var argsValueList = [];
var sqliteFuncArgsList = []; var sqliteFuncArgsList = [];
var intCount = 0; var intCount = 0;
let argsList = []; //debuggerFinalArgs.current?.changed ? [] : debuggerArgsData.current.aregsCollection; let argsList = [];
let argSet = []; let argSet = [];
setDebuggingArgs(argsList, argSet); setDebuggingArgs(argsList, argSet);
argsList.forEach(arg => { argsList.forEach(arg => {
checkArgsVal(arg, argsValueList); checkArgsVal(arg, argsValueList);
setSqliteFuncArgs(d, treeInfo, arg, intCount, sqliteFuncArgsList); setSqliteFuncArgs(pgData, treeInfo, arg, intCount, sqliteFuncArgsList);
intCount = intCount + 1; intCount = intCount + 1;
}); });
@@ -719,7 +698,7 @@ export default function DebuggerArgumentComponent({ debuggerInfo, restartDebug,
/* If debugging is not started again then we should initialize the target otherwise not */ /* If debugging is not started again then we should initialize the target otherwise not */
if (restartDebug == 0) { if (restartDebug == 0) {
baseUrl = checkTypeAndGetUrl(d, treeInfo); baseUrl = checkTypeAndGetUrl(pgData, treeInfo);
api({ api({
url: baseUrl, url: baseUrl,
@@ -791,7 +770,7 @@ export default function DebuggerArgumentComponent({ debuggerInfo, restartDebug,
}); });
} }
var _url = getSetArgsUrl(d, treeInfo); var _url = getSetArgsUrl(pgData, treeInfo);
api({ api({
url: _url, url: _url,
@@ -831,8 +810,12 @@ export default function DebuggerArgumentComponent({ debuggerInfo, restartDebug,
method: 'POST', method: 'POST',
data: JSON.stringify(argsValueList), data: JSON.stringify(argsValueList),
}) })
.then(function () {/*This is intentional (SonarQube)*/ }) .then(function () {
/* Close the debugger modal dialog */
props.closeModal();
})
.catch(function (error) { .catch(function (error) {
props.closeModal();
Notify.alert( Notify.alert(
gettext('Debugger Listener Startup Error'), gettext('Debugger Listener Startup Error'),
gettext(error.response.data) gettext(error.response.data)
@@ -851,7 +834,9 @@ export default function DebuggerArgumentComponent({ debuggerInfo, restartDebug,
method: 'POST', method: 'POST',
data: JSON.stringify(sqliteFuncArgsList), data: JSON.stringify(sqliteFuncArgsList),
}) })
.then(function () {/*This is intentional (SonarQube)*/ }) .then(function () {
/*This is intentional (SonarQube)*/
})
.catch(function (error) { .catch(function (error) {
setLoaderText(''); setLoaderText('');
Notify.alert( Notify.alert(
@@ -942,5 +927,7 @@ DebuggerArgumentComponent.propTypes = {
isEdbProc: PropTypes.bool, isEdbProc: PropTypes.bool,
transId: PropTypes.string, transId: PropTypes.string,
closeModal: PropTypes.func, closeModal: PropTypes.func,
pgTreeInfo: PropTypes.object,
pgData: PropTypes.object,
}; };

View File

@@ -31,6 +31,7 @@ import { ToolBar } from './ToolBar';
import { Stack } from './Stack'; import { Stack } from './Stack';
import { Results } from './Results'; import { Results } from './Results';
import { LocalVariablesAndParams } from './LocalVariablesAndParams'; import { LocalVariablesAndParams } from './LocalVariablesAndParams';
import DebuggerArgumentComponent from './DebuggerArgumentComponent';
export const DebuggerContext = React.createContext(); export const DebuggerContext = React.createContext();
export const DebuggerEventsContext = React.createContext(); export const DebuggerEventsContext = React.createContext();
@@ -524,7 +525,7 @@ export default function DebuggerComponent({ pgAdmin, selectedNodeInfo, panel, ev
// Restarting debugging in the same transaction do not work // Restarting debugging in the same transaction do not work
// We will give same behaviour as pgAdmin3 and disable all buttons // We will give same behaviour as pgAdmin3 and disable all buttons
enableToolbarButtons(MENUS.CONTINUE); disableToolbarButtons();
// Set the Alertify message to inform the user that execution // Set the Alertify message to inform the user that execution
// is completed. // is completed.
@@ -571,7 +572,26 @@ export default function DebuggerComponent({ pgAdmin, selectedNodeInfo, panel, ev
listener. listener.
*/ */
if (res.data.data.result.require_input) { if (res.data.data.result.require_input) {
params.funcArgsInstance.show(res.data.data.result, restart_dbg); let t = pgAdmin.Browser.tree,
i = t.selected(),
d = i ? t.itemData(i) : undefined;
let treeInfo = t.getTreeNodeHierarchy(i);
if (d) {
let isEdbProc = d._type == 'edbproc';
modal.showModal(gettext('Debugger'), (closeModal) => {
return <DebuggerArgumentComponent
closeModal={closeModal}
debuggerInfo={res.data.data.result}
restartDebug={restart_dbg}
isEdbProc={isEdbProc}
transId={params.transId.toString()}
pgData={d}
pgTreeInfo={treeInfo}
></DebuggerArgumentComponent>;
}, { isFullScreen: false, isResizeable: true, showFullScreen: true, isFullWidth: true, dialogWidth: pgAdmin.Browser.stdW.md, dialogHeight: pgAdmin.Browser.stdH.md });
}
} else { } else {
// Debugging of void function is started again so we need to start // Debugging of void function is started again so we need to start
// the listener again // the listener again
@@ -612,7 +632,7 @@ export default function DebuggerComponent({ pgAdmin, selectedNodeInfo, panel, ev
// If debugging is stopped by user then do not enable // If debugging is stopped by user then do not enable
// continue/restart button // continue/restart button
if (!params.directDebugger.is_user_aborted_debugging) { if (!params.directDebugger.is_user_aborted_debugging) {
enableToolbarButtons(MENUS.CONTINUE); enableToolbarButtons();
params.directDebugger.is_user_aborted_debugging = false; params.directDebugger.is_user_aborted_debugging = false;
} }
@@ -620,7 +640,7 @@ export default function DebuggerComponent({ pgAdmin, selectedNodeInfo, panel, ev
params.directDebugger.is_polling_required = false; params.directDebugger.is_polling_required = false;
}; };
const updateResultAnsMessages = (res) => { const updateResultAndMessages = (res) => {
if (res.data.data.result != null) { if (res.data.data.result != null) {
setActiveLine(-1); setActiveLine(-1);
// Call function to update results information and set result panel focus // Call function to update results information and set result panel focus
@@ -640,6 +660,7 @@ export default function DebuggerComponent({ pgAdmin, selectedNodeInfo, panel, ev
// "Continue/Start" button because user can still // "Continue/Start" button because user can still
// start the same execution again. // start the same execution again.
disableToolbarButtons(); disableToolbarButtons();
enableToolbarButtons(MENUS.START);
// Stop further pooling // Stop further pooling
params.directDebugger.is_polling_required = false; params.directDebugger.is_polling_required = false;
@@ -706,11 +727,12 @@ export default function DebuggerComponent({ pgAdmin, selectedNodeInfo, panel, ev
// "Continue/Start" button because user can still // "Continue/Start" button because user can still
// start the same execution again. // start the same execution again.
disableToolbarButtons(); disableToolbarButtons();
enableToolbarButtons(MENUS.START);
// Stop further polling // Stop further polling
params.directDebugger.is_polling_required = false; params.directDebugger.is_polling_required = false;
} else { } else {
updateResultAnsMessages(res); updateResultAndMessages(res);
} }
} else if (res.data.data.status === 'Busy') { } else if (res.data.data.status === 'Busy') {
// If status is Busy then poll the result by recursive call to // If status is Busy then poll the result by recursive call to

View File

@@ -25,7 +25,7 @@ import url_for from 'sources/url_for';
import { PgButtonGroup, PgIconButton } from '../../../../../static/js/components/Buttons'; import { PgButtonGroup, PgIconButton } from '../../../../../static/js/components/Buttons';
import { DebuggerContext, DebuggerEventsContext } from './DebuggerComponent'; import { DebuggerContext, DebuggerEventsContext } from './DebuggerComponent';
import { DEBUGGER_EVENTS } from '../DebuggerConstants'; import { DEBUGGER_EVENTS, MENUS } from '../DebuggerConstants';
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles((theme) => ({
root: { root: {
@@ -45,6 +45,8 @@ export function ToolBar() {
const eventBus = useContext(DebuggerEventsContext); const eventBus = useContext(DebuggerEventsContext);
let preferences = debuggerCtx.preferences.debugger; let preferences = debuggerCtx.preferences.debugger;
// JS not allowing to use constants as key hence unable to use MENUS constants,
// If required any changes in key update MENUS constans as well form DebuggerConstans file.
const [buttonsDisabled, setButtonsDisabled] = useState({ const [buttonsDisabled, setButtonsDisabled] = useState({
'stop': true, 'stop': true,
'clear-all-breakpoints': true, 'clear-all-breakpoints': true,
@@ -94,21 +96,21 @@ export function ToolBar() {
useEffect(() => { useEffect(() => {
eventBus.registerListener(DEBUGGER_EVENTS.DISABLE_MENU, () => { eventBus.registerListener(DEBUGGER_EVENTS.DISABLE_MENU, () => {
setDisableButton('start', true); setDisableButton(MENUS.START, true);
setDisableButton('step-into', true); setDisableButton(MENUS.STEPINTO, true);
setDisableButton('step-over', true); setDisableButton(MENUS.STEPOVER, true);
setDisableButton('clear-all-breakpoints', true); setDisableButton(MENUS.CLEAR_ALL_BREAKPOINT, true);
setDisableButton('toggle-breakpoint', true); setDisableButton(MENUS.TOGGLE_BREAKPOINT, true);
setDisableButton('stop', true); setDisableButton(MENUS.STOP, true);
}); });
eventBus.registerListener(DEBUGGER_EVENTS.ENABLE_MENU, () => { eventBus.registerListener(DEBUGGER_EVENTS.ENABLE_MENU, () => {
setDisableButton('start', false); setDisableButton(MENUS.START, false);
setDisableButton('step-into', false); setDisableButton(MENUS.STEPINTO, false);
setDisableButton('step-over', false); setDisableButton(MENUS.STEPOVER, false);
setDisableButton('clear-all-breakpoints', false); setDisableButton(MENUS.CLEAR_ALL_BREAKPOINT, false);
setDisableButton('toggle-breakpoint', false); setDisableButton(MENUS.TOGGLE_BREAKPOINT, false);
setDisableButton('stop', false); setDisableButton(MENUS.STOP, false);
}); });
eventBus.registerListener(DEBUGGER_EVENTS.ENABLE_SPECIFIC_MENU, (key) => { eventBus.registerListener(DEBUGGER_EVENTS.ENABLE_SPECIFIC_MENU, (key) => {
@@ -120,21 +122,21 @@ export function ToolBar() {
return ( return (
<Box className={classes.root}> <Box className={classes.root}>
<PgButtonGroup size="small"> <PgButtonGroup size="small">
<PgIconButton data-test='step-in' title={gettext('Step into')} disabled={buttonsDisabled['step-into']} icon={<FormatIndentIncreaseIcon />} onClick={() => { stepInTODebugger(); }} <PgIconButton data-test='step-in' title={gettext('Step into')} disabled={buttonsDisabled[MENUS.STEPINTO]} icon={<FormatIndentIncreaseIcon />} onClick={() => { stepInTODebugger(); }}
accesskey={shortcut_key(preferences?.btn_step_into)} /> accesskey={shortcut_key(preferences?.btn_step_into)} />
<PgIconButton data-test='step-over' title={gettext('Step over')} disabled={buttonsDisabled['step-over']} icon={<FormatIndentDecreaseIcon />} onClick={() => { stepOverDebugger(); }} <PgIconButton data-test='step-over' title={gettext('Step over')} disabled={buttonsDisabled[MENUS.STEPOVER]} icon={<FormatIndentDecreaseIcon />} onClick={() => { stepOverDebugger(); }}
accesskey={shortcut_key(preferences?.btn_step_over)} /> accesskey={shortcut_key(preferences?.btn_step_over)} />
<PgIconButton data-test='debugger-contiue' title={gettext('Continue/Start')} disabled={buttonsDisabled['start']} icon={<PlayCircleFilledWhiteIcon />} onClick={() => { continueDebugger(); }} <PgIconButton data-test='debugger-contiue' title={gettext('Continue/Start')} disabled={buttonsDisabled[MENUS.START]} icon={<PlayCircleFilledWhiteIcon />} onClick={() => { continueDebugger(); }}
accesskey={shortcut_key(preferences?.btn_start)} /> accesskey={shortcut_key(preferences?.btn_start)} />
</PgButtonGroup> </PgButtonGroup>
<PgButtonGroup size="small"> <PgButtonGroup size="small">
<PgIconButton data-test='toggle-breakpoint' title={gettext('Toggle breakpoint')} disabled={buttonsDisabled['toggle-breakpoint']} icon={<FiberManualRecordIcon style={{height: '2rem'}} />} <PgIconButton data-test='toggle-breakpoint' title={gettext('Toggle breakpoint')} disabled={buttonsDisabled[MENUS.TOGGLE_BREAKPOINT]} icon={<FiberManualRecordIcon style={{height: '2rem'}} />}
accesskey={shortcut_key(preferences?.btn_toggle_breakpoint)} onClick={() => { toggleBreakpoint(); }} /> accesskey={shortcut_key(preferences?.btn_toggle_breakpoint)} onClick={() => { toggleBreakpoint(); }} />
<PgIconButton data-test='clear-breakpoint' title={gettext('Clear all breakpoints')} disabled={buttonsDisabled['clear-all-breakpoints']} icon={<NotInterestedIcon />} <PgIconButton data-test='clear-breakpoint' title={gettext('Clear all breakpoints')} disabled={buttonsDisabled[MENUS.CLEAR_ALL_BREAKPOINT]} icon={<NotInterestedIcon />}
accesskey={shortcut_key(preferences?.btn_clear_breakpoints)} onClick={() => { clearAllBreakpoint(); }} /> accesskey={shortcut_key(preferences?.btn_clear_breakpoints)} onClick={() => { clearAllBreakpoint(); }} />
</PgButtonGroup> </PgButtonGroup>
<PgButtonGroup size="small"> <PgButtonGroup size="small">
<PgIconButton data-test='stop-debugger' title={gettext('Stop')} icon={<StopIcon style={{height: '2rem'}} />} disabled={buttonsDisabled['stop']} onClick={() => { stop(); }} <PgIconButton data-test='stop-debugger' title={gettext('Stop')} icon={<StopIcon style={{height: '2rem'}} />} disabled={buttonsDisabled[MENUS.STOP]} onClick={() => { stop(); }}
accesskey={shortcut_key(preferences?.btn_stop)} /> accesskey={shortcut_key(preferences?.btn_stop)} />
</PgButtonGroup> </PgButtonGroup>
<PgButtonGroup size="small"> <PgButtonGroup size="small">

View File

@@ -18,9 +18,17 @@ import DebuggerArgumentComponent from './components/DebuggerArgumentComponent';
export default class FunctionArguments { export default class FunctionArguments {
show(debugInfo, restartDebug, isEdbProc, transId) { show(debugInfo, restartDebug, isEdbProc, transId) {
var t = pgAdmin.Browser.tree,
i = t.selected(),
d = i ? t.itemData(i) : undefined;
if (!d)
return;
let treeInfo = t.getTreeNodeHierarchy(i);
// Render Debugger argument component // Render Debugger argument component
Notify.showModal(gettext('Debugger'), (closeModal) => { Notify.showModal(gettext('Debugger'), (closeModal) => {
return <DebuggerArgumentComponent closeModal={closeModal} debuggerInfo={debugInfo} restartDebug={restartDebug} isEdbProc={isEdbProc} transId={transId}></DebuggerArgumentComponent>; return <DebuggerArgumentComponent closeModal={closeModal} debuggerInfo={debugInfo} restartDebug={restartDebug} isEdbProc={isEdbProc} transId={transId} pgTreeInfo={treeInfo} pgData={d}></DebuggerArgumentComponent>;
}, { isFullScreen: false, isResizeable: true, showFullScreen: true, isFullWidth: true, dialogWidth: pgAdmin.Browser.stdW.md, dialogHeight: pgAdmin.Browser.stdH.md }); }, { isFullScreen: false, isResizeable: true, showFullScreen: true, isFullWidth: true, dialogWidth: pgAdmin.Browser.stdW.md, dialogHeight: pgAdmin.Browser.stdH.md });
} }
} }