mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2024-11-25 18:20:20 -06:00
Fix edit menu related issues of query tool codemirror
This commit is contained in:
parent
41812c9fde
commit
b5bd236387
@ -118,7 +118,7 @@ When using the syntax-highlighting SQL editors, the following shortcuts are avai
|
|||||||
+--------------------------+----------------------+-------------------------------------+
|
+--------------------------+----------------------+-------------------------------------+
|
||||||
| Shift + Tab | Shift + Tab | Un-indent selected text |
|
| Shift + Tab | Shift + Tab | Un-indent selected text |
|
||||||
+--------------------------+----------------------+-------------------------------------+
|
+--------------------------+----------------------+-------------------------------------+
|
||||||
| Alt + g | Option + g | Jump (to line:column) |
|
| Ctrl + l | Cmd + l | Go to line, column |
|
||||||
+--------------------------+----------------------+-------------------------------------+
|
+--------------------------+----------------------+-------------------------------------+
|
||||||
| Ctrl + Space | Ctrl + Space | Auto-complete |
|
| Ctrl + Space | Ctrl + Space | Auto-complete |
|
||||||
+--------------------------+----------------------+-------------------------------------+
|
+--------------------------+----------------------+-------------------------------------+
|
||||||
|
@ -87,7 +87,7 @@ Query Editing Options
|
|||||||
| | Select *Replace* to locate and replace (with prompting) individual occurrences of the target. | Option+Cmd+F (MAC) |
|
| | Select *Replace* to locate and replace (with prompting) individual occurrences of the target. | Option+Cmd+F (MAC) |
|
||||||
| | | Ctrl+Shift+F (Others) |
|
| | | Ctrl+Shift+F (Others) |
|
||||||
| +---------------------------------------------------------------------------------------------------+-----------------------+
|
| +---------------------------------------------------------------------------------------------------+-----------------------+
|
||||||
| | Select *Jump* to navigate to the next occurrence of the search target. | Alt+G |
|
| | Select *Go to Line/Column* to go to specified line number and column position | Cmd+L or Ctrl+L |
|
||||||
| +---------------------------------------------------------------------------------------------------+-----------------------+
|
| +---------------------------------------------------------------------------------------------------+-----------------------+
|
||||||
| | Select *Indent Selection* to indent the currently selected text. | Tab |
|
| | Select *Indent Selection* to indent the currently selected text. | Tab |
|
||||||
| +---------------------------------------------------------------------------------------------------+-----------------------+
|
| +---------------------------------------------------------------------------------------------------+-----------------------+
|
||||||
|
@ -3,7 +3,7 @@ import {
|
|||||||
} from '@codemirror/view';
|
} from '@codemirror/view';
|
||||||
import { StateEffect, EditorState } from '@codemirror/state';
|
import { StateEffect, EditorState } from '@codemirror/state';
|
||||||
import { autocompletion } from '@codemirror/autocomplete';
|
import { autocompletion } from '@codemirror/autocomplete';
|
||||||
import {undo} from '@codemirror/commands';
|
import {undo, indentMore, indentLess, toggleComment} from '@codemirror/commands';
|
||||||
import { errorMarkerEffect } from './extensions/errorMarker';
|
import { errorMarkerEffect } from './extensions/errorMarker';
|
||||||
import { activeLineEffect, activeLineField } from './extensions/activeLineMarker';
|
import { activeLineEffect, activeLineField } from './extensions/activeLineMarker';
|
||||||
import { clearBreakpoints, hasBreakpoint, toggleBreakpoint } from './extensions/breakpointGutter';
|
import { clearBreakpoints, hasBreakpoint, toggleBreakpoint } from './extensions/breakpointGutter';
|
||||||
@ -59,8 +59,19 @@ export default class CustomEditorView extends EditorView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setCursor(lineNo, ch) {
|
setCursor(lineNo, ch) {
|
||||||
const n = this.state.doc.line(lineNo).from + ch;
|
// line is 1-based;
|
||||||
this.dispatch({ selection: { anchor: n, head: n } });
|
// ch is 0-based;
|
||||||
|
let pos = 0;
|
||||||
|
if(lineNo > this.state.doc.lines) {
|
||||||
|
pos = this.state.doc.length;
|
||||||
|
} else {
|
||||||
|
const line = this.state.doc.line(lineNo);
|
||||||
|
pos = line.from + ch;
|
||||||
|
if(pos > line.to) {
|
||||||
|
pos = line.to;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.dispatch({ selection: { anchor: pos, head: pos } });
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrentLineNo() {
|
getCurrentLineNo() {
|
||||||
@ -106,14 +117,25 @@ export default class CustomEditorView extends EditorView {
|
|||||||
return !this._cleanDoc.eq(this.state.doc);
|
return !this._cleanDoc.eq(this.state.doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
undo() {
|
|
||||||
return undo(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
fireDOMEvent(event) {
|
fireDOMEvent(event) {
|
||||||
this.contentDOM.dispatchEvent(event);
|
this.contentDOM.dispatchEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
execCommand(cmd) {
|
||||||
|
switch (cmd) {
|
||||||
|
case 'undo': undo(this);
|
||||||
|
break;
|
||||||
|
case 'indentMore': indentMore(this);
|
||||||
|
break;
|
||||||
|
case 'indentLess': indentLess(this);
|
||||||
|
break;
|
||||||
|
case 'toggleComment': toggleComment(this);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
registerAutocomplete(completionFunc) {
|
registerAutocomplete(completionFunc) {
|
||||||
this.dispatch({
|
this.dispatch({
|
||||||
effects: StateEffect.appendConfig.of(
|
effects: StateEffect.appendConfig.of(
|
||||||
|
@ -12,11 +12,11 @@ import ReactDOMServer from 'react-dom/server';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import gettext from 'sources/gettext';
|
import gettext from 'sources/gettext';
|
||||||
import { makeStyles } from '@material-ui/core';
|
import { makeStyles } from '@material-ui/core';
|
||||||
import { PgIconButton } from '../Buttons';
|
import { PgIconButton } from '../../Buttons';
|
||||||
import { checkTrojanSource } from '../../utils';
|
import { checkTrojanSource } from '../../../utils';
|
||||||
import { copyToClipboard } from '../../clipboard';
|
import { copyToClipboard } from '../../../clipboard';
|
||||||
import { useDelayedCaller } from '../../custom_hooks';
|
import { useDelayedCaller } from '../../../custom_hooks';
|
||||||
import usePreferences from '../../../../preferences/static/js/store';
|
import usePreferences from '../../../../../preferences/static/js/store';
|
||||||
import FileCopyRoundedIcon from '@material-ui/icons/FileCopyRounded';
|
import FileCopyRoundedIcon from '@material-ui/icons/FileCopyRounded';
|
||||||
import CheckRoundedIcon from '@material-ui/icons/CheckRounded';
|
import CheckRoundedIcon from '@material-ui/icons/CheckRounded';
|
||||||
import KeyboardArrowRightRoundedIcon from '@material-ui/icons/KeyboardArrowRightRounded';
|
import KeyboardArrowRightRoundedIcon from '@material-ui/icons/KeyboardArrowRightRounded';
|
||||||
@ -35,7 +35,7 @@ import {
|
|||||||
import { EditorState, Compartment } from '@codemirror/state';
|
import { EditorState, Compartment } from '@codemirror/state';
|
||||||
import { history, defaultKeymap, historyKeymap, indentLess, insertTab } from '@codemirror/commands';
|
import { history, defaultKeymap, historyKeymap, indentLess, insertTab } from '@codemirror/commands';
|
||||||
import { highlightSelectionMatches } from '@codemirror/search';
|
import { highlightSelectionMatches } from '@codemirror/search';
|
||||||
import { closeBrackets, autocompletion, closeBracketsKeymap, completionKeymap } from '@codemirror/autocomplete';
|
import { closeBrackets, autocompletion, closeBracketsKeymap, completionKeymap, acceptCompletion } from '@codemirror/autocomplete';
|
||||||
import {
|
import {
|
||||||
foldGutter,
|
foldGutter,
|
||||||
indentOnInput,
|
indentOnInput,
|
||||||
@ -45,13 +45,14 @@ import {
|
|||||||
} from '@codemirror/language';
|
} from '@codemirror/language';
|
||||||
|
|
||||||
import FindDialog from './FindDialog';
|
import FindDialog from './FindDialog';
|
||||||
import syntaxHighlighting from './extensions/highlighting';
|
import syntaxHighlighting from '../extensions/highlighting';
|
||||||
import PgSQL from './extensions/dialect';
|
import PgSQL from '../extensions/dialect';
|
||||||
import { sql } from '@codemirror/lang-sql';
|
import { sql } from '@codemirror/lang-sql';
|
||||||
import errorMarkerExtn from './extensions/errorMarker';
|
import errorMarkerExtn from '../extensions/errorMarker';
|
||||||
import CustomEditorView from './CustomEditorView';
|
import CustomEditorView from '../CustomEditorView';
|
||||||
import breakpointGutter, { breakpointEffect } from './extensions/breakpointGutter';
|
import breakpointGutter, { breakpointEffect } from '../extensions/breakpointGutter';
|
||||||
import activeLineExtn from './extensions/activeLineMarker';
|
import activeLineExtn from '../extensions/activeLineMarker';
|
||||||
|
import GotoDialog from './GotoDialog';
|
||||||
|
|
||||||
const arrowRightHtml = ReactDOMServer.renderToString(<KeyboardArrowRightRoundedIcon style={{fontSize: '1.2em'}} />);
|
const arrowRightHtml = ReactDOMServer.renderToString(<KeyboardArrowRightRoundedIcon style={{fontSize: '1.2em'}} />);
|
||||||
const arrowDownHtml = ReactDOMServer.renderToString(<ExpandMoreRoundedIcon style={{fontSize: '1.2em'}} />);
|
const arrowDownHtml = ReactDOMServer.renderToString(<ExpandMoreRoundedIcon style={{fontSize: '1.2em'}} />);
|
||||||
@ -151,6 +152,9 @@ const defaultExtensions = [
|
|||||||
key: 'Shift-Tab',
|
key: 'Shift-Tab',
|
||||||
preventDefault: true,
|
preventDefault: true,
|
||||||
run: indentLess,
|
run: indentLess,
|
||||||
|
},{
|
||||||
|
key: 'Tab',
|
||||||
|
run: acceptCompletion,
|
||||||
}]),
|
}]),
|
||||||
sql({
|
sql({
|
||||||
dialect: PgSQL,
|
dialect: PgSQL,
|
||||||
@ -170,6 +174,7 @@ export default function Editor({
|
|||||||
breakpoint = false, onBreakPointChange, showActiveLine=false, showCopyBtn = false,
|
breakpoint = false, onBreakPointChange, showActiveLine=false, showCopyBtn = false,
|
||||||
keepHistory = true, cid, helpid, labelledBy}) {
|
keepHistory = true, cid, helpid, labelledBy}) {
|
||||||
const [[showFind, isReplace], setShowFind] = useState([false, false]);
|
const [[showFind, isReplace], setShowFind] = useState([false, false]);
|
||||||
|
const [showGoto, setShowGoto] = useState(false);
|
||||||
const [showCopy, setShowCopy] = useState(false);
|
const [showCopy, setShowCopy] = useState(false);
|
||||||
|
|
||||||
const editorContainerRef = useRef();
|
const editorContainerRef = useRef();
|
||||||
@ -184,7 +189,7 @@ export default function Editor({
|
|||||||
const configurables = useRef(new Compartment());
|
const configurables = useRef(new Compartment());
|
||||||
const editableConfig = useRef(new Compartment());
|
const editableConfig = useRef(new Compartment());
|
||||||
|
|
||||||
const findDialogKeyMap = [{
|
const editMenuKeyMap = [{
|
||||||
key: 'Mod-f', run: (view, e) => {
|
key: 'Mod-f', run: (view, e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@ -198,6 +203,12 @@ export default function Editor({
|
|||||||
setShowFind([false, false]);
|
setShowFind([false, false]);
|
||||||
setShowFind([true, true]);
|
setShowFind([true, true]);
|
||||||
},
|
},
|
||||||
|
}, {
|
||||||
|
key: 'Mod-l', run: (view, e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
setShowGoto(true);
|
||||||
|
},
|
||||||
}];
|
}];
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -226,7 +237,7 @@ export default function Editor({
|
|||||||
extensions: [
|
extensions: [
|
||||||
...finalExtns,
|
...finalExtns,
|
||||||
configurables.current.of([]),
|
configurables.current.of([]),
|
||||||
keymap.of(findDialogKeyMap),
|
keymap.of(editMenuKeyMap),
|
||||||
editableConfig.current.of([
|
editableConfig.current.of([
|
||||||
EditorView.editable.of(!disabled),
|
EditorView.editable.of(!disabled),
|
||||||
EditorState.readOnly.of(readonly),
|
EditorState.readOnly.of(readonly),
|
||||||
@ -397,6 +408,11 @@ export default function Editor({
|
|||||||
editor.current?.focus();
|
editor.current?.focus();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const closeGoto = () => {
|
||||||
|
setShowGoto(false);
|
||||||
|
editor.current?.focus();
|
||||||
|
};
|
||||||
|
|
||||||
const onMouseEnter = useCallback(()=>{showCopyBtn && setShowCopy(true);});
|
const onMouseEnter = useCallback(()=>{showCopyBtn && setShowCopy(true);});
|
||||||
const onMouseLeave = useCallback(()=>{showCopyBtn && setShowCopy(false);});
|
const onMouseLeave = useCallback(()=>{showCopyBtn && setShowCopy(false);});
|
||||||
|
|
||||||
@ -404,9 +420,8 @@ export default function Editor({
|
|||||||
<div onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave} style={{height: '100%'}}>
|
<div onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave} style={{height: '100%'}}>
|
||||||
<div style={{ height: '100%' }} ref={editorContainerRef} name={name}></div>
|
<div style={{ height: '100%' }} ref={editorContainerRef} name={name}></div>
|
||||||
{showCopy && <CopyButton editor={editor.current} />}
|
{showCopy && <CopyButton editor={editor.current} />}
|
||||||
{showFind &&
|
|
||||||
<FindDialog editor={editor.current} show={showFind} replace={isReplace} onClose={closeFind} />
|
<FindDialog editor={editor.current} show={showFind} replace={isReplace} onClose={closeFind} />
|
||||||
}
|
<GotoDialog editor={editor.current} show={showGoto} onClose={closeGoto} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
@ -11,14 +11,14 @@ 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';
|
||||||
import { Box, InputAdornment, makeStyles } from '@material-ui/core';
|
import { Box, InputAdornment, makeStyles } from '@material-ui/core';
|
||||||
import { InputText } from '../FormComponents';
|
import { InputText } from '../../FormComponents';
|
||||||
import { PgIconButton } from '../Buttons';
|
import { PgIconButton } from '../../Buttons';
|
||||||
import CloseIcon from '@material-ui/icons/CloseRounded';
|
import CloseIcon from '@material-ui/icons/CloseRounded';
|
||||||
import ArrowDownwardRoundedIcon from '@material-ui/icons/ArrowDownwardRounded';
|
import ArrowDownwardRoundedIcon from '@material-ui/icons/ArrowDownwardRounded';
|
||||||
import ArrowUpwardRoundedIcon from '@material-ui/icons/ArrowUpwardRounded';
|
import ArrowUpwardRoundedIcon from '@material-ui/icons/ArrowUpwardRounded';
|
||||||
import SwapHorizRoundedIcon from '@material-ui/icons/SwapHorizRounded';
|
import SwapHorizRoundedIcon from '@material-ui/icons/SwapHorizRounded';
|
||||||
import SwapCallsRoundedIcon from '@material-ui/icons/SwapCallsRounded';
|
import SwapCallsRoundedIcon from '@material-ui/icons/SwapCallsRounded';
|
||||||
import { RegexIcon, FormatCaseIcon } from '../ExternalIcon';
|
import { RegexIcon, FormatCaseIcon } from '../../ExternalIcon';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
openSearchPanel,
|
openSearchPanel,
|
||||||
@ -89,8 +89,8 @@ export default function FindDialog({editor, show, replace, onClose}) {
|
|||||||
}, [findVal, replaceVal, useRegex, matchCase]);
|
}, [findVal, replaceVal, useRegex, matchCase]);
|
||||||
|
|
||||||
const clearAndClose = ()=>{
|
const clearAndClose = ()=>{
|
||||||
onClose();
|
|
||||||
closeSearchPanel(editor);
|
closeSearchPanel(editor);
|
||||||
|
onClose();
|
||||||
};
|
};
|
||||||
|
|
||||||
const toggle = (name)=>{
|
const toggle = (name)=>{
|
||||||
@ -147,7 +147,7 @@ export default function FindDialog({editor, show, replace, onClose}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box className={classes.root} visibility={show ? 'visible' : 'hidden'} tabIndex="0" onKeyDown={onEscape}>
|
<Box className={classes.root} style={{visibility: show ? 'visible' : 'hidden'}} tabIndex="0" onKeyDown={onEscape}>
|
||||||
<InputText value={findVal}
|
<InputText value={findVal}
|
||||||
inputRef={(ele)=>{findInputRef.current = ele;}}
|
inputRef={(ele)=>{findInputRef.current = ele;}}
|
||||||
onChange={(value)=>setFindVal(value)}
|
onChange={(value)=>setFindVal(value)}
|
@ -0,0 +1,95 @@
|
|||||||
|
/////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// pgAdmin 4 - PostgreSQL Tools
|
||||||
|
//
|
||||||
|
// Copyright (C) 2013 - 2023, The pgAdmin Development Team
|
||||||
|
// This software is released under the PostgreSQL Licence
|
||||||
|
//
|
||||||
|
//////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import gettext from 'sources/gettext';
|
||||||
|
import { Box, FormControl, makeStyles } from '@material-ui/core';
|
||||||
|
import { InputText } from '../../FormComponents';
|
||||||
|
import { PgIconButton } from '../../Buttons';
|
||||||
|
import CloseIcon from '@material-ui/icons/CloseRounded';
|
||||||
|
|
||||||
|
const useStyles = makeStyles((theme)=>({
|
||||||
|
root: {
|
||||||
|
position: 'absolute',
|
||||||
|
zIndex: 99,
|
||||||
|
right: '4px',
|
||||||
|
top: '0px',
|
||||||
|
...theme.mixins.panelBorder.all,
|
||||||
|
borderTop: 'none',
|
||||||
|
padding: '2px 4px',
|
||||||
|
width: '250px',
|
||||||
|
backgroundColor: theme.palette.background.default,
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: '4px',
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
export default function GotoDialog({editor, show, onClose}) {
|
||||||
|
const [gotoVal, setGotoVal] = useState('');
|
||||||
|
const inputRef = useRef();
|
||||||
|
const classes = useStyles();
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
if(show) {
|
||||||
|
setGotoVal('');
|
||||||
|
inputRef.current?.focus();
|
||||||
|
}
|
||||||
|
}, [show]);
|
||||||
|
|
||||||
|
const onKeyPress = (e) => {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
e.preventDefault();
|
||||||
|
if(!/^[ ]*[1-9][0-9]*[ ]*(,[ ]*[1-9][0-9]*[ ]*){0,1}$/.test(gotoVal)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const v = gotoVal.split(',').map(Number);
|
||||||
|
if(v.length == 1) {
|
||||||
|
v.push(1);
|
||||||
|
}
|
||||||
|
editor.setCursor(v[0], v[1]-1);
|
||||||
|
onClose();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onEscape = (e)=>{
|
||||||
|
if (e.key === 'Escape') {
|
||||||
|
e.preventDefault();
|
||||||
|
onClose();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if(!editor) {
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box className={classes.root} style={{visibility: show ? 'visible' : 'hidden'}} tabIndex="0" onKeyDown={onEscape}>
|
||||||
|
<div style={{whiteSpace: 'nowrap'}}>Ln [,Col]</div>
|
||||||
|
<FormControl>
|
||||||
|
<InputText
|
||||||
|
value={gotoVal}
|
||||||
|
inputRef={(ele)=>{inputRef.current = ele;}}
|
||||||
|
onChange={(value)=>setGotoVal(value)}
|
||||||
|
onKeyPress={onKeyPress}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<PgIconButton title={gettext('Close')} icon={<CloseIcon />} size="xs" noBorder onClick={onClose}/>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
GotoDialog.propTypes = {
|
||||||
|
editor: PropTypes.object,
|
||||||
|
show: PropTypes.bool,
|
||||||
|
replace: PropTypes.bool,
|
||||||
|
onClose: PropTypes.func,
|
||||||
|
selFindVal: PropTypes.string,
|
||||||
|
};
|
@ -10,7 +10,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { makeStyles } from '@material-ui/core';
|
import { makeStyles } from '@material-ui/core';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import Editor from './Editor';
|
import Editor from './components/Editor';
|
||||||
import CustomPropTypes from '../../custom_prop_types';
|
import CustomPropTypes from '../../custom_prop_types';
|
||||||
|
|
||||||
const useStyles = makeStyles(() => ({
|
const useStyles = makeStyles(() => ({
|
||||||
|
@ -70,13 +70,14 @@ const FIXED_PREF = {
|
|||||||
'char': 'F',
|
'char': 'F',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
jump: {
|
gotolinecol: {
|
||||||
'control': false,
|
'control': true,
|
||||||
|
ctrl_is_meta: true,
|
||||||
'shift': false,
|
'shift': false,
|
||||||
'alt': true,
|
'alt': false,
|
||||||
'key': {
|
'key': {
|
||||||
'key_code': 71,
|
'key_code': 76,
|
||||||
'char': 'G',
|
'char': 'L',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
indent: {
|
indent: {
|
||||||
@ -599,8 +600,8 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros}) {
|
|||||||
onClick={()=>{eventBus.fireEvent(QUERY_TOOL_EVENTS.EDITOR_FIND_REPLACE, false);}}>{gettext('Find')}</PgMenuItem>
|
onClick={()=>{eventBus.fireEvent(QUERY_TOOL_EVENTS.EDITOR_FIND_REPLACE, false);}}>{gettext('Find')}</PgMenuItem>
|
||||||
<PgMenuItem shortcut={FIXED_PREF.replace}
|
<PgMenuItem shortcut={FIXED_PREF.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={FIXED_PREF.jump}
|
<PgMenuItem shortcut={FIXED_PREF.gotolinecol}
|
||||||
onClick={()=>{eventBus.fireEvent(QUERY_TOOL_EVENTS.EDITOR_EXEC_CMD, 'jumpToLine');}}>{gettext('Jump')}</PgMenuItem>
|
onClick={()=>{eventBus.fireEvent(QUERY_TOOL_EVENTS.EDITOR_EXEC_CMD, 'gotoLineCol');}}>{gettext('Go to Line/Column')}</PgMenuItem>
|
||||||
<PgMenuDivider />
|
<PgMenuDivider />
|
||||||
<PgMenuItem shortcut={FIXED_PREF.indent}
|
<PgMenuItem shortcut={FIXED_PREF.indent}
|
||||||
onClick={()=>{eventBus.fireEvent(QUERY_TOOL_EVENTS.EDITOR_EXEC_CMD, 'indentMore');}}>{gettext('Indent Selection')}</PgMenuItem>
|
onClick={()=>{eventBus.fireEvent(QUERY_TOOL_EVENTS.EDITOR_EXEC_CMD, 'indentMore');}}>{gettext('Indent Selection')}</PgMenuItem>
|
||||||
|
@ -211,7 +211,21 @@ export default function Query() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
eventBus.registerListener(QUERY_TOOL_EVENTS.EDITOR_EXEC_CMD, (cmd='')=>{
|
eventBus.registerListener(QUERY_TOOL_EVENTS.EDITOR_EXEC_CMD, (cmd='')=>{
|
||||||
|
if(cmd == 'gotoLineCol') {
|
||||||
|
editor.current?.focus();
|
||||||
|
let key = {
|
||||||
|
keyCode: 76, metaKey: false, ctrlKey: true, shiftKey: false, altKey: false,
|
||||||
|
};
|
||||||
|
if(isMac()) {
|
||||||
|
key.metaKey = true;
|
||||||
|
key.ctrlKey = false;
|
||||||
|
key.shiftKey = false;
|
||||||
|
key.altKey = false;
|
||||||
|
}
|
||||||
|
editor.current?.fireDOMEvent(new KeyboardEvent('keydown', key));
|
||||||
|
} else {
|
||||||
editor.current?.execCommand(cmd);
|
editor.current?.execCommand(cmd);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
eventBus.registerListener(QUERY_TOOL_EVENTS.COPY_TO_EDITOR, (text)=>{
|
eventBus.registerListener(QUERY_TOOL_EVENTS.COPY_TO_EDITOR, (text)=>{
|
||||||
editor.current?.setValue(text);
|
editor.current?.setValue(text);
|
||||||
@ -327,9 +341,7 @@ export default function Query() {
|
|||||||
}, [queryToolCtx.preferences]);
|
}, [queryToolCtx.preferences]);
|
||||||
|
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
registerAutocomplete(editor.current, queryToolCtx.api, queryToolCtx.params.trans_id, queryToolCtx.preferences.sqleditor,
|
registerAutocomplete(editor.current, queryToolCtx.api, queryToolCtx.params.trans_id);
|
||||||
(err)=>{eventBus.fireEvent(QUERY_TOOL_EVENTS.HANDLE_API_ERROR, err);}
|
|
||||||
);
|
|
||||||
}, [queryToolCtx.params.trans_id]);
|
}, [queryToolCtx.params.trans_id]);
|
||||||
|
|
||||||
const cursorActivity = useCallback(_.debounce((cursor)=>{
|
const cursorActivity = useCallback(_.debounce((cursor)=>{
|
||||||
@ -351,7 +363,7 @@ export default function Query() {
|
|||||||
|
|
||||||
const closePromotionWarning = (closeModal)=>{
|
const closePromotionWarning = (closeModal)=>{
|
||||||
if(editor.current.isDirty()) {
|
if(editor.current.isDirty()) {
|
||||||
editor.current.undo();
|
editor.current.execCommand('undo');
|
||||||
closeModal?.();
|
closeModal?.();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -400,6 +412,5 @@ export default function Query() {
|
|||||||
onCursorActivity={cursorActivity}
|
onCursorActivity={cursorActivity}
|
||||||
onChange={change}
|
onChange={change}
|
||||||
autocomplete={true}
|
autocomplete={true}
|
||||||
keepHistory={queryToolCtx.params.is_query_tool}
|
|
||||||
/>;
|
/>;
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ import { withTheme } from '../fake_theme';
|
|||||||
|
|
||||||
import pgWindow from 'sources/window';
|
import pgWindow from 'sources/window';
|
||||||
import CodeMirror from 'sources/components/ReactCodeMirror';
|
import CodeMirror from 'sources/components/ReactCodeMirror';
|
||||||
import FindDialog from 'sources/components/ReactCodeMirror/FindDialog';
|
import FindDialog from 'sources/components/ReactCodeMirror/components/FindDialog';
|
||||||
import CustomEditorView from 'sources/components/ReactCodeMirror/CustomEditorView';
|
import CustomEditorView from 'sources/components/ReactCodeMirror/CustomEditorView';
|
||||||
import fakePgAdmin from '../fake_pgadmin';
|
import fakePgAdmin from '../fake_pgadmin';
|
||||||
import { render, screen, fireEvent } from '@testing-library/react';
|
import { render, screen, fireEvent } from '@testing-library/react';
|
||||||
|
Loading…
Reference in New Issue
Block a user