Changes in Query Tool, Debugger, and ERD Tool shortcuts to remove the use of Accesskey which will allow them to be customized. #7192
Before Width: | Height: | Size: 179 KiB After Width: | Height: | Size: 191 KiB |
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 171 KiB |
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 178 KiB |
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 169 KiB |
|
@ -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
|
||||
********
|
||||
|
|
|
@ -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('');
|
||||
}
|
||||
|
|
|
@ -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',
|
||||
},
|
||||
}
|
||||
},
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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' }} /> {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' }} /> {option.label}
|
||||
</ToggleButton>
|
||||
);
|
||||
|
||||
return <ToggleCheckButton ref={i == 0 ? ref : null} key={option.label} label={option.label}
|
||||
selected={isSelected} value={option.value} disabled={isDisabled}
|
||||
/>;
|
||||
})
|
||||
}
|
||||
</ToggleButtonGroup>
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
/>);
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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'
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 />}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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 });
|
||||
});
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
|
|