Upgrade CodeMirror from version 5 to 6. #7097

This commit is contained in:
Aditya Toshniwal
2024-02-21 11:15:25 +05:30
committed by GitHub
parent 721290b1e9
commit d3ede3151a
53 changed files with 1565 additions and 1611 deletions

View File

@@ -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);

View File

@@ -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
/>);
}

View File

@@ -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}}');

View File

@@ -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(

View File

@@ -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;

View File

@@ -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}});

View File

@@ -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}
/>;
}

View File

@@ -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';

View File

@@ -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(