More CodeMirror fixes. #7268

Fix query tool autocomplete results when cursor is in between the SQL query. #7299
Fix an issue in query tool where custom keyboard shortcuts are not working for some. #7305
pull/7315/head
Aditya Toshniwal 2024-03-23 18:22:06 +05:30
parent 25074e46b4
commit cc1ce09b73
12 changed files with 76 additions and 37 deletions

View File

@ -37,3 +37,5 @@ Bug fixes
| `Issue #7268 <https://github.com/pgadmin-org/pgadmin4/issues/7268>`_ - Fix an issue in editor where Format SQL shortcut and multiline selection are not working. | `Issue #7268 <https://github.com/pgadmin-org/pgadmin4/issues/7268>`_ - Fix an issue in editor where Format SQL shortcut and multiline selection are not working.
| `Issue #7269 <https://github.com/pgadmin-org/pgadmin4/issues/7269>`_ - Fix an issue in editor where "Use Spaces?" Preference of Editor is not working. | `Issue #7269 <https://github.com/pgadmin-org/pgadmin4/issues/7269>`_ - Fix an issue in editor where "Use Spaces?" Preference of Editor is not working.
| `Issue #7277 <https://github.com/pgadmin-org/pgadmin4/issues/7277>`_ - Fix an issue in query tool where toggle case of selected text loses selection. | `Issue #7277 <https://github.com/pgadmin-org/pgadmin4/issues/7277>`_ - Fix an issue in query tool where toggle case of selected text loses selection.
| `Issue #7299 <https://github.com/pgadmin-org/pgadmin4/issues/7299>`_ - Fix query tool autocomplete results when cursor is in between the SQL query.
| `Issue #7305 <https://github.com/pgadmin-org/pgadmin4/issues/7305>`_ - Fix an issue in query tool where custom keyboard shortcuts are not working for some.

View File

@ -76,7 +76,7 @@
"dependencies": { "dependencies": {
"@babel/plugin-proposal-class-properties": "^7.10.4", "@babel/plugin-proposal-class-properties": "^7.10.4",
"@babel/preset-react": "^7.12.13", "@babel/preset-react": "^7.12.13",
"@codemirror/lang-sql": "^6.5.5", "@codemirror/lang-sql": "^6.6.2",
"@date-io/core": "^1.3.6", "@date-io/core": "^1.3.6",
"@date-io/date-fns": "1.x", "@date-io/date-fns": "1.x",
"@emotion/sheet": "^1.0.1", "@emotion/sheet": "^1.0.1",

View File

@ -102,9 +102,11 @@ export default function cmOverride(theme) {
} }
}, },
'.cm-tooltip': { '.cm-tooltip': {
...theme.mixins.fontSourceCode,
backgroundColor: theme.palette.background.default + '!important', backgroundColor: theme.palette.background.default + '!important',
color: theme.palette.text.primary + '!important', color: theme.palette.text.primary + '!important',
border: `1px solid ${theme.otherVars.borderColor} !important`, border: `1px solid ${theme.otherVars.borderColor} !important`,
fontSize: '0.9em',
'& li[aria-selected="true"]': { '& li[aria-selected="true"]': {
backgroundColor: theme.otherVars.treeBgSelected + '!important', backgroundColor: theme.otherVars.treeBgSelected + '!important',

View File

@ -27,7 +27,10 @@ export default class CustomEditorView extends EditorView {
this._cleanDoc = this.state.doc; this._cleanDoc = this.state.doc;
} }
getValue() { getValue(tillCursor=false) {
if(tillCursor) {
return this.state.sliceDoc(0, this.state.selection.main.head);
}
return this.state.doc.toString(); return this.state.doc.toString();
} }

View File

@ -1,5 +1,6 @@
import {useRef, useEffect, useState, useCallback, useLayoutEffect} from 'react'; import {useRef, useEffect, useState, useCallback, useLayoutEffect} from 'react';
import moment from 'moment'; import moment from 'moment';
import { isMac } from './keyboard_shortcuts';
/* React hook for setInterval */ /* React hook for setInterval */
export function useInterval(callback, delay) { export function useInterval(callback, delay) {
@ -150,9 +151,11 @@ export function useKeyboardShortcuts(shortcuts, eleRef) {
const matchFound = (shortcut, e)=>{ const matchFound = (shortcut, e)=>{
if(!shortcut) return false; if(!shortcut) return false;
let keyCode = e.which || e.keyCode; let keyCode = e.which || e.keyCode;
const ctrlKey = (isMac() && shortcut.ctrl_is_meta) ? e.metaKey : e.ctrlKey;
return Boolean(shortcut.alt) == e.altKey && return Boolean(shortcut.alt) == e.altKey &&
Boolean(shortcut.shift) == e.shiftKey && Boolean(shortcut.shift) == e.shiftKey &&
Boolean(shortcut.control) == e.ctrlKey && Boolean(shortcut.control) == ctrlKey &&
shortcut.key.key_code == keyCode; shortcut.key.key_code == keyCode;
}; };
useEffect(()=>{ useEffect(()=>{

View File

@ -46,7 +46,7 @@ export function toCodeMirrorKey(obj) {
if (obj.shift) { shortcut += 'Shift-'; } if (obj.shift) { shortcut += 'Shift-'; }
if (obj.control) { if (obj.control) {
if(isMac() && obj.ctrl_is_meta) { if(isMac() && obj.ctrl_is_meta) {
shortcut += 'Mod-'; shortcut += 'Meta-';
} else { } else {
shortcut += 'Ctrl-'; shortcut += 'Ctrl-';
} }

View File

@ -26,7 +26,7 @@ import DebuggerComponent from './components/DebuggerComponent';
import Theme from '../../../../static/js/Theme'; import Theme from '../../../../static/js/Theme';
import { BROWSER_PANELS } from '../../../../browser/static/js/constants'; import { BROWSER_PANELS } from '../../../../browser/static/js/constants';
import { NotifierProvider } from '../../../../static/js/helpers/Notifier'; import { NotifierProvider } from '../../../../static/js/helpers/Notifier';
import usePreferences from '../../../../preferences/static/js/store'; import usePreferences, { listenPreferenceBroadcast } from '../../../../preferences/static/js/store';
import pgAdmin from 'sources/pgadmin'; import pgAdmin from 'sources/pgadmin';
import { PgAdminContext } from '../../../../static/js/BrowserComponent'; import { PgAdminContext } from '../../../../static/js/BrowserComponent';
@ -565,7 +565,7 @@ export default class DebuggerModule {
} }
/* We should get the transaction id from the server during initialization here */ /* We should get the transaction id from the server during initialization here */
load(container, trans_id, debug_type, function_name_with_arguments, layout) { async load(container, trans_id, debug_type, function_name_with_arguments, layout) {
this.trans_id = trans_id; this.trans_id = trans_id;
this.debug_type = debug_type; this.debug_type = debug_type;
this.first_time_indirect_debug = false; this.first_time_indirect_debug = false;
@ -576,11 +576,11 @@ export default class DebuggerModule {
this.is_polling_required = true; // Flag to stop unwanted ajax calls this.is_polling_required = true; // Flag to stop unwanted ajax calls
this.function_name_with_arguments = function_name_with_arguments; this.function_name_with_arguments = function_name_with_arguments;
this.layout = layout; this.layout = layout;
this.preferences = usePreferences.getState().getPreferencesForModule('debugger');
let selectedNodeInfo = pgWindow.pgAdmin.Browser.tree.getTreeNodeHierarchy( let selectedNodeInfo = pgWindow.pgAdmin.Browser.tree.getTreeNodeHierarchy(
pgWindow.pgAdmin.Browser.tree.selected() pgWindow.pgAdmin.Browser.tree.selected()
); );
await listenPreferenceBroadcast();
ReactDOM.render( ReactDOM.render(
<Theme> <Theme>

View File

@ -23,7 +23,7 @@ import pgAdmin from 'sources/pgadmin';
import Loader from 'sources/components/Loader'; import Loader from 'sources/components/Loader';
import SchemaView from '../../../../../static/js/SchemaView'; import SchemaView from '../../../../../static/js/SchemaView';
import getApiInstance from '../../../../../static/js/api_instance'; import getApiInstance, { parseApiError } from '../../../../../static/js/api_instance';
import { DefaultButton, PrimaryButton } from '../../../../../static/js/components/Buttons'; import { DefaultButton, PrimaryButton } from '../../../../../static/js/components/Buttons';
import { getAppropriateLabel, getDebuggerTitle } from '../debugger_utils'; import { getAppropriateLabel, getDebuggerTitle } from '../debugger_utils';
import { DebuggerArgumentSchema } from './DebuggerArgs.ui'; import { DebuggerArgumentSchema } from './DebuggerArgs.ui';
@ -737,7 +737,7 @@ export default function DebuggerArgumentComponent({ debuggerInfo, restartDebug,
setLoaderText(''); setLoaderText('');
pgAdmin.Browser.notifier.alert( pgAdmin.Browser.notifier.alert(
gettext('Error occured: '), gettext('Error occured: '),
gettext(error.response.data) parseApiError(error)
); );
}); });
/* Close the debugger modal dialog */ /* Close the debugger modal dialog */
@ -748,7 +748,7 @@ export default function DebuggerArgumentComponent({ debuggerInfo, restartDebug,
setLoaderText(''); setLoaderText('');
pgAdmin.Browser.notifier.alert( pgAdmin.Browser.notifier.alert(
gettext('Debugger Target Initialization Error'), gettext('Debugger Target Initialization Error'),
gettext(error.response.data) parseApiError(error)
); );
}); });
@ -769,7 +769,7 @@ export default function DebuggerArgumentComponent({ debuggerInfo, restartDebug,
props.closeModal(); props.closeModal();
pgAdmin.Browser.notifier.alert( pgAdmin.Browser.notifier.alert(
gettext('Debugger Listener Startup Error'), gettext('Debugger Listener Startup Error'),
gettext(error.response.data) parseApiError(error)
); );
}); });
setLoaderText(''); setLoaderText('');
@ -793,7 +793,7 @@ export default function DebuggerArgumentComponent({ debuggerInfo, restartDebug,
setLoaderText(''); setLoaderText('');
pgAdmin.Browser.notifier.alert( pgAdmin.Browser.notifier.alert(
gettext('Debugger Listener Startup Set Arguments Error'), gettext('Debugger Listener Startup Set Arguments Error'),
gettext(error.response.data) parseApiError(error)
); );
}); });
} }

View File

@ -8,7 +8,7 @@
////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////
import { Box } from '@material-ui/core'; import { Box } from '@material-ui/core';
import React, { useEffect, useRef } from 'react'; import React, { useEffect, useRef, useState } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import gettext from 'sources/gettext'; import gettext from 'sources/gettext';
@ -45,13 +45,11 @@ export default function DebuggerComponent({ pgAdmin, selectedNodeInfo, panelId,
const editor = useRef(null); const editor = useRef(null);
const preferencesStore = usePreferences(); const preferencesStore = usePreferences();
let timeOut = null; let timeOut = null;
const qtState = {
is_new_tab: window.location == window.parent?.location, const [preferences, setPreferences] = useState({
params: { browser: preferencesStore.getPreferencesForModule('browser'),
...params, debugger: preferencesStore.getPreferencesForModule('debugger'),
node_name: retrieveNodeName(selectedNodeInfo), });
}
};
const disableToolbarButtons = () => { const disableToolbarButtons = () => {
eventBus.current.fireEvent(DEBUGGER_EVENTS.DISABLE_MENU); eventBus.current.fireEvent(DEBUGGER_EVENTS.DISABLE_MENU);
@ -1066,16 +1064,26 @@ export default function DebuggerComponent({ pgAdmin, selectedNodeInfo, panelId,
}); });
}, []); }, []);
useEffect(() => usePreferences.subscribe(
state => {
setPreferences({
browser: state.getPreferencesForModule('browser'),
debugger: state.getPreferencesForModule('debugger'),
});
}
), []);
const DebuggerContextValue = React.useMemo(() => ({ const DebuggerContextValue = React.useMemo(() => ({
docker: docker.current, docker: docker.current,
api: api, api: api,
modal: modal, modal: modal,
params: qtState.params, params: {
preferences: { ...params,
browser: preferencesStore.getPreferencesForModule('browser'), node_name: retrieveNodeName(selectedNodeInfo),
debugger: preferencesStore.getPreferencesForModule('debugger'),
}, },
}), [qtState.params, preferencesStore]); preferences: preferences,
}), [preferences]);
// Define the debugger layout components such as DebuggerEditor to show queries and // Define the debugger layout components such as DebuggerEditor to show queries and
let defaultLayout = { let defaultLayout = {

View File

@ -318,6 +318,8 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros}) {
); );
}; };
const executeCmd = (cmd)=>eventBus.fireEvent(QUERY_TOOL_EVENTS.EDITOR_EXEC_CMD, cmd);
useEffect(()=>{ useEffect(()=>{
if(queryToolPref) { if(queryToolPref) {
/* Get the prefs first time */ /* Get the prefs first time */
@ -370,9 +372,21 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros}) {
} }
}, },
{ {
shortcut: queryToolPref.format_sql, shortcut: queryToolPref.indent,
options: { options: {
callback: ()=>{formatSQL();} callback: ()=>{executeCmd('indentMore');}
}
},
{
shortcut: queryToolPref.unindent,
options: {
callback: ()=>{executeCmd('indentLess');}
}
},
{
shortcut: queryToolPref.comment,
options: {
callback: ()=>{executeCmd('toggleComment');}
} }
}, },
{ {
@ -387,6 +401,12 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros}) {
callback: ()=>{clearQuery();} callback: ()=>{clearQuery();}
} }
}, },
{
shortcut: queryToolPref.format_sql,
options: {
callback: ()=>{formatSQL();}
}
},
], containerRef); ], containerRef);
/* Macro shortcuts */ /* Macro shortcuts */
@ -520,14 +540,14 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros}) {
<PgMenuItem shortcut={queryToolPref.replace} <PgMenuItem shortcut={queryToolPref.replace}
onClick={()=>{eventBus.fireEvent(QUERY_TOOL_EVENTS.EDITOR_FIND_REPLACE, true);}}>{gettext('Replace')}</PgMenuItem> onClick={()=>{eventBus.fireEvent(QUERY_TOOL_EVENTS.EDITOR_FIND_REPLACE, true);}}>{gettext('Replace')}</PgMenuItem>
<PgMenuItem shortcut={queryToolPref.gotolinecol} <PgMenuItem shortcut={queryToolPref.gotolinecol}
onClick={()=>{eventBus.fireEvent(QUERY_TOOL_EVENTS.EDITOR_EXEC_CMD, 'gotoLineCol');}}>{gettext('Go to Line/Column')}</PgMenuItem> onClick={()=>{executeCmd('gotoLineCol');}}>{gettext('Go to Line/Column')}</PgMenuItem>
<PgMenuDivider /> <PgMenuDivider />
<PgMenuItem shortcut={queryToolPref.indent} <PgMenuItem shortcut={queryToolPref.indent}
onClick={()=>{eventBus.fireEvent(QUERY_TOOL_EVENTS.EDITOR_EXEC_CMD, 'indentMore');}}>{gettext('Indent Selection')}</PgMenuItem> onClick={()=>{executeCmd('indentMore');}}>{gettext('Indent Selection')}</PgMenuItem>
<PgMenuItem shortcut={queryToolPref.unindent} <PgMenuItem shortcut={queryToolPref.unindent}
onClick={()=>{eventBus.fireEvent(QUERY_TOOL_EVENTS.EDITOR_EXEC_CMD, 'indentLess');}}>{gettext('Unindent Selection')}</PgMenuItem> onClick={()=>{executeCmd('indentLess');}}>{gettext('Unindent Selection')}</PgMenuItem>
<PgMenuItem shortcut={queryToolPref.comment} <PgMenuItem shortcut={queryToolPref.comment}
onClick={()=>{eventBus.fireEvent(QUERY_TOOL_EVENTS.EDITOR_EXEC_CMD, 'toggleComment');}}>{gettext('Toggle Comment')}</PgMenuItem> onClick={()=>{executeCmd('toggleComment');}}>{gettext('Toggle Comment')}</PgMenuItem>
<PgMenuItem shortcut={queryToolPref.toggle_case} <PgMenuItem shortcut={queryToolPref.toggle_case}
onClick={toggleCase}>{gettext('Toggle Case Of Selected Text')}</PgMenuItem> onClick={toggleCase}>{gettext('Toggle Case Of Selected Text')}</PgMenuItem>
<PgMenuItem shortcut={queryToolPref.clear_query} <PgMenuItem shortcut={queryToolPref.clear_query}

View File

@ -39,7 +39,8 @@ async function registerAutocomplete(editor, api, transId) {
}); });
const word = context.matchBefore(/\w*/); const word = context.matchBefore(/\w*/);
const fullSql = context.state.doc.toString(); const fullSql = context.state.doc.toString();
api.post(url, JSON.stringify([fullSql, fullSql])) const sqlTillCur = context.state.sliceDoc(0, context.state.selection.main.head);
api.post(url, JSON.stringify([fullSql, sqlTillCur]))
.then((res) => { .then((res) => {
onAvailable(); onAvailable();
resolve({ resolve({

View File

@ -2383,9 +2383,9 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@codemirror/lang-sql@npm:^6.5.5": "@codemirror/lang-sql@npm:^6.6.2":
version: 6.5.5 version: 6.6.2
resolution: "@codemirror/lang-sql@npm:6.5.5" resolution: "@codemirror/lang-sql@npm:6.6.2"
dependencies: dependencies:
"@codemirror/autocomplete": ^6.0.0 "@codemirror/autocomplete": ^6.0.0
"@codemirror/language": ^6.0.0 "@codemirror/language": ^6.0.0
@ -2393,7 +2393,7 @@ __metadata:
"@lezer/common": ^1.2.0 "@lezer/common": ^1.2.0
"@lezer/highlight": ^1.0.0 "@lezer/highlight": ^1.0.0
"@lezer/lr": ^1.0.0 "@lezer/lr": ^1.0.0
checksum: 404003ae73b986bd7a00f6924db78b7ffb28fdc38d689fdc11416aaafe2d5c6dc37cc18972530f82e940acb61e18ac74a1cf7712beef448c145344ff93970dc3 checksum: 664b20c65a8fa142f76baec7fe3c7c419e12ee89481fef0083917cc8640256af4945a9c82712ae67c6e96a5f2a46007e1dda8b3ce3d38d61d13da0ed116bcae9
languageName: node languageName: node
linkType: hard linkType: hard
@ -14946,7 +14946,7 @@ __metadata:
"@babel/preset-env": ^7.10.2 "@babel/preset-env": ^7.10.2
"@babel/preset-react": ^7.12.13 "@babel/preset-react": ^7.12.13
"@babel/preset-typescript": ^7.22.5 "@babel/preset-typescript": ^7.22.5
"@codemirror/lang-sql": ^6.5.5 "@codemirror/lang-sql": ^6.6.2
"@date-io/core": ^1.3.6 "@date-io/core": ^1.3.6
"@date-io/date-fns": 1.x "@date-io/date-fns": 1.x
"@emotion/core": ^10.0.14 "@emotion/core": ^10.0.14