mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Upgrade CodeMirror from version 5 to 6. #7097
This commit is contained in:
@@ -114,13 +114,13 @@ export default function DebuggerComponent({ pgAdmin, selectedNodeInfo, panelId,
|
||||
url: baseUrl,
|
||||
method: 'POST',
|
||||
data: {
|
||||
'breakpoint_list': breakpoint_list.lenght > 0 ? breakpoint_list.join() : null,
|
||||
'breakpoint_list': breakpoint_list.length > 0 ? breakpoint_list.join() : null,
|
||||
},
|
||||
})
|
||||
.then(function (res) {
|
||||
if (res.data.data.status) {
|
||||
executeQuery(transId);
|
||||
setUnsetBreakpoint(res, breakpoint_list);
|
||||
editor.current.clearBreakpoints();
|
||||
}
|
||||
enableToolbarButtons();
|
||||
})
|
||||
@@ -158,7 +158,8 @@ export default function DebuggerComponent({ pgAdmin, selectedNodeInfo, panelId,
|
||||
}
|
||||
};
|
||||
|
||||
const raisePollingError = () => {
|
||||
const raisePollingError = (error) => {
|
||||
console.error(error);
|
||||
pgAdmin.Browser.notifier.alert(
|
||||
gettext('Debugger Error'),
|
||||
gettext('Error while polling result.')
|
||||
@@ -263,7 +264,7 @@ export default function DebuggerComponent({ pgAdmin, selectedNodeInfo, panelId,
|
||||
) {
|
||||
editor.current.setValue(res.data.data.result[0].src);
|
||||
|
||||
setActiveLine(res.data.data.result[0].linenumber - 2);
|
||||
editor.current.setActiveLine(res.data.data.result[0].linenumber - 1);
|
||||
}
|
||||
// Call function to create and update Stack information ....
|
||||
getStackInformation(transId);
|
||||
@@ -277,7 +278,8 @@ export default function DebuggerComponent({ pgAdmin, selectedNodeInfo, panelId,
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
.catch(function (error) {
|
||||
console.error(error);
|
||||
pgAdmin.Browser.notifier.alert(
|
||||
gettext('Debugger Error'),
|
||||
gettext('Error while executing requested debugging information.')
|
||||
@@ -285,31 +287,6 @@ export default function DebuggerComponent({ pgAdmin, selectedNodeInfo, panelId,
|
||||
});
|
||||
};
|
||||
|
||||
const setActiveLine = (lineNo) => {
|
||||
/* If lineNo sent, remove active line */
|
||||
if (lineNo && editor.current.activeLineNo) {
|
||||
editor.current.removeLineClass(
|
||||
editor.current.activeLineNo, 'wrap', 'CodeMirror-activeline-background'
|
||||
);
|
||||
}
|
||||
|
||||
/* If lineNo not sent, set it to active line */
|
||||
if (!lineNo && editor.current.activeLineNo) {
|
||||
lineNo = editor.current.activeLineNo;
|
||||
}
|
||||
|
||||
/* Set new active line only if positive */
|
||||
if (lineNo > 0) {
|
||||
editor.current.activeLineNo = lineNo;
|
||||
editor.current.addLineClass(
|
||||
editor.current.activeLineNo, 'wrap', 'CodeMirror-activeline-background'
|
||||
);
|
||||
|
||||
/* centerOnLine is codemirror extension in bundle/codemirror.js */
|
||||
editor.current.centerOnLine(editor.current.activeLineNo);
|
||||
}
|
||||
};
|
||||
|
||||
const selectFrame = (frameId) => {
|
||||
// Make ajax call to listen the database message
|
||||
let baseUrl = url_for('debugger.select_frame', {
|
||||
@@ -324,7 +301,7 @@ export default function DebuggerComponent({ pgAdmin, selectedNodeInfo, panelId,
|
||||
if (res.data.data.status) {
|
||||
editor.current.setValue(res.data.data.result[0].src);
|
||||
updateBreakpoint(params.transId, true);
|
||||
setActiveLine(res.data.data.result[0].linenumber - 2);
|
||||
editor.current.setActiveLine(res.data.data.result[0].linenumber - 1);
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
@@ -386,20 +363,6 @@ export default function DebuggerComponent({ pgAdmin, selectedNodeInfo, panelId,
|
||||
};
|
||||
}, []);
|
||||
|
||||
const setUnsetBreakpoint = (res, breakpoint_list) => {
|
||||
if (res.data.data.status) {
|
||||
for (let brk_val of breakpoint_list) {
|
||||
let info = editor.current.lineInfo((brk_val - 1));
|
||||
|
||||
if (info) {
|
||||
if (info.gutterMarkers != undefined) {
|
||||
editor.current.setGutterMarker((brk_val - 1), 'breakpoints', null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const triggerClearBreakpoint = () => {
|
||||
let clearBreakpoint = (br_list) => {
|
||||
// If there is no break point to clear then we should return from here.
|
||||
@@ -421,8 +384,8 @@ export default function DebuggerComponent({ pgAdmin, selectedNodeInfo, panelId,
|
||||
'breakpoint_list': breakpoint_list.join(),
|
||||
},
|
||||
})
|
||||
.then(function (res) {
|
||||
setUnsetBreakpoint(res, breakpoint_list);
|
||||
.then(function () {
|
||||
editor.current.clearBreakpoints();
|
||||
enableToolbarButtons();
|
||||
})
|
||||
.catch(raiseClearBrekpointError);
|
||||
@@ -448,63 +411,11 @@ export default function DebuggerComponent({ pgAdmin, selectedNodeInfo, panelId,
|
||||
|
||||
};
|
||||
|
||||
const debuggerMark = () => {
|
||||
let marker = document.createElement('div');
|
||||
marker.style.color = '#822';
|
||||
marker.innerHTML = '●';
|
||||
return marker;
|
||||
};
|
||||
|
||||
const triggerToggleBreakpoint = () => {
|
||||
disableToolbarButtons();
|
||||
let info = editor.current.lineInfo(editor.current.activeLineNo);
|
||||
let baseUrl = '';
|
||||
|
||||
// If gutterMarker is undefined that means there is no marker defined previously
|
||||
// So we need to set the breakpoint command here...
|
||||
if (info.gutterMarkers == undefined) {
|
||||
baseUrl = url_for('debugger.set_breakpoint', {
|
||||
'trans_id': params.transId,
|
||||
'line_no': editor.current.activeLineNo + 1,
|
||||
'set_type': '1',
|
||||
});
|
||||
} else {
|
||||
baseUrl = url_for('debugger.set_breakpoint', {
|
||||
'trans_id': params.transId,
|
||||
'line_no': editor.current.activeLineNo + 1,
|
||||
'set_type': '0',
|
||||
});
|
||||
}
|
||||
|
||||
api({
|
||||
url: baseUrl,
|
||||
method: 'GET',
|
||||
})
|
||||
.then(function (res) {
|
||||
if (res.data.data.status) {
|
||||
// Call function to create and update local variables ....
|
||||
let info_local = editor.current.lineInfo(editor.current.activeLineNo);
|
||||
|
||||
if (info_local.gutterMarkers != undefined) {
|
||||
editor.current.setGutterMarker(editor.current.activeLineNo, 'breakpoints', null);
|
||||
} else {
|
||||
editor.current.setGutterMarker(editor.current.activeLineNo, 'breakpoints', debuggerMark());
|
||||
}
|
||||
|
||||
enableToolbarButtons();
|
||||
} else if (res.data.status === 'NotConnected') {
|
||||
pgAdmin.Browser.notifier.alert(
|
||||
gettext('Debugger Error'),
|
||||
gettext('Error while toggling breakpoint.')
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
pgAdmin.Browser.notifier.alert(
|
||||
gettext('Debugger Error'),
|
||||
gettext('Error while toggling breakpoint.')
|
||||
);
|
||||
});
|
||||
const lineNo = editor.current.getActiveLine();
|
||||
editor.current.toggleBreakpoint(lineNo);
|
||||
enableToolbarButtons();
|
||||
};
|
||||
|
||||
const stopDebugging = () => {
|
||||
@@ -522,7 +433,7 @@ export default function DebuggerComponent({ pgAdmin, selectedNodeInfo, panelId,
|
||||
.then(function (res) {
|
||||
if (res.data.data.status) {
|
||||
// Remove active time in the editor
|
||||
setActiveLine(-1);
|
||||
editor.current.setActiveLine(-1);
|
||||
// Clear timeout on stop debugger.
|
||||
clearTimeout(timeOut);
|
||||
|
||||
@@ -628,7 +539,7 @@ export default function DebuggerComponent({ pgAdmin, selectedNodeInfo, panelId,
|
||||
|
||||
const pollEndExecuteError = (res) => {
|
||||
params.directDebugger.direct_execution_completed = true;
|
||||
setActiveLine(-1);
|
||||
editor.current.setActiveLine(-1);
|
||||
|
||||
//Set the notification message to inform the user that execution is
|
||||
// completed with error.
|
||||
@@ -654,7 +565,7 @@ export default function DebuggerComponent({ pgAdmin, selectedNodeInfo, panelId,
|
||||
|
||||
const updateResultAndMessages = (res) => {
|
||||
if (res.data.data.result != null) {
|
||||
setActiveLine(-1);
|
||||
editor.current.setActiveLine(-1);
|
||||
// Call function to update results information and set result panel focus
|
||||
eventBus.current.fireEvent(DEBUGGER_EVENTS.SET_RESULTS, res.data.data.col_info, res.data.data.result);
|
||||
eventBus.current.fireEvent(DEBUGGER_EVENTS.FOCUS_PANEL, PANELS.RESULTS);
|
||||
@@ -725,7 +636,7 @@ export default function DebuggerComponent({ pgAdmin, selectedNodeInfo, panelId,
|
||||
As Once the EDB procedure execution is completed then we are
|
||||
not getting any result so we need to ignore the result.
|
||||
*/
|
||||
setActiveLine(-1);
|
||||
editor.current.setActiveLine(-1);
|
||||
params.directDebugger.direct_execution_completed = true;
|
||||
params.directDebugger.polling_timeout_idle = true;
|
||||
|
||||
@@ -852,26 +763,9 @@ export default function DebuggerComponent({ pgAdmin, selectedNodeInfo, panelId,
|
||||
return breakpoint_list;
|
||||
};
|
||||
|
||||
// Function to get the latest breakpoint information and update the
|
||||
// gutters of codemirror
|
||||
// Function to get the latest breakpoint information
|
||||
const updateBreakpoint = (transId, updateLocalVar = false) => {
|
||||
let callBackFunc = (br_list) => {
|
||||
// If there is no break point to clear then we should return from here.
|
||||
if ((br_list.length == 1) && (br_list[0].linenumber == -1))
|
||||
return;
|
||||
|
||||
let breakpoint_list = getBreakpointList(br_list);
|
||||
|
||||
|
||||
for (let brk_val of breakpoint_list) {
|
||||
let info = editor.current.lineInfo((brk_val - 1));
|
||||
|
||||
if (info.gutterMarkers != undefined) {
|
||||
editor.current.setGutterMarker((brk_val - 1), 'breakpoints', null);
|
||||
} else {
|
||||
editor.current.setGutterMarker((brk_val - 1), 'breakpoints', debuggerMark());
|
||||
}
|
||||
}
|
||||
let callBackFunc = () => {
|
||||
if (updateLocalVar) {
|
||||
// Call function to create and update local variables ....
|
||||
getLocalVariables(params.transId);
|
||||
@@ -976,7 +870,7 @@ export default function DebuggerComponent({ pgAdmin, selectedNodeInfo, panelId,
|
||||
const updateInfo = (res, transId) => {
|
||||
if (!params.directDebugger.debug_type && !params.directDebugger.first_time_indirect_debug) {
|
||||
setLoaderText('');
|
||||
setActiveLine(-1);
|
||||
editor.current.setActiveLine(-1);
|
||||
clearAllBreakpoint(transId);
|
||||
|
||||
params.directDebugger.first_time_indirect_debug = true;
|
||||
@@ -987,7 +881,7 @@ export default function DebuggerComponent({ pgAdmin, selectedNodeInfo, panelId,
|
||||
// If the source is really changed then only update the breakpoint information
|
||||
updateBreakpointInfo(res, transId);
|
||||
|
||||
setActiveLine(res.data.data.result[0].linenumber - 2);
|
||||
editor.current.setActiveLine(res.data.data.result[0].linenumber - 1);
|
||||
// Update the stack, local variables and parameters information
|
||||
setTimeout(function () {
|
||||
getStackInformation(transId);
|
||||
|
||||
@@ -16,7 +16,7 @@ import gettext from 'sources/gettext';
|
||||
import url_for from 'sources/url_for';
|
||||
|
||||
import getApiInstance from '../../../../../static/js/api_instance';
|
||||
import CodeMirror from '../../../../../static/js/components/CodeMirror';
|
||||
import CodeMirror from '../../../../../static/js/components/ReactCodeMirror';
|
||||
import { DEBUGGER_EVENTS } from '../DebuggerConstants';
|
||||
import { DebuggerEventsContext } from './DebuggerComponent';
|
||||
import { usePgAdmin } from '../../../../../static/js/BrowserComponent';
|
||||
@@ -36,13 +36,6 @@ export default function DebuggerEditor({ getEditor, params }) {
|
||||
|
||||
const api = getApiInstance();
|
||||
|
||||
function makeMarker() {
|
||||
let marker = document.createElement('div');
|
||||
marker.style.color = '#822';
|
||||
marker.innerHTML = '●';
|
||||
return marker;
|
||||
}
|
||||
|
||||
function setBreakpoint(lineNo, setType) {
|
||||
// Make ajax call to set/clear the break point by user
|
||||
let baseUrl = url_for('debugger.set_breakpoint', {
|
||||
@@ -67,31 +60,6 @@ export default function DebuggerEditor({ getEditor, params }) {
|
||||
});
|
||||
}
|
||||
|
||||
function onBreakPoint(cm, n, gutter) {
|
||||
// If breakpoint gutter is clicked and execution is not completed then only set the breakpoint
|
||||
if (gutter == 'breakpoints' && !params.debuggerDirect.polling_timeout_idle) {
|
||||
let info = cm.lineInfo(n);
|
||||
// If gutterMarker is undefined that means there is no marker defined previously
|
||||
// So we need to set the breakpoint command here...
|
||||
if (info.gutterMarkers == undefined) {
|
||||
setBreakpoint(n + 1, 1); //set the breakpoint
|
||||
} else {
|
||||
if (info.gutterMarkers.breakpoints == undefined) {
|
||||
setBreakpoint(n + 1, 1); //set the breakpoint
|
||||
} else {
|
||||
setBreakpoint(n + 1, 0); //clear the breakpoint
|
||||
}
|
||||
}
|
||||
|
||||
// If line folding is defined then gutterMarker will be defined so
|
||||
// we need to find out 'breakpoints' information
|
||||
let markers = info.gutterMarkers;
|
||||
if (markers != undefined && info.gutterMarkers.breakpoints == undefined)
|
||||
markers = info.gutterMarkers.breakpoints;
|
||||
cm.setGutterMarker(n, 'breakpoints', markers ? null : makeMarker());
|
||||
}
|
||||
}
|
||||
|
||||
eventBus.registerListener(DEBUGGER_EVENTS.EDITOR_SET_SQL, (value, focus = true) => {
|
||||
focus && editor.current?.focus();
|
||||
editor.current?.setValue(value);
|
||||
@@ -99,19 +67,21 @@ export default function DebuggerEditor({ getEditor, params }) {
|
||||
|
||||
useEffect(() => {
|
||||
self = this;
|
||||
// Register the callback when user set/clear the breakpoint on gutter area.
|
||||
editor.current.on('gutterClick', onBreakPoint);
|
||||
getEditor(editor.current);
|
||||
}, [editor.current]);
|
||||
|
||||
return (
|
||||
<CodeMirror
|
||||
currEditor={(obj) => {
|
||||
editor.current = obj;
|
||||
}}
|
||||
gutters={['CodeMirror-linenumbers', 'CodeMirror-foldgutter', 'breakpoints']}
|
||||
value={''}
|
||||
onBreakPointChange={(line, on)=>{
|
||||
setBreakpoint(line, on ? 1 : 0);
|
||||
}}
|
||||
className={classes.sql}
|
||||
disabled={true}
|
||||
readonly={true}
|
||||
breakpoint
|
||||
/>);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
try {
|
||||
require(
|
||||
['sources/generated/debugger', 'sources/pgadmin', 'sources/generated/codemirror'],
|
||||
['sources/generated/debugger', 'sources/pgadmin'],
|
||||
function(pgDirectDebug, pgAdmin) {
|
||||
var pgDebug = window.pgAdmin.Tools.Debugger;
|
||||
pgDebug.load(document.getElementById('debugger-main-container'), {{ uniqueId }}, {{ debug_type }}, '{{ function_name_with_arguments }}', '{{layout|safe}}');
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
{% block init_script %}
|
||||
try {
|
||||
require(
|
||||
['sources/generated/browser_nodes', 'sources/generated/codemirror'],
|
||||
['sources/generated/browser_nodes'],
|
||||
function() {
|
||||
require(['sources/generated/erd_tool'], function(module) {
|
||||
window.pgAdmin.Tools.ERD.loadComponent(
|
||||
|
||||
@@ -108,17 +108,6 @@
|
||||
height: calc(100% - #{$footer-height-calc});
|
||||
}
|
||||
|
||||
.wizard-right-panel_content .CodeMirror {
|
||||
border: 1px solid $color-gray-light;
|
||||
height: 100% !important;
|
||||
min-height: 100% !important;
|
||||
}
|
||||
|
||||
.wizard-right-panel_content .CodeMirror-linenumber {
|
||||
background: $color-gray-light;
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.grant_wizard_container {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{% block init_script %}
|
||||
try {
|
||||
require(
|
||||
['sources/generated/codemirror', 'sources/generated/browser_nodes', 'sources/generated/schema_diff'],
|
||||
['sources/generated/browser_nodes', 'sources/generated/schema_diff'],
|
||||
function() {
|
||||
var pgSchemaDiff = window.pgAdmin.Tools.SchemaDiff;
|
||||
pgSchemaDiff.load(document.getElementById('schema-diff-main-container'),{{trans_id}});
|
||||
|
||||
@@ -10,13 +10,12 @@ import { makeStyles } from '@material-ui/styles';
|
||||
import React, {useContext, useCallback, useEffect } from 'react';
|
||||
import { format } from 'sql-formatter';
|
||||
import { QueryToolContext, QueryToolEventsContext } from '../QueryToolComponent';
|
||||
import CodeMirror from '../../../../../../static/js/components/CodeMirror';
|
||||
import CodeMirror from '../../../../../../static/js/components/ReactCodeMirror';
|
||||
import {PANELS, QUERY_TOOL_EVENTS} from '../QueryToolConstants';
|
||||
import url_for from 'sources/url_for';
|
||||
import { LayoutDockerContext, LAYOUT_EVENTS } from '../../../../../../static/js/helpers/Layout';
|
||||
import ConfirmSaveContent from '../../../../../../static/js/Dialogs/ConfirmSaveContent';
|
||||
import gettext from 'sources/gettext';
|
||||
import OrigCodeMirror from 'bundled_codemirror';
|
||||
import { isMac } from '../../../../../../static/js/keyboard_shortcuts';
|
||||
import { checkTrojanSource } from '../../../../../../static/js/utils';
|
||||
import { parseApiError } from '../../../../../../static/js/api_instance';
|
||||
@@ -32,211 +31,32 @@ const useStyles = makeStyles(()=>({
|
||||
}
|
||||
}));
|
||||
|
||||
function registerAutocomplete(api, transId, sqlEditorPref, onFailure) {
|
||||
let timeoutId;
|
||||
let loadingEle;
|
||||
let prevSearch = null;
|
||||
OrigCodeMirror.registerHelper('hint', 'sql', function (editor) {
|
||||
let data = [],
|
||||
doc = editor.getDoc(),
|
||||
cur = doc.getCursor(),
|
||||
// function context
|
||||
ctx = {
|
||||
editor: editor,
|
||||
// URL for auto-complete
|
||||
url: url_for('sqleditor.autocomplete', {
|
||||
'trans_id': transId,
|
||||
}),
|
||||
data: data,
|
||||
// Get the line number in the cursor position
|
||||
current_line: cur.line,
|
||||
/*
|
||||
* Render function for hint to add our own class
|
||||
* and icon as per the object type.
|
||||
*/
|
||||
hint_render: function (elt, data_arg, cur_arg) {
|
||||
let el = document.createElement('span');
|
||||
switch (cur_arg.type) {
|
||||
case 'database':
|
||||
el.className = 'sqleditor-hint pg-icon-' + cur_arg.type;
|
||||
break;
|
||||
case 'datatype':
|
||||
el.className = 'sqleditor-hint icon-type';
|
||||
break;
|
||||
case 'keyword':
|
||||
el.className = 'sqleditor-hint icon-key';
|
||||
break;
|
||||
case 'table alias':
|
||||
el.className = 'sqleditor-hint icon-at';
|
||||
break;
|
||||
case 'join':
|
||||
case 'fk join':
|
||||
el.className = 'sqleditor-hint icon-join';
|
||||
break;
|
||||
default:
|
||||
el.className = 'sqleditor-hint icon-' + cur_arg.type;
|
||||
}
|
||||
|
||||
el.appendChild(document.createTextNode(cur_arg.text));
|
||||
elt.appendChild(el);
|
||||
},
|
||||
};
|
||||
|
||||
data.push(doc.getValue());
|
||||
|
||||
if (!editor.state.autoCompleteList)
|
||||
editor.state.autoCompleteList = [];
|
||||
|
||||
// This function is used to show the loading element until response comes.
|
||||
const showLoading = (editor)=>{
|
||||
if (editor.getInputField().getAttribute('aria-activedescendant') != null) {
|
||||
hideLoading();
|
||||
return;
|
||||
}
|
||||
|
||||
if(!loadingEle) {
|
||||
let ownerDocument = editor.getInputField().ownerDocument;
|
||||
loadingEle = ownerDocument.createElement('div');
|
||||
loadingEle.className = 'CodeMirror-hints';
|
||||
let iconEle = ownerDocument.createElement('div');
|
||||
iconEle.className = 'icon-spinner';
|
||||
iconEle.style.marginTop = '4px';
|
||||
iconEle.style.marginLeft = '2px';
|
||||
|
||||
let spanEle = ownerDocument.createElement('span');
|
||||
spanEle.innerText = gettext('Loading...');
|
||||
spanEle.style.marginLeft = '17px';
|
||||
|
||||
iconEle.appendChild(spanEle);
|
||||
loadingEle.appendChild(iconEle);
|
||||
ownerDocument.body.appendChild(loadingEle);
|
||||
}
|
||||
let pos = editor.cursorCoords(true);
|
||||
loadingEle.style.left = pos.left + 'px';
|
||||
loadingEle.style.top = pos.bottom + 'px';
|
||||
loadingEle.style.height = '25px';
|
||||
};
|
||||
|
||||
// This function is used to hide the loading element.
|
||||
const hideLoading = ()=>{
|
||||
loadingEle?.parentNode?.removeChild(loadingEle);
|
||||
loadingEle = null;
|
||||
};
|
||||
|
||||
return {
|
||||
then: function (cb) {
|
||||
let self_local = this;
|
||||
|
||||
// This function is used to filter the data and call the callback
|
||||
// function with that filtered data.
|
||||
function setAutoCompleteData() {
|
||||
const searchRe = new RegExp('^"{0,1}' + search, 'i');
|
||||
let filterData = self_local.editor.state.autoCompleteList.filter((item)=>{
|
||||
return searchRe.test(item.text);
|
||||
async function registerAutocomplete(editor, api, transId) {
|
||||
editor.registerAutocomplete((context, onAvailable)=>{
|
||||
return new Promise((resolve, reject)=>{
|
||||
const url = url_for('sqleditor.autocomplete', {
|
||||
'trans_id': transId,
|
||||
});
|
||||
const word = context.matchBefore(/\w*/);
|
||||
const fullSql = context.state.doc.toString();
|
||||
api.post(url, JSON.stringify([fullSql, fullSql]))
|
||||
.then((res) => {
|
||||
onAvailable();
|
||||
resolve({
|
||||
from: word.from,
|
||||
options: Object.keys(res.data.data.result).map((key)=>({
|
||||
label: key, type: res.data.data.result[key].object_type
|
||||
})),
|
||||
validFor: (text, from)=>{
|
||||
return text.startsWith(fullSql.slice(from));
|
||||
}
|
||||
});
|
||||
|
||||
cb({
|
||||
list: filterData,
|
||||
from: {
|
||||
line: self_local.current_line,
|
||||
ch: start,
|
||||
},
|
||||
to: {
|
||||
line: self_local.current_line,
|
||||
ch: end,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Below logic find the start and end point
|
||||
* to replace the selected auto complete suggestion.
|
||||
*/
|
||||
let token = self_local.editor.getTokenAt(cur),
|
||||
start, end, search;
|
||||
if (token.end > cur.ch) {
|
||||
token.end = cur.ch;
|
||||
token.string = token.string.slice(0, cur.ch - token.start);
|
||||
}
|
||||
|
||||
if (token.string.match(/^[."`\w@]\w*$/)) {
|
||||
search = token.string;
|
||||
start = token.start;
|
||||
end = token.end;
|
||||
} else {
|
||||
start = end = cur.ch;
|
||||
search = '';
|
||||
}
|
||||
|
||||
/*
|
||||
* Added 1 in the start position if search string
|
||||
* started with "." or "`" else auto complete of code mirror
|
||||
* will remove the "." when user select any suggestion.
|
||||
*/
|
||||
if (search.charAt(0) == '.' || search.charAt(0) == '``') {
|
||||
start += 1;
|
||||
search = search.slice(1);
|
||||
}
|
||||
|
||||
// Handled special case when autocomplete on keypress is off,
|
||||
// the query is cleared, and retype some other words and press CTRL/CMD + Space.
|
||||
if (!sqlEditorPref.autocomplete_on_key_press && start == 0)
|
||||
self_local.editor.state.autoCompleteList = [];
|
||||
|
||||
// Clear the auto complete list if previous token/search is blank or dot.
|
||||
if (prevSearch == '' || prevSearch == '.' || prevSearch == '"')
|
||||
self_local.editor.state.autoCompleteList = [];
|
||||
|
||||
prevSearch = search;
|
||||
// Get the text from start to the current cursor position.
|
||||
self_local.data.push(
|
||||
doc.getRange({
|
||||
line: 0,
|
||||
ch: 0,
|
||||
}, {
|
||||
line: self_local.current_line,
|
||||
ch: token.start + 1,
|
||||
})
|
||||
);
|
||||
|
||||
// If search token is not empty and auto complete list have some data
|
||||
// then no need to send the request to the backend to fetch the data.
|
||||
// auto complete the data using already fetched list.
|
||||
if (search != '' && self_local.editor.state.autoCompleteList.length != 0) {
|
||||
setAutoCompleteData();
|
||||
return;
|
||||
}
|
||||
|
||||
//Show loading indicator
|
||||
showLoading(self_local.editor);
|
||||
|
||||
timeoutId && clearTimeout(timeoutId);
|
||||
timeoutId = setTimeout(()=> {
|
||||
timeoutId = null;
|
||||
// Make ajax call to find the autocomplete data
|
||||
api.post(self_local.url, JSON.stringify(self_local.data))
|
||||
.then((res) => {
|
||||
hideLoading();
|
||||
let result = [];
|
||||
|
||||
_.each(res.data.data.result, function (obj, key) {
|
||||
result.push({
|
||||
text: key,
|
||||
type: obj.object_type,
|
||||
render: self_local.hint_render,
|
||||
});
|
||||
});
|
||||
|
||||
self_local.editor.state.autoCompleteList = result;
|
||||
setAutoCompleteData();
|
||||
})
|
||||
.catch((err) => {
|
||||
hideLoading();
|
||||
onFailure?.(err);
|
||||
});
|
||||
}, 300);
|
||||
}.bind(ctx),
|
||||
};
|
||||
})
|
||||
.catch((err) => {
|
||||
onAvailable();
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -247,31 +67,22 @@ export default function Query() {
|
||||
const queryToolCtx = useContext(QueryToolContext);
|
||||
const layoutDocker = useContext(LayoutDockerContext);
|
||||
const lastCursorPos = React.useRef();
|
||||
const lastSavedText = React.useRef('');
|
||||
const markedLine = React.useRef(0);
|
||||
const marker = React.useRef();
|
||||
const pgAdmin = usePgAdmin();
|
||||
const preferencesStore = usePreferences();
|
||||
|
||||
const removeHighlightError = (cmObj)=>{
|
||||
// Remove already existing marker
|
||||
marker.current?.clear();
|
||||
cmObj.removeLineClass(markedLine.current, 'wrap', 'CodeMirror-activeline-background');
|
||||
markedLine.current = 0;
|
||||
};
|
||||
const highlightError = (cmObj, {errormsg: result, data})=>{
|
||||
let errorLineNo = 0,
|
||||
startMarker = 0,
|
||||
endMarker = 0,
|
||||
selectedLineNo = 0,
|
||||
selectedLineNo = 1,
|
||||
origQueryLen = cmObj.getValue().length;
|
||||
|
||||
removeHighlightError(cmObj);
|
||||
cmObj.removeErrorMark();
|
||||
|
||||
// In case of selection we need to find the actual line no
|
||||
if (cmObj.getSelection().length > 0) {
|
||||
selectedLineNo = cmObj.getCursor(true).line;
|
||||
origQueryLen = cmObj.getLine(selectedLineNo).length;
|
||||
selectedLineNo = cmObj.getCurrentLineNo();
|
||||
origQueryLen = cmObj.line(selectedLineNo).length;
|
||||
}
|
||||
|
||||
// Fetch the LINE string using regex from the result
|
||||
@@ -281,8 +92,8 @@ export default function Query() {
|
||||
|
||||
// If line and character is null then no need to mark
|
||||
if (line != null && char != null) {
|
||||
errorLineNo = (parseInt(line[1]) - 1) + selectedLineNo;
|
||||
let errorCharNo = (parseInt(char[1]) - 1);
|
||||
errorLineNo = parseInt(line[1]) + selectedLineNo - 1;
|
||||
let errorCharNo = parseInt(char[1]) - 1;
|
||||
|
||||
/* If explain query has been run we need to
|
||||
calculate the character number.
|
||||
@@ -298,8 +109,8 @@ export default function Query() {
|
||||
* have also added 1 per line for the "\n" character.
|
||||
*/
|
||||
let prevLineChars = 0;
|
||||
for (let i = selectedLineNo > 0 ? selectedLineNo : 0; i < errorLineNo; i++)
|
||||
prevLineChars += cmObj.getLine(i).length + 1;
|
||||
for (let i = selectedLineNo; i < errorLineNo; i++)
|
||||
prevLineChars += cmObj.getLine(i).length;
|
||||
|
||||
/* Marker starting point for the individual line is
|
||||
* equal to error character index minus total no of
|
||||
@@ -316,18 +127,14 @@ export default function Query() {
|
||||
endMarker = errorLine.length;
|
||||
|
||||
// Mark the error text
|
||||
marker.current = cmObj.markText({
|
||||
cmObj.setErrorMark({
|
||||
line: errorLineNo,
|
||||
ch: startMarker,
|
||||
pos: startMarker,
|
||||
}, {
|
||||
line: errorLineNo,
|
||||
ch: endMarker,
|
||||
}, {
|
||||
className: 'sql-editor-mark',
|
||||
pos: endMarker,
|
||||
});
|
||||
|
||||
markedLine.current = errorLineNo;
|
||||
cmObj.addLineClass(errorLineNo, 'wrap', 'CodeMirror-activeline-background');
|
||||
cmObj.focus();
|
||||
cmObj.setCursor(errorLineNo, endMarker);
|
||||
}
|
||||
@@ -364,7 +171,7 @@ export default function Query() {
|
||||
if(result) {
|
||||
highlightError(editor.current, result);
|
||||
} else {
|
||||
removeHighlightError(editor.current);
|
||||
editor.current.removeErrorMark();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -381,7 +188,7 @@ export default function Query() {
|
||||
editor.current.setValue(res.data);
|
||||
//Check the file content for Trojan Source
|
||||
checkTrojanSource(res.data);
|
||||
lastSavedText.current = res.data;
|
||||
editor.current.markClean();
|
||||
eventBus.fireEvent(QUERY_TOOL_EVENTS.LOAD_FILE_DONE, fileName, true);
|
||||
}).catch((err)=>{
|
||||
eventBus.fireEvent(QUERY_TOOL_EVENTS.LOAD_FILE_DONE, null, false);
|
||||
@@ -390,12 +197,11 @@ export default function Query() {
|
||||
});
|
||||
|
||||
eventBus.registerListener(QUERY_TOOL_EVENTS.SAVE_FILE, (fileName)=>{
|
||||
let editorValue = editor.current.getValue();
|
||||
queryToolCtx.api.post(url_for('sqleditor.save_file'), {
|
||||
'file_name': decodeURI(fileName),
|
||||
'file_content': editor.current.getValue(),
|
||||
}).then(()=>{
|
||||
lastSavedText.current = editorValue;
|
||||
editor.current.markClean();
|
||||
eventBus.fireEvent(QUERY_TOOL_EVENTS.SAVE_FILE_DONE, fileName, true);
|
||||
pgAdmin.Browser.notifier.success(gettext('File saved successfully.'));
|
||||
}).catch((err)=>{
|
||||
@@ -426,16 +232,11 @@ export default function Query() {
|
||||
key.shiftKey = false;
|
||||
key.altKey = replace;
|
||||
}
|
||||
editor.current?.triggerOnKeyDown(
|
||||
new KeyboardEvent('keydown', key)
|
||||
);
|
||||
editor.current?.fireDOMEvent(new KeyboardEvent('keydown', key));
|
||||
});
|
||||
eventBus.registerListener(QUERY_TOOL_EVENTS.EDITOR_SET_SQL, (value, focus=true)=>{
|
||||
focus && editor.current?.focus();
|
||||
if(!queryToolCtx.params.is_query_tool){
|
||||
lastSavedText.current = value;
|
||||
}
|
||||
editor.current?.setValue(value);
|
||||
editor.current?.setValue(value, !queryToolCtx.params.is_query_tool);
|
||||
if (value == '' && editor.current) {
|
||||
editor.current.state.autoCompleteList = [];
|
||||
}
|
||||
@@ -500,7 +301,7 @@ export default function Query() {
|
||||
|
||||
useEffect(()=>{
|
||||
const warnSaveTextClose = ()=>{
|
||||
if(!isDirty() || !queryToolCtx.preferences?.sqleditor.prompt_save_query_changes) {
|
||||
if(!editor.current.isDirty() || !queryToolCtx.preferences?.sqleditor.prompt_save_query_changes) {
|
||||
eventBus.fireEvent(QUERY_TOOL_EVENTS.WARN_TXN_CLOSE);
|
||||
return;
|
||||
}
|
||||
@@ -526,23 +327,20 @@ export default function Query() {
|
||||
}, [queryToolCtx.preferences]);
|
||||
|
||||
useEffect(()=>{
|
||||
registerAutocomplete(queryToolCtx.api, queryToolCtx.params.trans_id, queryToolCtx.preferences.sqleditor,
|
||||
registerAutocomplete(editor.current, queryToolCtx.api, queryToolCtx.params.trans_id, queryToolCtx.preferences.sqleditor,
|
||||
(err)=>{eventBus.fireEvent(QUERY_TOOL_EVENTS.HANDLE_API_ERROR, err);}
|
||||
);
|
||||
}, [queryToolCtx.params.trans_id]);
|
||||
|
||||
const isDirty = ()=>(lastSavedText.current !== editor.current.getValue());
|
||||
|
||||
const cursorActivity = useCallback(_.debounce((cmObj)=>{
|
||||
const c = cmObj.getCursor();
|
||||
lastCursorPos.current = c;
|
||||
eventBus.fireEvent(QUERY_TOOL_EVENTS.CURSOR_ACTIVITY, [c.line+1, c.ch+1]);
|
||||
const cursorActivity = useCallback(_.debounce((cursor)=>{
|
||||
lastCursorPos.current = cursor;
|
||||
eventBus.fireEvent(QUERY_TOOL_EVENTS.CURSOR_ACTIVITY, [lastCursorPos.current.line, lastCursorPos.current.ch+1]);
|
||||
}, 100), []);
|
||||
|
||||
const change = useCallback(()=>{
|
||||
eventBus.fireEvent(QUERY_TOOL_EVENTS.QUERY_CHANGED, isDirty());
|
||||
eventBus.fireEvent(QUERY_TOOL_EVENTS.QUERY_CHANGED, editor.current.isDirty());
|
||||
|
||||
if(!queryToolCtx.params.is_query_tool && isDirty()){
|
||||
if(!queryToolCtx.params.is_query_tool && editor.current.isDirty()){
|
||||
if(queryToolCtx.preferences.sqleditor.view_edit_promotion_warning){
|
||||
checkViewEditDataPromotion();
|
||||
} else {
|
||||
@@ -552,7 +350,7 @@ export default function Query() {
|
||||
}, []);
|
||||
|
||||
const closePromotionWarning = (closeModal)=>{
|
||||
if(isDirty()) {
|
||||
if(editor.current.isDirty()) {
|
||||
editor.current.undo();
|
||||
closeModal?.();
|
||||
}
|
||||
@@ -567,7 +365,7 @@ export default function Query() {
|
||||
promoteToQueryTool();
|
||||
let cursor = editor.current.getCursor();
|
||||
editor.current.setValue(editor.current.getValue());
|
||||
editor.current.setCursor(cursor);
|
||||
editor.current.setCursor(cursor.line, cursor.ch);
|
||||
editor.current.focus();
|
||||
let title = getTitle(pgAdmin, queryToolCtx.preferences.browser, null,null,queryToolCtx.params.server_name, queryToolCtx.params.dbname, queryToolCtx.params.user);
|
||||
queryToolCtx.updateTitle(title);
|
||||
@@ -599,11 +397,9 @@ export default function Query() {
|
||||
}}
|
||||
value={''}
|
||||
className={classes.sql}
|
||||
events={{
|
||||
'focus': cursorActivity,
|
||||
'cursorActivity': cursorActivity,
|
||||
'change': change,
|
||||
}}
|
||||
onCursorActivity={cursorActivity}
|
||||
onChange={change}
|
||||
autocomplete={true}
|
||||
keepHistory={queryToolCtx.params.is_query_tool}
|
||||
/>;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ import AssessmentRoundedIcon from '@material-ui/icons/AssessmentRounded';
|
||||
import ExplicitRoundedIcon from '@material-ui/icons/ExplicitRounded';
|
||||
import { SaveDataIcon, CommitIcon, RollbackIcon, ViewDataIcon } from '../../../../../../static/js/components/ExternalIcon';
|
||||
import { InputSwitch } from '../../../../../../static/js/components/FormComponents';
|
||||
import CodeMirror from '../../../../../../static/js/components/CodeMirror';
|
||||
import CodeMirror from '../../../../../../static/js/components/ReactCodeMirror';
|
||||
import { DefaultButton } from '../../../../../../static/js/components/Buttons';
|
||||
import { useDelayedCaller } from '../../../../../../static/js/custom_hooks';
|
||||
import Loader from 'sources/components/Loader';
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
{% block init_script %}
|
||||
try {
|
||||
require(
|
||||
['sources/generated/browser_nodes', 'sources/generated/codemirror'],
|
||||
['sources/generated/browser_nodes'],
|
||||
function() {
|
||||
require(['sources/generated/sqleditor'], function(module) {
|
||||
window.pgAdmin.Tools.SQLEditor.loadComponent(
|
||||
|
||||
Reference in New Issue
Block a user