Changes in Query Tool, Debugger, and ERD Tool shortcuts to remove the use of Accesskey which will allow them to be customized. #7192

pull/7451/head
Aditya Toshniwal 2024-05-06 11:15:44 +05:30 committed by GitHub
parent 0ac006fde1
commit b85d8c1446
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
23 changed files with 482 additions and 269 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 179 KiB

After

Width:  |  Height:  |  Size: 191 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

After

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 169 KiB

View File

@ -140,55 +140,55 @@ When using the Query Tool, the following shortcuts are available:
:class: longtable
:widths: 2 2 3
+--------------------------+--------------------+-----------------------------------+
| Shortcut (Windows/Linux) | Shortcut (Mac) | Function |
+==========================+====================+===================================+
| <accesskey> + q | <accesskey> + q | Cancel query |
+--------------------------+--------------------+-----------------------------------+
| <accesskey> + t | <accesskey> + t | Connection status |
+--------------------------+--------------------+-----------------------------------+
| <accesskey> + d | <accesskey> + d | Delete rows |
+--------------------------+--------------------+-----------------------------------+
| <accesskey> + x | <accesskey> + x | Execute options |
+--------------------------+--------------------+-----------------------------------+
| <accesskey> + f | <accesskey> + f | Filter dialog |
+--------------------------+--------------------+-----------------------------------+
| <accesskey> + i | <accesskey> + i | Filter options |
+--------------------------+--------------------+-----------------------------------+
| <accesskey> + n | <accesskey> + n | Find options |
+--------------------------+--------------------+-----------------------------------+
| <accesskey> + o | <accesskey> + o | Open file |
+--------------------------+--------------------+-----------------------------------+
| <accesskey> + p | <accesskey> + p | Paste rows |
+--------------------------+--------------------+-----------------------------------+
| <accesskey> + r | <accesskey> + r | Rows limit |
+--------------------------+--------------------+-----------------------------------+
| <accesskey> + s | <accesskey> + s | Save file |
+--------------------------+--------------------+-----------------------------------+
| Ctrl + Alt + L | Ctrl + option + L | Clear query |
+--------------------------+--------------------+-----------------------------------+
| Shift + Ctrl + m | Shift + Ctrl + m | Commit |
+--------------------------+--------------------+-----------------------------------+
| F8 | F8 | Download Results |
+--------------------------+--------------------+-----------------------------------+
| Shift + F7 | Shift + F7 | EXPLAIN ANALYZE query |
+--------------------------+--------------------+-----------------------------------+
| F7 | F7 | EXPLAIN query |
+--------------------------+--------------------+-----------------------------------+
| F5 | F5 | Execute query |
+--------------------------+--------------------+-----------------------------------+
| Shift + Alt + ] | Shift + option + ] | Next tab |
+--------------------------+--------------------+-----------------------------------+
| Shift + Alt + [ | Shift + option + [ | Previous tab |
+--------------------------+--------------------+-----------------------------------+
| Shift + Ctrl + r | Shift + Ctrl + r | Rollback |
+--------------------------+--------------------+-----------------------------------+
| F6 | F6 | Save data changes |
+--------------------------+--------------------+-----------------------------------+
| Shift + Alt + Tab | Shift + option +Tab| Switch Panel |
+--------------------------+--------------------+-----------------------------------+
| Shift + Ctrl + u | Shift + Ctrl + u | Toggle case of selected text |
+--------------------------+--------------------+-----------------------------------+
+--------------------------+-----------------------+-----------------------------------+
| Shortcut (Windows/Linux) | Shortcut (Mac) | Function |
+==========================+=======================+===================================+
| Alt + Shift + o | Option + Shift + o | Open file |
+--------------------------+-----------------------+-----------------------------------+
| Alt + Shift + s | Option + Shift + s | Save file |
+--------------------------+-----------------------+-----------------------------------+
| Alt + Shift + n | Option + Shift + n | Edit options |
+--------------------------+-----------------------+-----------------------------------+
| Alt + Shift + f | Option + Shift + f | Sort/Filter |
+--------------------------+-----------------------+-----------------------------------+
| Alt + Shift + i | Option + Shift + i | Filter options |
+--------------------------+-----------------------+-----------------------------------+
| Alt + Shift + q | Option + Shift + q | Cancel query |
+--------------------------+-----------------------+-----------------------------------+
| F5 | F5 | Execute Script |
+--------------------------+-----------------------+-----------------------------------+
| Alt + Shift + x | Option + Shift + x | Execute options |
+--------------------------+-----------------------+-----------------------------------+
| F7 | F7 | EXPLAIN query |
+--------------------------+-----------------------+-----------------------------------+
| Shift + F7 | Shift + F7 | EXPLAIN ANALYZE query |
+--------------------------+-----------------------+-----------------------------------+
| Shift + Ctrl + m | Shift + Ctrl + m | Commit |
+--------------------------+-----------------------+-----------------------------------+
| Shift + Ctrl + r | Shift + Ctrl + r | Rollback |
+--------------------------+-----------------------+-----------------------------------+
| Alt + Ctrl + a | Option + Ctrl + a | Add row |
+--------------------------+-----------------------+-----------------------------------+
| Ctrl + c | Cmd + c | Copy rows |
+--------------------------+-----------------------+-----------------------------------+
| Alt + Shift + p | Option + Shift + p | Paste rows |
+--------------------------+-----------------------+-----------------------------------+
| Alt + Shift + d | Option + Shift + d | Delete rows |
+--------------------------+-----------------------+-----------------------------------+
| F6 | F6 | Save data changes |
+--------------------------+-----------------------+-----------------------------------+
| Ctrl + Alt + L | Ctrl + option + L | Clear query |
+--------------------------+-----------------------+-----------------------------------+
| F8 | F8 | Download Results |
+--------------------------+-----------------------+-----------------------------------+
| Shift + Alt + ] | Shift + option + ] | Next tab |
+--------------------------+-----------------------+-----------------------------------+
| Shift + Alt + [ | Shift + option + [ | Previous tab |
+--------------------------+-----------------------+-----------------------------------+
| Shift + Alt + Tab | Shift + option +Tab | Switch Panel |
+--------------------------+-----------------------+-----------------------------------+
| Shift + Ctrl + u | Shift + Ctrl + u | Toggle case of selected text |
+--------------------------+-----------------------+-----------------------------------+
Debugger
********
@ -199,29 +199,29 @@ When using the Debugger, the following shortcuts are available:
:class: longtable
:widths: 2 2 3
+--------------------------+--------------------+-----------------------------------+
| Shortcut (Windows/Linux) | Shortcut (Mac) | Function |
+==========================+====================+===================================+
| <accesskey> + x | <accesskey> + x | Clear all breakpoints |
+--------------------------+--------------------+-----------------------------------+
| <accesskey> + c | <accesskey> + c | Continue/Start |
+--------------------------+--------------------+-----------------------------------+
| <accesskey> + i | <accesskey> + i | Step into |
+--------------------------+--------------------+-----------------------------------+
| <accesskey> + o | <accesskey> + o | Step over |
+--------------------------+--------------------+-----------------------------------+
| <accesskey> + s | <accesskey> + s | Stop |
+--------------------------+--------------------+-----------------------------------+
| <accesskey> + t | <accesskey> + t | Toggle breakpoint |
+--------------------------+--------------------+-----------------------------------+
| Shift + Alt + q | Shift + option + q | Edit grid values |
+--------------------------+--------------------+-----------------------------------+
| Shift + Alt + ] | Shift + option + ] | Next tab |
+--------------------------+--------------------+-----------------------------------+
| Shift + Alt + [ | Shift + option + ] | Previous tab |
+--------------------------+--------------------+-----------------------------------+
| Shift + Alt + Tab | Shift + option +Tab| Switch Panel |
+--------------------------+--------------------+-----------------------------------+
+--------------------------+-----------------------+-----------------------------------+
| Shortcut (Windows/Linux) | Shortcut (Mac) | Function |
+==========================+=======================+===================================+
| Alt + Shift + x | Option + Shift + x | Clear all breakpoints |
+--------------------------+-----------------------+-----------------------------------+
| Alt + Shift + c | Option + Shift + c | Continue/Start |
+--------------------------+-----------------------+-----------------------------------+
| Alt + Shift + i | Option + Shift + i | Step into |
+--------------------------+-----------------------+-----------------------------------+
| Alt + Shift + o | Option + Shift + o | Step over |
+--------------------------+-----------------------+-----------------------------------+
| Alt + Shift + s | Option + Shift + s | Stop |
+--------------------------+-----------------------+-----------------------------------+
| Alt + Shift + t | Option + Shift + t | Toggle breakpoint |
+--------------------------+-----------------------+-----------------------------------+
| Alt + Shift + q | Option + Shift + q | Edit grid values |
+--------------------------+-----------------------+-----------------------------------+
| Alt + Shift + ] | Option + Shift + ] | Next tab |
+--------------------------+-----------------------+-----------------------------------+
| Alt + Shift + [ | Option + Shift + ] | Previous tab |
+--------------------------+-----------------------+-----------------------------------+
| Alt + Shift + Tab | Option + Shift + Tab | Switch Panel |
+--------------------------+-----------------------+-----------------------------------+
ERD Tool
********

View File

@ -25,7 +25,6 @@ import pgAdmin from 'sources/pgadmin';
import { DefaultButton, PgIconButton, PrimaryButton } from '../../../../static/js/components/Buttons';
import BaseUISchema from 'sources/SchemaView/base_schema.ui';
import { getBinaryPathSchema } from '../../../../browser/server_groups/servers/static/js/binary_path.ui';
import { getBrowserAccesskey } from '../../../../static/js/components/ShortcutTitle';
import usePreferences from '../store';
class PreferencesSchema extends BaseUISchema {
@ -340,8 +339,6 @@ export default function PreferencesComponent({ ...props }) {
// Check and add the note for the element.
if (subNode.label == gettext('Nodes') && node.label == gettext('Browser')) {
note = [gettext('This settings is to Show/Hide nodes in the object explorer.')].join('');
} if(nodeData.name == 'keyboard_shortcuts') {
note = gettext('The Accesskey here is %s.', getBrowserAccesskey().join(' + '));
} else {
note = [note].join('');
}

View File

@ -573,6 +573,12 @@ function getFinalTheme(baseTheme) {
'&:not(:first-of-type)': {
borderLeft: 'abc'
}
},
middleButton: {
borderLeftColor: baseTheme.otherVars.borderColor,
},
lastButton: {
borderLeftColor: baseTheme.otherVars.borderColor,
}
}
},
@ -631,24 +637,22 @@ function getFinalTheme(baseTheme) {
MuiToggleButton: {
styleOverrides: {
root: {
paddingTop: '2px',
paddingBottom: '2px',
paddingRight: baseTheme.spacing(2.5),
paddingLeft: baseTheme.spacing(0.5),
padding: '3px 16px 3px 4px',
color: 'abc',
textTransform: 'initial',
'&:hover':{
backgroundColor: 'abc',
},
'&.Mui-selected': {
color: [baseTheme.palette.primary.contrastText,'!important'],
backgroundColor: baseTheme.palette.primary.main,
color: baseTheme.palette.primary.main,
backgroundColor: baseTheme.palette.primary.light,
borderColor: baseTheme.palette.primary.main,
zIndex: 1,
'&:hover':{
//backgroundColor: 'abc',
backgroundColor: baseTheme.palette.primary.hoverMain,
borderColor: baseTheme.palette.primary.hoverBorderColor,
backgroundColor: baseTheme.palette.primary.hoverLight,
}
}
},
backgroundClip: 'padding-box',
},
}
},

View File

@ -29,6 +29,7 @@ export default function(basicSettings) {
contrastText: '#fff',
hoverMain: darken('#326690', 0.25),
hoverBorderColor: darken('#326690', 0.25),
hoverLight: darken('#d6effc', 0.05),
disabledMain: '#326690',
},
success: {

View File

@ -642,6 +642,22 @@ InputRadio.propTypes = {
labelPlacement: PropTypes.string
};
export const ToggleCheckButton = forwardRef(({ value, selected, label, ...props }, ref) => {
return (
<ToggleButton ref={ref} value={value} component={selected ? PrimaryButton : DefaultButton}
aria-label={label} {...props}>
<CheckRoundedIcon style={{ visibility: selected ? 'visible' : 'hidden', fontSize: '1.2rem' }} />&nbsp;{label}
</ToggleButton>
);
});
ToggleCheckButton.displayName = 'ToggleCheckButton';
ToggleCheckButton.propTypes = {
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.bool]),
selected: PropTypes.bool,
options: PropTypes.array,
label: PropTypes.string,
};
export const InputToggle = forwardRef(({ cid, value, onChange, options, disabled, readonly, helpid, ...props }, ref) => {
return (
<>
@ -655,12 +671,10 @@ export const InputToggle = forwardRef(({ cid, value, onChange, options, disabled
(options || []).map((option, i) => {
const isSelected = option.value === value;
const isDisabled = disabled || option.disabled || (readonly && !isSelected);
return (
<ToggleButton ref={i == 0 ? ref : null} key={option.label} value={option.value} component={isSelected ? PrimaryButton : DefaultButton}
disabled={isDisabled} aria-label={option.label}>
<CheckRoundedIcon style={{ visibility: isSelected ? 'visible' : 'hidden' }} />&nbsp;{option.label}
</ToggleButton>
);
return <ToggleCheckButton ref={i == 0 ? ref : null} key={option.label} label={option.label}
selected={isSelected} value={option.value} disabled={isDisabled}
/>;
})
}
</ToggleButtonGroup>

View File

@ -7,38 +7,19 @@
//
//////////////////////////////////////////////////////////////
import _ from 'lodash';
import { Grid, Typography, Box } from '@mui/material';
import { makeStyles } from '@mui/styles';
import React from 'react';
import { InputCheckbox, InputText } from './FormComponents';
import { Box, ToggleButtonGroup } from '@mui/material';
import React, { useMemo } from 'react';
import { InputText, ToggleCheckButton } from './FormComponents';
import PropTypes from 'prop-types';
import { isMac } from '../keyboard_shortcuts';
import gettext from 'sources/gettext';
const useStyles = makeStyles((theme) => ({
inputLabel: {
textAlign: 'center',
padding: 2,
paddingLeft: 10
},
inputCheckboxClass: {
border: '1px solid',
borderRadius: theme.shape.borderRadius,
borderColor: theme.otherVars.inputBorderColor,
padding: 3
}
}));
export default function KeyboardShortcuts({ value, onChange, fields }) {
const classes = useStyles();
const keyCid = _.uniqueId('c');
export default function KeyboardShortcuts({ value, onChange, fields, name }) {
const keyCid = `key-${name}`;
const keyhelpid = `h${keyCid}`;
const shiftCid = _.uniqueId('c');
const shifthelpid = `h${shiftCid}`;
const ctrlCid = _.uniqueId('c');
const ctrlhelpid = `h${ctrlCid}`;
const altCid = _.uniqueId('c');
const althelpid = `h${altCid}`;
const keyLabel = _.uniqueId('c');
const hasKeys = useMemo(()=>{
return fields?.some((f)=>['shift', 'control', 'alt'].includes(f.name));
}, [fields]);
const onKeyDown = (e) => {
let newVal = { ...value };
@ -53,81 +34,82 @@ export default function KeyboardShortcuts({ value, onChange, fields }) {
onChange(newVal);
};
const onShiftChange = (e) => {
let newVal = { ...value };
newVal.shift = e.target.checked;
onChange(newVal);
const onChangeButton = (k, v)=>{
onChange({
...value,
[k]: v,
});
};
const onCtrlChange = (e) => {
let newVal = { ...value };
newVal.control = e.target.checked;
onChange(newVal);
const onChangeCtrl = (_e, val)=>{
if(val == null) {
onChange({
...value,
ctrl_is_meta: false,
control: false,
});
} else if(val == 'ctrl_is_meta') {
onChange({
...value,
[val]: true,
control: true,
});
} else if(val == 'control') {
onChange({
...value,
[val]: true,
ctrl_is_meta: false,
});
} else {
onChange({
...value,
[val]: true,
});
}
};
const onAltChange = (e) => {
let newVal = { ...value };
newVal.alt = e.target.checked;
onChange(newVal);
};
let ctrlValue = value?.control ? 'control' : '';
if(ctrlValue && value?.ctrl_is_meta && isMac()) {
ctrlValue = 'ctrl_is_meta';
}
return (
<Grid
container
direction="row"
<Box
display="flex"
alignItems="center"
key={_.uniqueId('c')}
flexWrap="wrap"
gap="5px"
rowGap="5px"
>
{fields.map(element => {
let ctrlProps = {
label: element.label
};
if (element.type == 'keyCode') {
return <Grid item container lg={4} md={4} sm={4} xs={12} key={_.uniqueId('c')}>
<Grid item lg={4} md={4} sm={4} xs={12} className={classes.inputLabel}>
<Typography id={keyLabel}>{element.label}</Typography>
</Grid>
<Grid item lg={8} md={8} sm={8} xs={12}>
<InputText id={keyCid} helpid={keyhelpid} value={value?.key?.char} controlProps={
{
onKeyDown: onKeyDown,
}
}/>
</Grid>
</Grid>;
} else if (element.name == 'shift') {
return <Grid item lg={2} md={2} sm={2} xs={12} className={classes.inputLabel} key={_.uniqueId('c')}>
<Box className={classes.inputCheckboxClass}>
<InputCheckbox id={shiftCid} helpid={shifthelpid} value={value?.shift}
controlProps={ctrlProps}
onChange={onShiftChange}></InputCheckbox>
</Box>
</Grid>;
} else if (element.name == 'control') {
return <Grid item lg={2} md={2} sm={2} xs={12} className={classes.inputLabel} key={_.uniqueId('c')}>
<Box className={classes.inputCheckboxClass}>
<InputCheckbox id={ctrlCid} helpid={ctrlhelpid} value={value?.control}
controlProps={ctrlProps}
onChange={onCtrlChange}></InputCheckbox>
</Box>
</Grid>;
} else if (element.name == 'alt') {
return <Grid item lg={3} md={3} sm={3} xs={12} className={classes.inputLabel} key={_.uniqueId('c')}>
<Box className={classes.inputCheckboxClass}>
<InputCheckbox id={altCid} helpid={althelpid} value={value?.alt}
controlProps={ctrlProps}
onChange={onAltChange}></InputCheckbox>
</Box>
</Grid>;
{hasKeys &&
<>
<ToggleButtonGroup value={value?.shift ? ['shift'] : []} onChange={(e, val)=>{
onChangeButton('shift', val.length == 0 ? false : true);
}}>
<ToggleCheckButton value="shift" label={gettext('Shift')} selected={value?.shift} />
</ToggleButtonGroup>
<ToggleButtonGroup exclusive value={ctrlValue} onChange={onChangeCtrl}>
<ToggleCheckButton value="control" label={gettext('Ctrl')} selected={ctrlValue == 'control'} />
{isMac() && <ToggleCheckButton value="ctrl_is_meta" label={gettext('Cmd')} selected={ctrlValue == 'ctrl_is_meta'} />}
</ToggleButtonGroup>
<ToggleButtonGroup value={value?.alt ? ['alt'] : []} onChange={(e, val)=>{
onChangeButton('alt', val.length == 0 ? false : true);
}}>
<ToggleCheckButton value="alt" label={isMac() ? gettext('Option') : gettext('Alt')} selected={value?.alt} />
</ToggleButtonGroup>
</>}
<InputText style={{maxWidth: '100px'}} id={keyCid} helpid={keyhelpid} value={value?.key?.char} controlProps={
{
onKeyDown: onKeyDown,
}
})}
</Grid>
}/>
</Box>
);
}
KeyboardShortcuts.propTypes = {
value: PropTypes.object,
onChange: PropTypes.func,
fields: PropTypes.array
fields: PropTypes.array,
name: PropTypes.string,
};

View File

@ -20,8 +20,7 @@ from pgadmin.user_login_check import pga_login_required
from werkzeug.user_agent import UserAgent
from pgadmin.utils import PgAdminModule, \
SHORTCUT_FIELDS as shortcut_fields, \
ACCESSKEY_FIELDS as accesskey_fields
SHORTCUT_FIELDS as shortcut_fields
from pgadmin.utils.ajax import bad_request
from pgadmin.utils.ajax import make_json_response, \
internal_server_error, gone
@ -58,80 +57,98 @@ class DebuggerModule(PgAdminModule):
def register_preferences(self):
self.preference.register(
'keyboard_shortcuts', 'btn_start',
gettext('Accesskey (Continue/Start)'), 'keyboardshortcut',
gettext('Continue/Start'), 'keyboardshortcut',
{
'alt': True,
'shift': True,
'control': False,
'key': {
'key_code': 67,
'char': 'c'
}
},
category_label=PREF_LABEL_KEYBOARD_SHORTCUTS,
fields=accesskey_fields
fields=shortcut_fields
)
self.preference.register(
'keyboard_shortcuts', 'btn_stop',
gettext('Accesskey (Stop)'), 'keyboardshortcut',
gettext('Stop'), 'keyboardshortcut',
{
'alt': True,
'shift': True,
'control': False,
'key': {
'key_code': 83,
'char': 's'
}
},
category_label=PREF_LABEL_KEYBOARD_SHORTCUTS,
fields=accesskey_fields
fields=shortcut_fields
)
self.preference.register(
'keyboard_shortcuts', 'btn_step_into',
gettext('Accesskey (Step into)'), 'keyboardshortcut',
gettext('Step into'), 'keyboardshortcut',
{
'alt': True,
'shift': True,
'control': False,
'key': {
'key_code': 73,
'char': 'i'
}
},
category_label=PREF_LABEL_KEYBOARD_SHORTCUTS,
fields=accesskey_fields
fields=shortcut_fields
)
self.preference.register(
'keyboard_shortcuts', 'btn_step_over',
gettext('Accesskey (Step over)'), 'keyboardshortcut',
gettext('Step over'), 'keyboardshortcut',
{
'alt': True,
'shift': True,
'control': False,
'key': {
'key_code': 79,
'char': 'o'
}
},
category_label=PREF_LABEL_KEYBOARD_SHORTCUTS,
fields=accesskey_fields
fields=shortcut_fields
)
self.preference.register(
'keyboard_shortcuts', 'btn_toggle_breakpoint',
gettext('Accesskey (Toggle breakpoint)'), 'keyboardshortcut',
gettext('Toggle breakpoint'), 'keyboardshortcut',
{
'alt': True,
'shift': True,
'control': False,
'key': {
'key_code': 84,
'char': 't'
}
},
category_label=PREF_LABEL_KEYBOARD_SHORTCUTS,
fields=accesskey_fields
fields=shortcut_fields
)
self.preference.register(
'keyboard_shortcuts', 'btn_clear_breakpoints',
gettext('Accesskey (Clear all breakpoints)'), 'keyboardshortcut',
gettext('Clear all breakpoints'), 'keyboardshortcut',
{
'alt': True,
'shift': True,
'control': False,
'key': {
'key_code': 88,
'char': 'x'
}
},
category_label=PREF_LABEL_KEYBOARD_SHORTCUTS,
fields=accesskey_fields
fields=shortcut_fields
)
self.preference.register(

View File

@ -1083,6 +1083,7 @@ export default function DebuggerComponent({ pgAdmin, selectedNodeInfo, panelId,
node_name: retrieveNodeName(selectedNodeInfo),
},
preferences: preferences,
containerRef: containerRef,
}), [preferences]);
// Define the debugger layout components such as DebuggerEditor to show queries and

View File

@ -10,7 +10,7 @@
import { makeStyles } from '@mui/styles';
import PropTypes from 'prop-types';
import React, { useContext, useEffect } from 'react';
import React, { useContext, useEffect, useMemo } from 'react';
import gettext from 'sources/gettext';
import url_for from 'sources/url_for';
@ -18,8 +18,9 @@ import url_for from 'sources/url_for';
import getApiInstance from '../../../../../static/js/api_instance';
import CodeMirror from '../../../../../static/js/components/ReactCodeMirror';
import { DEBUGGER_EVENTS } from '../DebuggerConstants';
import { DebuggerEventsContext } from './DebuggerComponent';
import { DebuggerContext, DebuggerEventsContext } from './DebuggerComponent';
import { usePgAdmin } from '../../../../../static/js/BrowserComponent';
import { isShortcutValue, toCodeMirrorKey } from '../../../../../static/js/utils';
const useStyles = makeStyles(() => ({
@ -33,6 +34,8 @@ export default function DebuggerEditor({ getEditor, params }) {
const editor = React.useRef();
const eventBus = useContext(DebuggerEventsContext);
const pgAdmin = usePgAdmin();
const debuggerCtx = useContext(DebuggerContext);
let preferences = debuggerCtx.preferences.debugger;
const api = getApiInstance();
@ -70,6 +73,29 @@ export default function DebuggerEditor({ getEditor, params }) {
getEditor(editor.current);
}, [editor.current]);
const shortcutOverrideKeys = useMemo(
()=>{
return Object.values(preferences)
.filter((p)=>isShortcutValue(p))
.map((p)=>({
key: toCodeMirrorKey(p), run: (_v, e)=>{
debuggerCtx.containerRef?.current?.dispatchEvent(new KeyboardEvent('keydown', {
which: e.which,
keyCode: e.keyCode,
altKey: e.altKey,
shiftKey: e.shiftKey,
ctrlKey: e.ctrlKey,
metaKey: e.metaKey,
}));
return true;
},
preventDefault: true,
stopPropagation: true,
}));
},
[preferences]
);
return (
<CodeMirror
currEditor={(obj) => {
@ -81,6 +107,7 @@ export default function DebuggerEditor({ getEditor, params }) {
}}
className={classes.sql}
readonly={true}
customKeyMap={shortcutOverrideKeys}
breakpoint
/>);
}

View File

@ -21,12 +21,12 @@ import HelpIcon from '@mui/icons-material/HelpRounded';
import RotateLeftRoundedIcon from '@mui/icons-material/RotateLeftRounded';
import gettext from 'sources/gettext';
import { shortcut_key } from 'sources/keyboard_shortcuts';
import url_for from 'sources/url_for';
import { PgButtonGroup, PgIconButton } from '../../../../../static/js/components/Buttons';
import { DebuggerContext, DebuggerEventsContext } from './DebuggerComponent';
import { DEBUGGER_EVENTS, MENUS } from '../DebuggerConstants';
import { useKeyboardShortcuts } from '../../../../../static/js/custom_hooks';
const useStyles = makeStyles((theme) => ({
root: {
@ -120,27 +120,67 @@ export function ToolBar() {
}, []);
/* Button shortcuts */
useKeyboardShortcuts([
{
shortcut: preferences.btn_step_into,
options: {
callback: ()=>{!buttonsDisabled[MENUS.STEPINTO] && stepInTODebugger();}
}
},
{
shortcut: preferences.btn_step_over,
options: {
callback: ()=>{!buttonsDisabled[MENUS.STEPOVER] && stepOverDebugger();}
}
},
{
shortcut: preferences.btn_start,
options: {
callback: ()=>{!buttonsDisabled[MENUS.START] && continueDebugger();}
}
},
{
shortcut: preferences.btn_toggle_breakpoint,
options: {
callback: ()=>{!buttonsDisabled[MENUS.TOGGLE_BREAKPOINT] && toggleBreakpoint();}
}
},
{
shortcut: preferences.btn_clear_breakpoints,
options: {
callback: ()=>{!buttonsDisabled[MENUS.CLEAR_ALL_BREAKPOINT] && clearAllBreakpoint();}
}
},
{
shortcut: preferences.btn_stop,
options: {
callback: ()=>{!buttonsDisabled[MENUS.STOP] && stop();}
}
}
], debuggerCtx.containerRef);
return (
<Box className={classes.root}>
<PgButtonGroup size="small">
<PgIconButton data-test='step-in' title={gettext('Step into')} disabled={buttonsDisabled[MENUS.STEPINTO]} icon={<FormatIndentIncreaseIcon />} onClick={() => { stepInTODebugger(); }}
accesskey={shortcut_key(preferences?.btn_step_into)} />
shortcut={preferences?.btn_step_into} />
<PgIconButton data-test='step-over' title={gettext('Step over')} disabled={buttonsDisabled[MENUS.STEPOVER]} icon={<FormatIndentDecreaseIcon />} onClick={() => { stepOverDebugger(); }}
accesskey={shortcut_key(preferences?.btn_step_over)} />
shortcut={preferences?.btn_step_over} />
<PgIconButton data-test='debugger-contiue' title={gettext('Continue/Start')} disabled={buttonsDisabled[MENUS.START]} icon={<PlayCircleFilledWhiteIcon />} onClick={() => { continueDebugger(); }}
accesskey={shortcut_key(preferences?.btn_start)} />
shortcut={preferences?.btn_start} />
</PgButtonGroup>
<PgButtonGroup size="small">
<PgIconButton data-test='toggle-breakpoint' title={gettext('Toggle breakpoint')} disabled={buttonsDisabled[MENUS.TOGGLE_BREAKPOINT]} icon={<FiberManualRecordIcon style={{height: '2rem'}} />}
accesskey={shortcut_key(preferences?.btn_toggle_breakpoint)} onClick={() => { toggleBreakpoint(); }} />
shortcut={preferences?.btn_toggle_breakpoint} onClick={() => { toggleBreakpoint(); }} />
<PgIconButton data-test='clear-breakpoint' title={gettext('Clear all breakpoints')} disabled={buttonsDisabled[MENUS.CLEAR_ALL_BREAKPOINT]} icon={<NotInterestedIcon />}
accesskey={shortcut_key(preferences?.btn_clear_breakpoints)} onClick={() => {
shortcut={preferences?.btn_clear_breakpoints} onClick={() => {
clearAllBreakpoint();
}} />
</PgButtonGroup>
<PgButtonGroup size="small">
<PgIconButton data-test='stop-debugger' title={gettext('Stop')} icon={<StopIcon style={{height: '2rem'}} />} disabled={buttonsDisabled[MENUS.STOP]} onClick={() => { stop(); }}
accesskey={shortcut_key(preferences?.btn_stop)} />
shortcut={preferences?.btn_stop} />
</PgButtonGroup>
<PgButtonGroup size="small">
<PgIconButton data-test='debugger-help' title={gettext('Help')} icon={<HelpIcon />} onClick={onHelpClick} />
@ -151,4 +191,4 @@ export function ToolBar() {
</PgButtonGroup>
</Box>
);
}
}

View File

@ -73,6 +73,7 @@ class ERDModule(PgAdminModule):
'alt': False,
'shift': False,
'control': True,
'ctrl_is_meta': True,
'key': {
'key_code': 79,
'char': 'o'
@ -91,6 +92,7 @@ class ERDModule(PgAdminModule):
'alt': False,
'shift': False,
'control': True,
'ctrl_is_meta': True,
'key': {
'key_code': 83,
'char': 's'

View File

@ -51,7 +51,7 @@ export class KeyboardShortcutAction extends Action {
for(let shortcut_val of shortcut_handlers){
let [key, handler] = shortcut_val;
if(key) {
this.shortcuts[this.shortcutKey(key.alt, key.control, key.shift, false, key.key.key_code)] = handler;
this.shortcuts[this.shortcutKey(key.alt, key.ctrl_is_meta ? false : key.control, key.shift, Boolean(key.ctrl_is_meta), key.key.key_code)] = handler;
}
}
}
@ -63,6 +63,8 @@ export class KeyboardShortcutAction extends Action {
callHandler(event) {
let handler = this.shortcuts[this.shortcutKey(event.altKey, event.ctrlKey, event.shiftKey, event.metaKey, event.keyCode)];
if(handler) {
event.stopPropagation();
event.preventDefault();
handler();
}
}

View File

@ -26,7 +26,6 @@ import { QueryToolConnectionContext, QueryToolContext, QueryToolEventsContext }
import { PgMenu, PgMenuDivider, PgMenuItem, usePgMenuGroup } from '../../../../../../static/js/components/Menu';
import gettext from 'sources/gettext';
import { useKeyboardShortcuts } from '../../../../../../static/js/custom_hooks';
import {shortcut_key} from 'sources/keyboard_shortcuts';
import url_for from 'sources/url_for';
import _ from 'lodash';
import { InputSelectNonSearch } from '../../../../../../static/js/components/FormComponents';
@ -341,6 +340,54 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros}) {
/* Button shortcuts */
useKeyboardShortcuts([
{
shortcut: queryToolPref.btn_open_file,
options: {
callback: ()=>{openFile();}
}
},
{
shortcut: queryToolPref.btn_save_file,
options: {
callback: ()=>{!buttonsDisabled['save']&&saveFile(false);}
}
},
{
shortcut: queryToolPref.btn_edit_options,
options: {
callback: ()=>{queryToolCtx.params.is_query_tool&&toggleMenu({
currentTarget: {name: 'menu-edit'}
});}
}
},
{
shortcut: queryToolPref.btn_filter_dialog,
options: {
callback: ()=>{!buttonsDisabled['filter']&&onFilterClick();}
}
},
{
shortcut: queryToolPref.btn_filter_options,
options: {
callback: ()=>{!buttonsDisabled['filter']&&toggleMenu({
currentTarget: {name: 'menu-filter'}
});}
}
},
{
shortcut: queryToolPref.btn_cancel_query,
options: {
callback: ()=>{!buttonsDisabled['cancel']&&cancelQuery();}
}
},
{
shortcut: queryToolPref.btn_execute_options,
options: {
callback: ()=>{!buttonsDisabled['execute-options']&&toggleMenu({
currentTarget: {name: 'menu-autocommit'}
});}
}
},
{
shortcut: queryToolPref.execute_query,
options: {
@ -443,9 +490,9 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros}) {
<Box className={classes.root}>
<PgButtonGroup size="small">
<PgIconButton title={gettext('Open File')} icon={<FolderRoundedIcon />} disabled={!queryToolCtx.params.is_query_tool}
accesskey={shortcut_key(queryToolPref.btn_open_file)} onClick={openFile} />
shortcut={queryToolPref.btn_open_file} onClick={openFile} />
<PgIconButton title={gettext('Save File')} icon={<SaveRoundedIcon />}
accesskey={shortcut_key(queryToolPref.btn_save_file)} disabled={buttonsDisabled['save'] || !queryToolCtx.params.is_query_tool}
shortcut={queryToolPref.btn_save_file} disabled={buttonsDisabled['save'] || !queryToolCtx.params.is_query_tool}
onClick={()=>{saveFile(false);}} />
<PgIconButton title={gettext('File')} icon={<KeyboardArrowDownIcon />} splitButton disabled={!queryToolCtx.params.is_query_tool}
name="menu-saveas" ref={saveAsMenuRef} onClick={toggleMenu}
@ -454,14 +501,14 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros}) {
<PgButtonGroup size="small">
<PgIconButton title={gettext('Edit')} icon={
<><EditRoundedIcon /><KeyboardArrowDownIcon style={{marginLeft: '-10px'}} /></>}
disabled={!queryToolCtx.params.is_query_tool} accesskey={shortcut_key(queryToolPref.btn_edit_options)}
disabled={!queryToolCtx.params.is_query_tool} shortcut={queryToolPref.btn_edit_options}
name="menu-edit" ref={editMenuRef} onClick={toggleMenu} />
</PgButtonGroup>
<PgButtonGroup size="small" >
<PgIconButton title={gettext('Sort/Filter')} color={highlightFilter ? 'primary' : 'default'} icon={<FilterIcon />}
onClick={onFilterClick} disabled={buttonsDisabled['filter']} accesskey={shortcut_key(queryToolPref.btn_filter_dialog)}/>
onClick={onFilterClick} disabled={buttonsDisabled['filter']} shortcut={queryToolPref.btn_filter_dialog}/>
<PgIconButton title={gettext('Filter options')} color={highlightFilter ? 'primary' : 'default'} icon={<KeyboardArrowDownIcon />} splitButton
disabled={buttonsDisabled['filter']} name="menu-filter" ref={filterMenuRef} accesskey={shortcut_key(queryToolPref.btn_filter_options)}
disabled={buttonsDisabled['filter']} name="menu-filter" ref={filterMenuRef} shortcut={queryToolPref.btn_filter_options}
onClick={toggleMenu} />
</PgButtonGroup>
<InputSelectNonSearch options={[
@ -472,11 +519,11 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros}) {
]} value={limit} onChange={onLimitChange} disabled={buttonsDisabled['limit'] || queryToolCtx.params.is_query_tool} />
<PgButtonGroup size="small">
<PgIconButton title={gettext('Cancel query')} icon={<StopRoundedIcon style={{height: 'unset'}} />}
onClick={cancelQuery} disabled={buttonsDisabled['cancel']} accesskey={shortcut_key(queryToolPref.btn_cancel_query)} />
onClick={cancelQuery} disabled={buttonsDisabled['cancel']} shortcut={queryToolPref.btn_cancel_query} />
<PgIconButton title={gettext('Execute script')} icon={<PlayArrowRoundedIcon style={{height: 'unset'}} />}
onClick={executeQuery} disabled={buttonsDisabled['execute']} shortcut={queryToolPref.execute_query}/>
<PgIconButton title={gettext('Execute options')} icon={<KeyboardArrowDownIcon />} splitButton
name="menu-autocommit" ref={autoCommitMenuRef} accesskey={shortcut_key(queryToolPref.btn_execute_options)}
name="menu-autocommit" ref={autoCommitMenuRef} shortcut={queryToolPref.btn_execute_options}
onClick={toggleMenu} disabled={buttonsDisabled['execute-options']}/>
</PgButtonGroup>
<PgButtonGroup size="small">

View File

@ -377,6 +377,7 @@ export function QueryHistory() {
const eventBus = React.useContext(QueryToolEventsContext);
const [selectedItemKey, setSelectedItemKey] = React.useState(1);
const [showInternal, setShowInternal] = React.useState(true);
const [, setRefresh] = React.useState(false);
const [loaderText, setLoaderText] = React.useState('');
const selectedEntry = qhu.current.getEntry(selectedItemKey);
const layoutDocker = useContext(LayoutDockerContext);
@ -424,6 +425,7 @@ export function QueryHistory() {
};
}
qhu.current.addEntry(h);
setRefresh((prev)=>!prev);
};
listRef.current?.focus();

View File

@ -22,7 +22,6 @@ import { QueryToolContext, QueryToolEventsContext } from '../QueryToolComponent'
import { PgMenu, PgMenuItem } from '../../../../../../static/js/components/Menu';
import gettext from 'sources/gettext';
import { useKeyboardShortcuts } from '../../../../../../static/js/custom_hooks';
import {shortcut_key} from 'sources/keyboard_shortcuts';
import CopyData from '../QueryToolDataGrid/CopyData';
import PropTypes from 'prop-types';
@ -137,6 +136,24 @@ export function ResultSetToolbar({canEdit, totalRowCount}) {
};
useKeyboardShortcuts([
{
shortcut: queryToolPref.btn_add_row,
options: {
callback: ()=>{canEdit && addRow();}
}
},
{
shortcut: queryToolPref.btn_paste_row,
options: {
callback: ()=>{canEdit && pasteRows();}
}
},
{
shortcut: queryToolPref.btn_delete_row,
options: {
callback: ()=>{!(buttonsDisabled['delete-rows'] || !canEdit) && deleteRows();}
}
},
{
shortcut: queryToolPref.save_data,
options: {
@ -156,17 +173,17 @@ export function ResultSetToolbar({canEdit, totalRowCount}) {
<Box className={classes.root}>
<PgButtonGroup size="small">
<PgIconButton title={gettext('Add row')} icon={<PlaylistAddRoundedIcon style={{height: 'unset'}}/>}
accesskey={shortcut_key(queryToolPref.btn_add_row)} disabled={!canEdit} onClick={addRow} />
shortcut={queryToolPref.btn_add_row} disabled={!canEdit} onClick={addRow} />
<PgIconButton title={gettext('Copy')} icon={<FileCopyRoundedIcon />}
shortcut={FIXED_PREF.copy} disabled={buttonsDisabled['copy-rows']} onClick={copyData} />
<PgIconButton title={gettext('Copy options')} icon={<KeyboardArrowDownIcon />} splitButton
name="menu-copyheader" ref={copyMenuRef} onClick={openMenu} />
<PgIconButton title={gettext('Paste')} icon={<PasteIcon />}
accesskey={shortcut_key(queryToolPref.btn_paste_row)} disabled={!canEdit} onClick={pasteRows} />
shortcut={queryToolPref.btn_paste_row} disabled={!canEdit} onClick={pasteRows} />
<PgIconButton title={gettext('Paste options')} icon={<KeyboardArrowDownIcon />} splitButton
name="menu-pasteoptions" ref={pasetMenuRef} onClick={openMenu} />
<PgIconButton title={gettext('Delete')} icon={<DeleteRoundedIcon />}
accesskey={shortcut_key(queryToolPref.btn_delete_row)} disabled={buttonsDisabled['delete-rows'] || !canEdit} onClick={deleteRows} />
shortcut={queryToolPref.btn_delete_row} disabled={buttonsDisabled['delete-rows'] || !canEdit} onClick={deleteRows} />
</PgButtonGroup>
<PgButtonGroup size="small">
<PgIconButton title={gettext('Save Data Changes')} icon={<SaveDataIcon />}

View File

@ -13,8 +13,7 @@ from pgadmin.utils.constants import PREF_LABEL_DISPLAY,\
PREF_LABEL_KEYBOARD_SHORTCUTS, PREF_LABEL_EXPLAIN, PREF_LABEL_OPTIONS,\
PREF_LABEL_EDITOR, PREF_LABEL_CSV_TXT, PREF_LABEL_RESULTS_GRID,\
PREF_LABEL_SQL_FORMATTING, PREF_LABEL_GRAPH_VISUALISER
from pgadmin.utils import SHORTCUT_FIELDS as shortcut_fields, \
ACCESSKEY_FIELDS as accesskey_fields
from pgadmin.utils import SHORTCUT_FIELDS as shortcut_fields
from config import ON_DEMAND_RECORD_COUNT
@ -374,13 +373,13 @@ def register_query_tool_preferences(self):
'alt': False,
'shift': False,
'control': False,
'ctrl_is_meta': False,
'key': {
'key_code': 116,
'char': 'F5'
}
},
category_label=PREF_LABEL_KEYBOARD_SHORTCUTS,
fields=shortcut_fields
)
self.preference.register(
@ -530,132 +529,172 @@ def register_query_tool_preferences(self):
# All about access keys
self.preference.register(
'keyboard_shortcuts', 'btn_open_file',
gettext('Accesskey (Open file)'), 'keyboardshortcut',
gettext('Open file'), 'keyboardshortcut',
{
'alt': False,
'shift': False,
'control': True,
'ctrl_is_meta': True,
'key': {
'key_code': 79,
'char': 'o'
}
},
},
category_label=PREF_LABEL_KEYBOARD_SHORTCUTS,
fields=accesskey_fields
fields=shortcut_fields
)
self.preference.register(
'keyboard_shortcuts', 'btn_save_file',
gettext('Accesskey (Save file)'), 'keyboardshortcut',
gettext('Save file'), 'keyboardshortcut',
{
'alt': False,
'shift': False,
'control': True,
'ctrl_is_meta': True,
'key': {
'key_code': 83,
'char': 's'
}
},
category_label=PREF_LABEL_KEYBOARD_SHORTCUTS,
fields=accesskey_fields
fields=shortcut_fields
)
self.preference.register(
'keyboard_shortcuts', 'btn_add_row',
gettext('Add row'), 'keyboardshortcut',
{
'alt': True,
'shift': True,
'control': False,
'ctrl_is_meta': False,
'key': {
'key_code': 65,
'char': 'a'
}
},
category_label=PREF_LABEL_KEYBOARD_SHORTCUTS,
fields=shortcut_fields
)
self.preference.register(
'keyboard_shortcuts', 'btn_paste_row',
gettext('Accesskey (Paste rows)'), 'keyboardshortcut',
gettext('Paste rows'), 'keyboardshortcut',
{
'alt': True,
'shift': True,
'control': False,
'ctrl_is_meta': False,
'key': {
'key_code': 80,
'char': 'p'
}
},
category_label=PREF_LABEL_KEYBOARD_SHORTCUTS,
fields=accesskey_fields
fields=shortcut_fields
)
self.preference.register(
'keyboard_shortcuts', 'btn_delete_row',
gettext('Accesskey (Delete rows)'), 'keyboardshortcut',
gettext('Delete rows'), 'keyboardshortcut',
{
'alt': True,
'shift': True,
'control': False,
'ctrl_is_meta': False,
'key': {
'key_code': 68,
'char': 'd'
}
},
category_label=PREF_LABEL_KEYBOARD_SHORTCUTS,
fields=accesskey_fields
fields=shortcut_fields
)
self.preference.register(
'keyboard_shortcuts', 'btn_filter_dialog',
gettext('Accesskey (Filter dialog)'), 'keyboardshortcut',
gettext('Filter dialog'), 'keyboardshortcut',
{
'alt': True,
'shift': True,
'control': False,
'ctrl_is_meta': False,
'key': {
'key_code': 70,
'char': 'f'
}
},
category_label=PREF_LABEL_KEYBOARD_SHORTCUTS,
fields=accesskey_fields
fields=shortcut_fields
)
self.preference.register(
'keyboard_shortcuts', 'btn_filter_options',
gettext('Accesskey (Filter options)'), 'keyboardshortcut',
gettext('Filter options'), 'keyboardshortcut',
{
'alt': True,
'shift': True,
'control': False,
'ctrl_is_meta': False,
'key': {
'key_code': 73,
'char': 'i'
}
},
category_label=PREF_LABEL_KEYBOARD_SHORTCUTS,
fields=accesskey_fields
)
self.preference.register(
'keyboard_shortcuts', 'btn_rows_limit',
gettext('Accesskey (Rows limit)'), 'keyboardshortcut',
{
'key': {
'key_code': 82,
'char': 'r'
}
},
category_label=PREF_LABEL_KEYBOARD_SHORTCUTS,
fields=accesskey_fields
fields=shortcut_fields
)
self.preference.register(
'keyboard_shortcuts', 'btn_execute_options',
gettext('Accesskey (Execute options)'), 'keyboardshortcut',
gettext('Execute options'), 'keyboardshortcut',
{
'alt': True,
'shift': True,
'control': False,
'ctrl_is_meta': False,
'key': {
'key_code': 88,
'char': 'x'
}
},
category_label=PREF_LABEL_KEYBOARD_SHORTCUTS,
fields=accesskey_fields
fields=shortcut_fields
)
self.preference.register(
'keyboard_shortcuts', 'btn_cancel_query',
gettext('Accesskey (Cancel query)'), 'keyboardshortcut',
gettext('Cancel query'), 'keyboardshortcut',
{
'alt': True,
'shift': True,
'control': False,
'ctrl_is_meta': False,
'key': {
'key_code': 81,
'char': 'q'
}
},
category_label=PREF_LABEL_KEYBOARD_SHORTCUTS,
fields=accesskey_fields
fields=shortcut_fields
)
self.preference.register(
'keyboard_shortcuts', 'btn_edit_options',
gettext('Accesskey (Edit options)'), 'keyboardshortcut',
gettext('Edit options'), 'keyboardshortcut',
{
'alt': True,
'shift': True,
'control': False,
'ctrl_is_meta': False,
'key': {
'key_code': 78,
'char': 'n'
}
},
category_label=PREF_LABEL_KEYBOARD_SHORTCUTS,
fields=accesskey_fields
fields=shortcut_fields
)
self.preference.register(

View File

@ -10,9 +10,9 @@
import React from 'react';
import { withTheme } from '../fake_theme';
import { fireEvent, render, screen } from '@testing-library/react';
import { fireEvent, render } from '@testing-library/react';
import * as keyShort from '../../../pgadmin/static/js/keyboard_shortcuts';
import KeyboardShortcuts from '../../../pgadmin/static/js/components/KeyboardShortcuts';
/* MUI Components need to be wrapped in Theme for theme vars */
@ -48,8 +48,9 @@ describe('KeyboardShortcuts', () => {
describe('KeyboardShortcuts', () => {
let ThemedFormInputKeyboardShortcuts = withTheme(KeyboardShortcuts);
let onChange = jest.fn();
beforeEach(() => {
render(
const ctrlRender = ()=>{
return render(
<ThemedFormInputKeyboardShortcuts
value={defult_value}
fields={fields}
@ -59,34 +60,49 @@ describe('KeyboardShortcuts', () => {
}}
onChange={onChange}
/>);
};
beforeAll(()=>{
jest.spyOn(keyShort, 'isMac').mockReturnValue(true);
});
it('init', () => {
expect(screen.getByRole('textbox').getAttribute('value')).toBe('a');
const ctrl = ctrlRender();
expect(ctrl.container.querySelector('input').getAttribute('value')).toBe('a');
});
it('Key change', () => {
fireEvent.keyDown(screen.getByRole('textbox'), {
const ctrl = ctrlRender();
fireEvent.keyDown(ctrl.container.querySelector('input'), {
key: 'Space', code: 32, keyCode: 32
});
expect(onChange).toHaveBeenCalledWith({ control: true, alt: true, key: { char: 'Space', key_code: 32 }, shift: false });
});
it('Shift option', () => {
const input = screen.getAllByRole('checkbox').at(0);
const ctrl = ctrlRender();
const input = ctrl.container.querySelectorAll('button')[0];
fireEvent.click(input);
expect(onChange).toHaveBeenCalledWith({ control: true, alt: true, key: { char: 'a', key_code: 97 }, shift: true });
});
it('Control option', () => {
const input = screen.getAllByRole('checkbox').at(1);
const ctrl = ctrlRender();
const input = ctrl.container.querySelectorAll('button')[1];
fireEvent.click(input);
expect(onChange).toHaveBeenCalledWith({ control: false, alt: true, key: { char: 'a', key_code: 97 }, shift: false });
expect(onChange).toHaveBeenCalledWith({ control: false, ctrl_is_meta: false, alt: true, key: { char: 'a', key_code: 97 }, shift: false });
});
it('Cmd option', () => {
const ctrl = ctrlRender();
const input = ctrl.container.querySelectorAll('button')[2];
fireEvent.click(input);
expect(onChange).toHaveBeenCalledWith({ control: true, ctrl_is_meta: true, alt: true, key: { char: 'a', key_code: 97 }, shift: false });
});
it('Alt option', () => {
const input = screen.getAllByRole('checkbox').at(2);
const ctrl = ctrlRender();
const input = ctrl.container.querySelectorAll('button')[3];
fireEvent.click(input);
expect(onChange).toHaveBeenCalledWith({ control: true, alt: false, key: { char: 'a', key_code: 97 }, shift: false });
});

View File

@ -7,17 +7,20 @@
//
//////////////////////////////////////////////////////////////
import React from 'react';
import React, { useRef } from 'react';
import PropTypes from 'prop-types';
import {DebuggerContext, DebuggerEventsContext} from '../../../pgadmin/tools/debugger/static/js/components/DebuggerComponent';
import { withBrowser } from '../genericFunctions';
function MockDebuggerComponent({value, eventsvalue, children}) {
const containerRef = useRef();
return (
<DebuggerContext.Provider value={value}>
<DebuggerContext.Provider value={{...value, containerRef: containerRef}}>
<DebuggerEventsContext.Provider value={eventsvalue}>
{children}
<div ref={containerRef} style={{width: '100%', height: '100%'}}>
{children}
</div>
</DebuggerEventsContext.Provider>
</DebuggerContext.Provider>
);

View File

@ -50,11 +50,13 @@ describe('KeyboardShortcutAction', ()=>{
});
it('callHandler', ()=>{
let keyEvent = {altKey: key1.alt, ctrlKey: key1.control, shiftKey: key1.shift, metaKey: false, keyCode:key1.key.key_code};
let keyEvent = {altKey: key1.alt, ctrlKey: key1.control, shiftKey: key1.shift, metaKey: false, keyCode:key1.key.key_code,
stopPropagation: jest.fn(), preventDefault: jest.fn()};
keyAction.callHandler(keyEvent);
expect(handler1).toHaveBeenCalled();
keyEvent = {altKey: key2.alt, ctrlKey: key2.control, shiftKey: key2.shift, metaKey: false, keyCode:key2.key.key_code};
keyEvent = {altKey: key2.alt, ctrlKey: key2.control, shiftKey: key2.shift, metaKey: false, keyCode:key2.key.key_code,
stopPropagation: jest.fn(), preventDefault: jest.fn()};
keyAction.callHandler(keyEvent);
expect(handler2).toHaveBeenCalled();
});