Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
DebuggerComponent.jsx1164 linesDownload Raw Back to components
1/////////////////////////////////////////////////////////////2//3// pgAdmin 4 - PostgreSQL Tools4//5// Copyright (C) 2013 - 2024, The pgAdmin Development Team6// This software is released under the PostgreSQL Licence7//8//////////////////////////////////////////////////////////////9 10import { Box } from '@mui/material';11import React, { useEffect, useRef, useState } from 'react';12import PropTypes from 'prop-types';13 14import gettext from 'sources/gettext';15import url_for from 'sources/url_for';16import Loader from 'sources/components/Loader';17 18import Layout, { LayoutDocker } from '../../../../../static/js/helpers/Layout';19import EventBus from '../../../../../static/js/helpers/EventBus';20import getApiInstance, { callFetch } from '../../../../../static/js/api_instance';21 22import { PANELS, DEBUGGER_EVENTS, MENUS } from '../DebuggerConstants';23import { retrieveNodeName } from '../../../../sqleditor/static/js/show_view_data';24import { useModal } from '../../../../../static/js/helpers/ModalProvider';25import DebuggerEditor from './DebuggerEditor';26import DebuggerMessages from './DebuggerMessages';27import { ToolBar } from './ToolBar';28import { Stack } from './Stack';29import { Results } from './Results';30import { LocalVariablesAndParams } from './LocalVariablesAndParams';31import DebuggerArgumentComponent from './DebuggerArgumentComponent';32import usePreferences from '../../../../../preferences/static/js/store';33 34export const DebuggerContext = React.createContext();35export const DebuggerEventsContext = React.createContext();36 37export default function DebuggerComponent({ pgAdmin, selectedNodeInfo, panelId, panelDocker, eventBusObj, layout, params }) {38  const savedLayout = layout;39  const containerRef = React.useRef(null);40  const docker = useRef(null);41  const api = getApiInstance();42  const modal = useModal();43  const eventBus = useRef(eventBusObj || (new EventBus()));44  const [loaderText, setLoaderText] = React.useState('');45  const editor = useRef(null);46  const preferencesStore = usePreferences();47  let timeOut = null;48 49  const [preferences, setPreferences] = useState({50    browser: preferencesStore.getPreferencesForModule('browser'),51    debugger: preferencesStore.getPreferencesForModule('debugger'),52  });53 54  const disableToolbarButtons = () => {55    eventBus.current.fireEvent(DEBUGGER_EVENTS.DISABLE_MENU);56    eventBus.current.fireEvent(DEBUGGER_EVENTS.GET_TOOL_BAR_BUTTON_STATUS, { disabled: true });57  };58 59  const enableToolbarButtons = (key = null) => {60    if (key) {61      eventBus.current.fireEvent(DEBUGGER_EVENTS.ENABLE_SPECIFIC_MENU, key);62    } else {63      eventBus.current.fireEvent(DEBUGGER_EVENTS.ENABLE_MENU);64    }65 66    eventBus.current.fireEvent(DEBUGGER_EVENTS.GET_TOOL_BAR_BUTTON_STATUS, { disabled: false });67  };68 69  // Function to get the breakpoint information from the server70  const getBreakpointInformation = (transId, callBackFunc) => {71    let result = '';72 73    // Make ajax call to listen the database message74    let baseUrl = url_for('debugger.execute_query', {75      'trans_id': transId,76      'query_type': 'get_breakpoints',77    });78    api({79      url: baseUrl,80      method: 'GET',81    })82      .then(function (res) {83        if (res.data.data.status === 'Success') {84          result = res.data.data.result;85          if (callBackFunc) {86            callBackFunc(result);87          }88        } else if (res.data.data.status === 'NotConnected') {89          raiseFetchingBreakpointError();90        }91      })92      .catch(raiseFetchingBreakpointError);93 94    return result;95  };96 97  const clearAllBreakpoint = (transId) => {98    let clearBreakpoint = (br_list) => {99      // If there is no break point to clear then we should return from here.100      if ((br_list.length == 1) && (br_list[0].linenumber == -1))101        return;102 103      disableToolbarButtons();104      let breakpoint_list = getBreakpointList(br_list);105 106      // Make ajax call to listen the database message107      let baseUrl = url_for('debugger.clear_all_breakpoint', {108        'trans_id': transId,109      });110 111      api({112        url: baseUrl,113        method: 'POST',114        data: {115          'breakpoint_list': breakpoint_list.length > 0 ? breakpoint_list.join() : null,116        },117      })118        .then(function (res) {119          if (res.data.data.status) {120            executeQuery(transId);121            editor.current.clearBreakpoints();122          }123          enableToolbarButtons();124        })125        .catch(raiseClearBrekpointError);126    };127    getBreakpointInformation(transId, clearBreakpoint);128  };129 130  const raiseJSONError = (xhr) => {131    try {132      let err = xhr.response.data;133      if (err.success == 0) {134        let header_msg = gettext('Debugger Error'),135          err_msg = err.errormsg;136 137        // Stopped Debugger forcefully. 57014 is the SQL State138        if (err.errormsg.indexOf('57014') !== -1) {139          header_msg = gettext('Debugger Aborted');140          err_msg = gettext('Debugger has been aborted. '141           + 'On clicking the ok button, debugger panel will be closed.');142        }143 144        pgAdmin.Browser.notifier.alert(header_msg, err_msg, () => {145          if (panelId) {146            panelDocker.close(panelId, true);147          }148        });149      }150    } catch (e) {151      alert(xhr);152      pgAdmin.Browser.notifier.alert(153        gettext('Debugger Error'),154        gettext('Error while starting debugging listener.')155      );156    }157  };158 159  const raisePollingError = (error) => {160    console.error(error);161    pgAdmin.Browser.notifier.alert(162      gettext('Debugger Error'),163      gettext('Error while polling result.')164    );165  };166 167  const raiseClearBrekpointError = () => {168    pgAdmin.Browser.notifier.alert(169      gettext('Debugger Error'),170      gettext('Error while clearing all breakpoint.')171    );172  };173 174  const raiseFetchingBreakpointError = () => {175    pgAdmin.Browser.notifier.alert(176      gettext('Debugger Error'),177      gettext('Error while fetching breakpoint information.')178    );179  };180 181  const messages = (transId) => {182    // Make ajax call to listen the database message183    let baseUrl = url_for('debugger.messages', {184      'trans_id': transId,185    });186 187    api({188      url: baseUrl,189      method: 'GET',190    })191      .then(function (res) {192        if (res.data.data.status === 'Success') {193          enableToolbarButtons();194          // If status is Success then find the port number to attach the executer.195          startExecution(transId, res.data.data.result);196        } else if (res.data.data.status === 'Busy') {197          // If status is Busy then poll the result by recursive call to the poll function198          messages(transId);199        } else if (res.data.data.status === 'NotConnected') {200          pgAdmin.Browser.notifier.alert(201            gettext('Not connected to server or connection with the server has been closed.'),202            res.data.result203          );204        }205      })206      .catch(function () {207        pgAdmin.Browser.notifier.alert(208          gettext('Debugger Error'),209          gettext('Error while fetching messages information.')210        );211      });212 213  };214 215  const startExecution = (transId, port_num) => {216    // Make ajax call to listen the database message217    let baseUrl = url_for(218      'debugger.start_execution', {219        'trans_id': transId,220        'port_num': port_num,221      });222    api({223      url: baseUrl,224      method: 'GET',225    })226      .then(function (res) {227        if (res.data.data.status === 'Success') {228          // If status is Success then find the port number to attach the executer.229          executeQuery(transId);230        } else if (res.data.data.status === 'NotConnected') {231          pgAdmin.Browser.notifier.alert(232            gettext('Debugger Error'),233            gettext('Error while starting debugging session.')234          );235        }236      })237      .catch(function () {238        pgAdmin.Browser.notifier.alert(239          gettext('Debugger Error'),240          gettext('Error while starting debugging session.')241        );242      });243  };244 245  const executeQuery = (transId) => {246    // Make ajax call to listen the database message247    let baseUrl = url_for(248      'debugger.execute_query', {249        'trans_id': transId,250        'query_type': 'wait_for_breakpoint',251      });252    api({253      url: baseUrl,254      method: 'GET',255    })256      .then(function (res) {257        if (res.data.data.status === 'Success') {258          // set the return code to the code editor text area259          if (260            res.data.data.result[0].src != null &&261            res.data.data.result[0].linenumber != null262          ) {263            editor.current.setValue(res.data.data.result[0].src);264 265            editor.current.setActiveLine(res.data.data.result[0].linenumber - 1);266          }267          // Call function to create and update Stack information ....268          getStackInformation(transId);269          if (params.directDebugger.debug_type) {270            pollEndExecutionResult(transId);271          }272        } else if (res.data.data.status === 'NotConnected') {273          pgAdmin.Browser.notifier.alert(274            gettext('Debugger Error'),275            gettext('Error while executing requested debugging information.')276          );277        }278      })279      .catch(function (error) {280        console.error(error);281        pgAdmin.Browser.notifier.alert(282          gettext('Debugger Error'),283          gettext('Error while executing requested debugging information.')284        );285      });286  };287 288  const selectFrame = (frameId) => {289    // Make ajax call to listen the database message290    let baseUrl = url_for('debugger.select_frame', {291      'trans_id': params.transId,292      'frame_id': frameId,293    });294    api({295      url: baseUrl,296      method: 'GET',297    })298      .then(function (res) {299        if (res.data.data.status) {300          editor.current.setValue(res.data.data.result[0].src);301          updateBreakpoint(params.transId, true);302          editor.current.setActiveLine(res.data.data.result[0].linenumber - 1);303        }304      })305      .catch(function () {306        pgAdmin.Browser.notifier.alert(307          gettext('Debugger Error'),308          gettext('Error while selecting frame.')309        );310      });311  };312 313  useEffect(() => {314    let baseUrl = '';315    if (params.transId != undefined && !params.directDebugger.debug_type) {316      // Make ajax call to execute the and start the target for execution317      baseUrl = url_for('debugger.start_listener', {318        'trans_id': params.transId,319      });320 321      api({322        url: baseUrl,323        method: 'POST',324      })325        .catch(raiseJSONError);326      enableToolbarButtons();327      pollResult(params.transId);328    } else if (params.transId != undefined) {329      // Make api call to execute the and start the target for execution330      baseUrl = url_for('debugger.start_listener', {331        'trans_id': params.transId,332      });333 334      api({335        url: baseUrl,336        method: 'POST',337      })338        .catch(raiseJSONError);339      messages(params.transId);340    }341 342    const closeConn = ()=>{343      /* Using fetch with keepalive as the browser may344      cancel the axios request on tab close. keepalive will345      make sure the request is completed */346      callFetch(347        url_for('debugger.close', {348          'trans_id': params.transId,349        }), {350          keepalive: true,351          method: 'DELETE',352        }353      )354        .then(()=>{/* Success */})355        .catch((err)=>console.error(err));356    };357    window.addEventListener('unload', closeConn);358 359    return ()=>{360      window.removeEventListener('unload', closeConn);361    };362  }, []);363 364  const triggerClearBreakpoint = () => {365    let clearBreakpoint = (br_list) => {366      // If there is no break point to clear then we should return from here.367      if ((br_list.length == 1) && (br_list[0].linenumber == -1))368        return;369 370      disableToolbarButtons();371      let breakpoint_list = getBreakpointList(br_list);372 373      // Make ajax call to listen the database message374      let _baseUrl = url_for('debugger.clear_all_breakpoint', {375        'trans_id': params.transId,376      });377 378      api({379        url: _baseUrl,380        method: 'POST',381        data: {382          'breakpoint_list': breakpoint_list.join(),383        },384      })385        .then(function () {386          editor.current.clearBreakpoints();387          enableToolbarButtons();388        })389        .catch(raiseClearBrekpointError);390    };391    // Make ajax call to listen the database message392    let baseUrl = url_for('debugger.execute_query', {393      'trans_id': params.transId,394      'query_type': 'get_breakpoints',395    });396    api({397      url: baseUrl,398      method: 'GET',399    })400      .then(function (res) {401        if (res.data.data.status === 'Success') {402          let result = res.data.data.result;403          clearBreakpoint(result);404        } else if (res.data.data.status === 'NotConnected') {405          raiseFetchingBreakpointError();406        }407      })408      .catch(raiseFetchingBreakpointError);409 410  };411 412  const triggerToggleBreakpoint = () => {413    disableToolbarButtons();414    const lineNo = editor.current.getActiveLine();415    editor.current.toggleBreakpoint(lineNo);416    enableToolbarButtons();417  };418 419  const stopDebugging = () => {420    disableToolbarButtons();421    // Make ajax call to listen the database message422    let baseUrl = url_for(423      'debugger.execute_query', {424        'trans_id': params.transId,425        'query_type': 'abort_target',426      });427    api({428      url: baseUrl,429      method: 'GET',430    })431      .then(function (res) {432        if (res.data.data.status) {433          // Remove active time in the editor434          editor.current.setActiveLine(-1);435          // Clear timeout on stop debugger.436          clearTimeout(timeOut);437 438          params.directDebugger.direct_execution_completed = true;439          params.directDebugger.is_user_aborted_debugging = true;440 441          // Stop further pooling442          params.directDebugger.is_polling_required = false;443 444          // Restarting debugging in the same transaction do not work445          // We will give same behaviour as pgAdmin3 and disable all buttons446          disableToolbarButtons();447 448          // Set the message to inform the user that execution449          // is completed.450          pgAdmin.Browser.notifier.success(res.data.info, 3000);451        } else if (res.data.data.status === 'NotConnected') {452          pgAdmin.Browser.notifier.alert(453            gettext('Debugger Error'),454            gettext('Error while executing stop in debugging session.')455          );456        }457      })458      .catch(function () {459        pgAdmin.Browser.notifier.alert(460          gettext('Debugger Error'),461          gettext('Error while executing stop in debugging session.')462        );463      });464  };465 466  const restart = (transId) => {467    let baseUrl = url_for('debugger.restart', { 'trans_id': transId });468    disableToolbarButtons();469 470    api({471      url: baseUrl,472    })473      .then(function (res) {474        // Restart the same function debugging with previous arguments475        let restart_dbg = res.data.data.restart_debug ? 1 : 0;476 477        // Start pooling again478        params.directDebugger.polling_timeout_idle = false;479        params.directDebugger.is_polling_required = true;480        pollResult(transId);481 482        if (restart_dbg) {483          params.directDebugger.debug_restarted = true;484        }485 486        /*487        Need to check if restart debugging really require to open the input488        dialog? If yes then we will get the previous arguments from database489        and populate the input dialog, If no then we should directly start the490        listener.491        */492        if (res.data.data.result.require_input) {493          let t = pgAdmin.Browser.tree,494            i = t.selected(),495            d = i ? t.itemData(i) : undefined;496 497          let treeInfo = t.getTreeNodeHierarchy(i);498 499          if (d) {500            let isEdbProc = d._type == 'edbproc';501            modal.showModal(gettext('Debugger'), (closeModal) => {502              return <DebuggerArgumentComponent503                closeModal={closeModal}504                debuggerInfo={res.data.data.result}505                restartDebug={restart_dbg}506                isEdbProc={isEdbProc}507                transId={params.transId.toString()}508                pgData={d}509                pgTreeInfo={treeInfo}510              ></DebuggerArgumentComponent>;511            }, { isFullScreen: false, isResizeable: true, showFullScreen: true, isFullWidth: true, dialogWidth: pgAdmin.Browser.stdW.md, dialogHeight: pgAdmin.Browser.stdH.md });512          }513        } else {514          // This will start lister for void de515          restartDebuggerListener();516        }517      })518      .catch(raiseJSONError);519  };520 521  function restartDebuggerListener() {522    // Debugging of void function is started again so we need to start523    // the listener again524    let base_url = url_for('debugger.start_listener', {525      'trans_id': params.transId,526    });527 528    api({529      url: base_url,530      method: 'POST',531    })532      .catch(raisePollingError);533    if (params.directDebugger.debug_type) {534      pollEndExecutionResult(params.transId);535    }536  }537 538  const pollEndExecuteError = (res) => {539    params.directDebugger.direct_execution_completed = true;540    editor.current.setActiveLine(-1);541 542    //Set the notification message to inform the user that execution is543    // completed with error.544    if (!params.directDebugger.is_user_aborted_debugging) {545      pgAdmin.Browser.notifier.error(res.data.info, 3000);546    }547 548    // Update the message tab of the debugger549    updateMessages(res.data.data.status_message);550 551    eventBus.current.fireEvent(DEBUGGER_EVENTS.FOCUS_PANEL, PANELS.MESSAGES);552    disableToolbarButtons();553    // If debugging is stopped by user then do not enable554    // continue/restart button555    if (!params.directDebugger.is_user_aborted_debugging) {556      enableToolbarButtons();557      params.directDebugger.is_user_aborted_debugging = false;558    }559 560    // Stop further pooling561    params.directDebugger.is_polling_required = false;562  };563 564  const updateResultAndMessages = (res) => {565    if (res.data.data.result != null) {566      editor.current.setActiveLine(-1);567      // Call function to update results information and set result panel focus568      eventBus.current.fireEvent(DEBUGGER_EVENTS.SET_RESULTS, res.data.data.col_info, res.data.data.result);569      eventBus.current.fireEvent(DEBUGGER_EVENTS.FOCUS_PANEL, PANELS.RESULTS);570 571      params.directDebugger.direct_execution_completed = true;572      params.directDebugger.polling_timeout_idle = true;573 574      //Set the message to inform the user that execution is completed.575      pgAdmin.Browser.notifier.success(res.data.info, 3000);576 577      // Update the message tab of the debugger578      updateMessages(res.data.data.status_message);579 580      // Execution completed so disable the buttons other than581      // "Continue/Start" button because user can still582      // start the same execution again.583      disableToolbarButtons();584      enableToolbarButtons(MENUS.START);585 586      // Stop further pooling587      params.directDebugger.is_polling_required = false;588    }589  };590 591  /*592    For the direct debugging, we need to check weather the functions execution593    is completed or not. After completion of the debugging, we will stop polling594    the result  until new execution starts.595  */596  const pollEndExecutionResult = (transId) => {597    // Do we need to poll?598    if (!params.directDebugger.is_polling_required) {599      return;600    }601 602    // Make ajax call to listen the database message603    let baseUrl = url_for('debugger.poll_end_execution_result', {604        'trans_id': transId,605      }),606      poll_end_timeout;607 608    /*609      * During the execution we should poll the result in minimum seconds610      * but once the execution is completed and wait for the another611      * debugging session then we should decrease the polling frequency.612    */613    if (params.directDebugger.polling_timeout_idle) {614      // Poll the result to check that execution is completed or not615      // after 1200 ms616      poll_end_timeout = 1200;617    } else {618      // Poll the result to check that execution is completed or not619      // after 350 ms620      poll_end_timeout = 250;621    }622 623    timeOut = setTimeout(624      function () {625        api({626          url: baseUrl,627          method: 'GET',628        })629          .then(function (res) {630            if (res.data.data.status === 'Success') {631              if (res.data.data.result == undefined) {632                /*633                "result" is undefined only in case of EDB procedure.634                As Once the EDB procedure execution is completed then we are635                not getting any result so we need to ignore the result.636                */637                editor.current.setActiveLine(-1);638                params.directDebugger.direct_execution_completed = true;639                params.directDebugger.polling_timeout_idle = true;640 641                //Set the message to inform the user that execution is completed.642                pgAdmin.Browser.notifier.success(res.data.info, 3000);643 644                // Update the message tab of the debugger645                updateMessages(res.data.data.status_message);646 647                // Execution completed so disable the buttons other than648                // "Continue/Start" button because user can still649                // start the same execution again.650                disableToolbarButtons();651                enableToolbarButtons(MENUS.START);652 653                // Stop further polling654                params.directDebugger.is_polling_required = false;655              } else {656                updateResultAndMessages(res);657              }658            } else if (res.data.data.status === 'Busy') {659              // If status is Busy then poll the result by recursive call to660              // the poll function661              pollEndExecutionResult(transId);662              // Update the message tab of the debugger663              updateMessages(res.data.data.status_message);664            } else if (res.data.status === 'NotConnected') {665              pgAdmin.Browser.notifier.alert(666                gettext('Debugger poll end execution error'),667                res.data.result668              );669            } else if (res.data.data.status === 'ERROR') {670              pollEndExecuteError(res);671            }672          })673          .catch(raisePollingError);674      }, poll_end_timeout);675 676  };677 678  // This function will update messages tab679  const updateMessages = (msg) => {680    if (msg) {681      // Call function to update messages information682      eventBus.current.fireEvent(DEBUGGER_EVENTS.SET_MESSAGES, msg, true);683    }684  };685 686  const continueDebugger = () => {687    disableToolbarButtons();688 689    //Check first if previous execution was completed or not690    if (params.directDebugger.direct_execution_completed &&691      params.directDebugger.direct_execution_completed == params.directDebugger.polling_timeout_idle) {692      restart(params.transId);693    } else {694      // Make ajax call to listen the database message695      let baseUrl = url_for('debugger.execute_query', {696        'trans_id': params.transId,697        'query_type': 'continue',698      });699      api({700        url: baseUrl,701        method: 'GET',702      })703        .then(function (res) {704          if (res.data.data.status) {705            pollResult(params.transId);706          } else {707            pgAdmin.Browser.notifier.alert(708              gettext('Debugger Error'),709              gettext('Error while executing continue in debugging session.')710            );711          }712        })713        .catch(function () {714          pgAdmin.Browser.notifier.alert(715            gettext('Debugger Error'),716            gettext('Error while executing continue in debugging session.')717          );718        });719    }720  };721 722  const stepOver = () => {723    disableToolbarButtons();724 725    // Make ajax call to listen the database message726    let baseUrl = url_for('debugger.execute_query', {727      'trans_id': params.transId,728      'query_type': 'step_over',729    });730    api({731      url: baseUrl,732      method: 'GET',733    })734      .then(function (res) {735        if (res.data.data.status) {736          pollResult(params.transId);737        } else {738          pgAdmin.Browser.notifier.alert(739            gettext('Debugger Error'),740            gettext('Error while executing step over in debugging session.')741          );742        }743      })744      .catch(function () {745        pgAdmin.Browser.notifier.alert(746          gettext('Debugger Error'),747          gettext('Error while executing step over in debugging session.')748        );749      });750 751  };752 753  const getBreakpointList = (br_list) => {754    let breakpoint_list = [];755    for (let val of br_list) {756      if (val.linenumber != -1) {757        breakpoint_list.push(val.linenumber);758      }759    }760 761    return breakpoint_list;762  };763 764  // Function to get the latest breakpoint information765  const updateBreakpoint = (transId, updateLocalVar = false) => {766    let callBackFunc = () => {767      if (updateLocalVar) {768        // Call function to create and update local variables ....769        getLocalVariables(params.transId);770      }771    };772    getBreakpointInformation(transId, callBackFunc);773  };774 775  // Get the local variable information of the functions and update the grid776  const getLocalVariables = (transId) => {777    // Make ajax call to listen the database message778    let baseUrl = url_for(779      'debugger.execute_query', {780        'trans_id': transId,781        'query_type': 'get_variables',782      });783    api({784      url: baseUrl,785      method: 'GET',786    })787      .then(function (res) {788        if (res.data.data.status === 'Success') {789          // Call function to update local variables790          let variablesResult = res.data.data.result.filter((lvar) => {791            return lvar.varclass == 'L';792          });793          eventBus.current.fireEvent(DEBUGGER_EVENTS.SET_LOCAL_VARIABLES, variablesResult);794 795          let parametersResult = res.data.data.result.filter((lvar) => {796            return lvar.varclass == 'A';797          });798          // update Parameter panel data.799          eventBus.current.fireEvent(DEBUGGER_EVENTS.SET_PARAMETERS, parametersResult);800          // If debug function is restarted then again start listener to801          // read the updated messages.802          if (params.directDebugger.debug_restarted) {803            if (params.directDebugger.debug_type) {804              pollEndExecutionResult(transId);805            }806            params.directDebugger.debug_restarted = false;807          }808        } else if (res.data.data.status === 'NotConnected') {809          pgAdmin.Browser.notifier.alert(810            gettext('Debugger Error'),811            gettext('Error while fetching variable information.')812          );813        }814      })815      .catch(function () {816        pgAdmin.Browser.notifier.alert(817          gettext('Debugger Error'),818          gettext('Error while fetching variable information.')819        );820      });821  };822 823  const getStackInformation = (transId) => {824    // Make ajax call to listen the database message825    let baseUrl = url_for(826      'debugger.execute_query', {827        'trans_id': transId,828        'query_type': 'get_stack_info',829      });830    api({831      url: baseUrl,832      method: 'GET',833    })834      .then(function (res) {835        if (res.data.data.status === 'Success') {836          // Call function to update stack information837          eventBus.current.fireEvent(DEBUGGER_EVENTS.SET_STACK, res.data.data.result);838          // Call function to create and update stack information839          getLocalVariables(params.transId);840        } else if (res.data.data.status === 'NotConnected') {841          pgAdmin.Browser.notifier.alert(842            gettext('Debugger Error'),843            gettext('Error while fetching stack information.')844          );845        }846      })847      .catch(function () {848        pgAdmin.Browser.notifier.alert(849          gettext('Debugger Error'),850          gettext('Error while fetching stack information.')851        );852      });853  };854 855 856  const updateBreakpointInfo = (res, transId) => {857    if (res.data.data.result[0].src != editor.current.getValue()) {858      editor.current.setValue(res.data.data.result[0].src);859      try {860        updateBreakpoint(transId);861      } catch (err) {862        pgAdmin.Browser.notifier.alert(gettext('Error in update'), err);863      }864 865    }866  };867 868  const updateInfo = (res, transId) => {869    if (!params.directDebugger.debug_type && !params.directDebugger.first_time_indirect_debug) {870      setLoaderText('');871      editor.current.setActiveLine(-1);872      clearAllBreakpoint(transId);873 874      params.directDebugger.first_time_indirect_debug = true;875      params.directDebugger.polling_timeout_idle = false;876    } else {877      params.directDebugger.polling_timeout_idle = false;878      setLoaderText('');879      // If the source is really changed then only update the breakpoint information880      updateBreakpointInfo(res, transId);881 882      editor.current.setActiveLine(res.data.data.result[0].linenumber - 1);883      // Update the stack, local variables and parameters information884      setTimeout(function () {885        getStackInformation(transId);886      }, 10);887    }888  };889 890  const checkDebuggerStatus = (transId) => {891    // If status is Busy then poll the result by recursive call to the poll function892    if (!params.directDebugger.debug_type) {893      setLoaderText(gettext('Waiting for another session to invoke the target...'));894      // As we are waiting for another session to invoke the target,disable all the buttons895      disableToolbarButtons();896      params.directDebugger.first_time_indirect_debug = false;897      pollResult(transId);898    } else {899      pollResult(transId);900    }901  };902 903  /* poll the actual result after user has executed the "continue", "step-into",904    "step-over" actions and get the other updated information from the server.905  */906  const pollResult = (transId) => {907    // Do we need to poll?908    if (!params.directDebugger.is_polling_required) {909      return;910    }911 912    // Make ajax call to listen the database message913    let baseUrl = url_for('debugger.poll_result', {914        'trans_id': transId,915      }),916      poll_timeout;917 918    /*919          During the execution we should poll the result in minimum seconds but920          once the execution is completed and wait for the another debugging921          session then we should decrease the polling frequency.922        */923    if (params.directDebugger.polling_timeout_idle) {924      // Poll the result after 1 second925      poll_timeout = 1000;926    } else {927      // Poll the result after 200 ms928      poll_timeout = 200;929    }930 931    setTimeout(932      function () {933        api({934          url: baseUrl,935          method: 'GET',936          beforeSend: function (xhr) {937            xhr.setRequestHeader(938              pgAdmin.csrf_token_header, pgAdmin.csrf_token939            );940          },941        })942          .then(function (res) {943            if (res.data.data.status === 'Success') {944              // If no result then poll again to wait for results.945              if (res.data.data.result == null || res.data.data.result.length == 0) {946                pollResult(transId);947              } else {948                updateInfo(res, transId);949                // Enable all the buttons as we got the results950                enableToolbarButtons();951              }952            } else if (res.data.data.status === 'Busy') {953              params.directDebugger.polling_timeout_idle = true;954              checkDebuggerStatus(transId);955            } else if (res.data.data.status === 'NotConnected') {956              pgAdmin.Browser.notifier.alert(957                gettext('Debugger Error: poll_result'),958                gettext('Error while polling result.')959              );960            }961          })962          .catch(raisePollingError);963      }, poll_timeout);964 965  };966 967  const stepInto = () => {968    disableToolbarButtons();969    // Make ajax call to listen the database message970    let baseUrl = url_for('debugger.execute_query', {971      'trans_id': params.transId,972      'query_type': 'step_into',973    });974    api({975      url: baseUrl,976      method: 'GET',977    })978      .then(function (res) {979        if (res.data.data.status) {980          pollResult(params.transId);981        } else {982          pgAdmin.Browser.notifier.alert(983            gettext('Debugger Error'),984            gettext('Error while executing step into in debugging session.')985          );986        }987      })988      .catch(function () {989        pgAdmin.Browser.notifier.alert(990          gettext('Debugger Error'),991          gettext('Error while executing step into in debugging session.')992        );993      });994  };995 996 997  const onChangesLocalVarParameters = (data) => {998    // Make api call to listen the database message999    let baseUrl = url_for('debugger.deposit_value', {1000      'trans_id': params.transId,1001    });1002    api({1003      url: baseUrl,1004      method: 'POST',1005      data: data,1006    })1007      .then(function (res) {1008        if (res.data.data.status) {1009          // Get the updated variables value1010          getLocalVariables(params.transId);1011          // Show the message to the user that deposit value is success or failure1012          if (res.data.data.result) {1013            pgAdmin.Browser.notifier.success(res.data.data.info, 3000);1014          } else {1015            pgAdmin.Browser.notifier.error(res.data.data.info, 3000);1016          }1017        }1018      })1019      .catch(function () {1020        pgAdmin.Browser.notifier.alert(1021          gettext('Debugger Error'),1022          gettext('Error while depositing variable value.')1023        );1024      });1025  };1026 1027  useEffect(() => {1028    // Register all eventes for debugger.1029    eventBus.current.registerListener(1030      DEBUGGER_EVENTS.TRIGGER_CLEAR_ALL_BREAKPOINTS, triggerClearBreakpoint);1031 1032    eventBus.current.registerListener(1033      DEBUGGER_EVENTS.TRIGGER_TOGGLE_BREAKPOINTS, triggerToggleBreakpoint);1034 1035    eventBus.current.registerListener(1036      DEBUGGER_EVENTS.TRIGGER_STOP_DEBUGGING, stopDebugging);1037 1038    eventBus.current.registerListener(1039      DEBUGGER_EVENTS.TRIGGER_CONTINUE_DEBUGGING, continueDebugger);1040 1041    eventBus.current.registerListener(1042      DEBUGGER_EVENTS.TRIGGER_STEPOVER_DEBUGGING, stepOver);1043 1044    eventBus.current.registerListener(1045      DEBUGGER_EVENTS.TRIGGER_STEINTO_DEBUGGING, stepInto);1046 1047    eventBus.current.registerListener(1048      DEBUGGER_EVENTS.SET_LOCAL_VARIABLE_VALUE_CHANGE, onChangesLocalVarParameters);1049 1050    eventBus.current.registerListener(1051      DEBUGGER_EVENTS.SET_PARAMETERS_VALUE_CHANGE, onChangesLocalVarParameters);1052 1053    eventBus.current.registerListener(DEBUGGER_EVENTS.SET_FRAME, (frameId) => {1054      selectFrame(frameId);1055    });1056 1057    eventBus.current.registerListener(DEBUGGER_EVENTS.FOCUS_PANEL, (panelId) => {1058      docker.current.focus(panelId);1059    });1060 1061    eventBus.current.registerListener(1062      DEBUGGER_EVENTS.TRIGGER_RESET_LAYOUT, () => {1063        docker.current?.resetLayout();1064      });1065  }, []);1066 1067 1068  useEffect(() => usePreferences.subscribe(1069    state => {1070      setPreferences({1071        browser: state.getPreferencesForModule('browser'),1072        debugger: state.getPreferencesForModule('debugger'),1073      });1074    }1075  ), []);1076 1077  const DebuggerContextValue = React.useMemo(() => ({1078    docker: docker.current,1079    api: api,1080    modal: modal,1081    params: {1082      ...params,1083      node_name: retrieveNodeName(selectedNodeInfo),1084    },1085    preferences: preferences,1086  }), [preferences]);1087 1088  // Define the debugger layout components such as DebuggerEditor to show queries and1089  let defaultLayout = {1090    dockbox: {1091      mode: 'vertical',1092      children: [1093        {1094          mode: 'horizontal',1095          children: [1096            {1097              tabs: [1098                LayoutDocker.getPanel({1099                  id: PANELS.DEBUGGER, title: gettext('Debugger'), content: <DebuggerEditor getEditor={(edRef) => {1100                    editor.current = edRef;1101                  }} params={{ transId: params.transId, debuggerDirect: params.directDebugger }} />1102                })1103              ],1104            }1105          ]1106        },1107        {1108          mode: 'horizontal',1109          children: [1110            {1111              tabs: [1112                LayoutDocker.getPanel({1113                  id: PANELS.PARAMETERS, title: gettext('Parameters'), content: <LocalVariablesAndParams type={1} />,1114                }),1115                LayoutDocker.getPanel({1116                  id: PANELS.LOCAL_VARIABLES, title: gettext('Local Variables'), content: <LocalVariablesAndParams type={2} />,1117                }),1118                LayoutDocker.getPanel({1119                  id: PANELS.MESSAGES, title: gettext('Messages'), content: <DebuggerMessages />,1120                }),1121                LayoutDocker.getPanel({1122                  id: PANELS.RESULTS, title: gettext('Result'), content: <Results />,1123                }),1124                LayoutDocker.getPanel({1125                  id: PANELS.STACK, title: gettext('Stack'), content: <Stack />,1126                }),1127              ],1128            }1129          ]1130        },1131      ]1132    },1133  };1134 1135  return (1136    <DebuggerContext.Provider value={DebuggerContextValue}>1137      <DebuggerEventsContext.Provider value={eventBus.current}>1138        <Loader message={loaderText} />1139        <Box width="100%" height="100%" display="flex" flexDirection="column" flexGrow="1" tabIndex="0" ref={containerRef}>1140          <ToolBar1141            containerRef={containerRef}1142          />1143          <Layout1144            getLayoutInstance={(obj) => docker.current = obj}1145            defaultLayout={defaultLayout}1146            layoutId="Debugger/Layout"1147            savedLayout={savedLayout}1148          />1149        </Box>1150      </DebuggerEventsContext.Provider>1151    </DebuggerContext.Provider>1152  );1153}1154 1155DebuggerComponent.propTypes = {1156  pgAdmin: PropTypes.object,1157  selectedNodeInfo: PropTypes.object,1158  panelId: PropTypes.string,1159  panelDocker: PropTypes.object,1160  eventBusObj: PropTypes.object,1161  layout: PropTypes.string,1162  params: PropTypes.object1163};1164 
codekingpro/portable-devtools · Team Ai