Added Keybindings tab. (#3204)

* Added Keybindings tab.

* Minor Refactoring
This commit is contained in:
Sanjai Kumar 2024-09-30 17:20:46 +05:30 committed by GitHub
parent 02a82c5371
commit 95e56cd9c9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 179 additions and 17 deletions

View File

@ -0,0 +1,46 @@
import styled from 'styled-components';
const StyledWrapper = styled.div`
table {
width: 100%;
border-collapse: collapse;
thead,
td {
border: 2px solid ${(props) => props.theme.table.border};
}
thead {
color: ${(props) => props.theme.table.thead.color};
font-size: 1rem;
user-select: none;
}
td {
padding: 4px 8px;
}
thead th {
font-weight: 600;
padding: 10px;
text-align: left;
}
}
.table-container {
max-height: 400px;
overflow-y: scroll;
}
.key-button {
display: inline-block;
color: ${(props) => props.theme.colors.text.white};
border-radius: 4px;
padding: 1px 5px;
font-family: monospace;
margin-right: 8px;
border: 1px solid #ccc;
}
`;
export default StyledWrapper;

View File

@ -0,0 +1,45 @@
import StyledWrapper from './StyledWrapper';
import React from 'react';
import { getKeyBindingsForOS } from 'providers/Hotkeys/keyMappings';
import { isMacOS } from 'utils/common/platform';
const Keybindings = ({ close }) => {
const keyMapping = getKeyBindingsForOS(isMacOS() ? 'mac' : 'windows');
return (
<StyledWrapper className="w-full">
<div className="table-container">
<table>
<thead>
<tr>
<th>Command</th>
<th>Keybinding</th>
</tr>
</thead>
<tbody>
{keyMapping ? (
Object.entries(keyMapping).map(([action, { name, keys }], index) => (
<tr key={index}>
<td>{name}</td>
<td>
{keys.split('+').map((key, i) => (
<div className="key-button" key={i}>
{key}
</div>
))}
</td>
</tr>
))
) : (
<tr>
<td colSpan="2">No key bindings available</td>
</tr>
)}
</tbody>
</table>
</div>
</StyledWrapper>
);
};
export default Keybindings;

View File

@ -1,11 +1,14 @@
import Modal from 'components/Modal/index'; import Modal from 'components/Modal/index';
import classnames from 'classnames'; import classnames from 'classnames';
import React, { useState } from 'react'; import React, { useState } from 'react';
import Support from './Support'; import Support from './Support';
import General from './General'; import General from './General';
import Proxy from './ProxySettings'; import Proxy from './ProxySettings';
import Display from './Display';
import Keybindings from './Keybindings';
import StyledWrapper from './StyledWrapper'; import StyledWrapper from './StyledWrapper';
import Display from './Display/index';
const Preferences = ({ onClose }) => { const Preferences = ({ onClose }) => {
const [tab, setTab] = useState('general'); const [tab, setTab] = useState('general');
@ -30,6 +33,10 @@ const Preferences = ({ onClose }) => {
return <Display close={onClose} />; return <Display close={onClose} />;
} }
case 'keybindings': {
return <Keybindings close={onClose} />;
}
case 'support': { case 'support': {
return <Support />; return <Support />;
} }
@ -50,6 +57,9 @@ const Preferences = ({ onClose }) => {
<div className={getTabClassname('proxy')} role="tab" onClick={() => setTab('proxy')}> <div className={getTabClassname('proxy')} role="tab" onClick={() => setTab('proxy')}>
Proxy Proxy
</div> </div>
<div className={getTabClassname('keybindings')} role="tab" onClick={() => setTab('keybindings')}>
Keybindings
</div>
<div className={getTabClassname('support')} role="tab" onClick={() => setTab('support')}> <div className={getTabClassname('support')} role="tab" onClick={() => setTab('support')}>
Support Support
</div> </div>

View File

@ -10,6 +10,7 @@ import NewRequest from 'components/Sidebar/NewRequest';
import { sendRequest, saveRequest, saveCollectionRoot } from 'providers/ReduxStore/slices/collections/actions'; import { sendRequest, saveRequest, saveCollectionRoot } from 'providers/ReduxStore/slices/collections/actions';
import { findCollectionByUid, findItemInCollection } from 'utils/collections'; import { findCollectionByUid, findItemInCollection } from 'utils/collections';
import { closeTabs, switchTab } from 'providers/ReduxStore/slices/tabs'; import { closeTabs, switchTab } from 'providers/ReduxStore/slices/tabs';
import { getKeyBindingsForActionAllOS } from './keyMappings';
export const HotkeysContext = React.createContext(); export const HotkeysContext = React.createContext();
@ -43,7 +44,7 @@ export const HotkeysProvider = (props) => {
// save hotkey // save hotkey
useEffect(() => { useEffect(() => {
Mousetrap.bind(['command+s', 'ctrl+s'], (e) => { Mousetrap.bind([...getKeyBindingsForActionAllOS('save')], (e) => {
if (isEnvironmentSettingsModalOpen) { if (isEnvironmentSettingsModalOpen) {
console.log('todo: save environment settings'); console.log('todo: save environment settings');
} else { } else {
@ -68,13 +69,13 @@ export const HotkeysProvider = (props) => {
}); });
return () => { return () => {
Mousetrap.unbind(['command+s', 'ctrl+s']); Mousetrap.unbind([...getKeyBindingsForActionAllOS('save')]);
}; };
}, [activeTabUid, tabs, saveRequest, collections, isEnvironmentSettingsModalOpen]); }, [activeTabUid, tabs, saveRequest, collections, isEnvironmentSettingsModalOpen]);
// send request (ctrl/cmd + enter) // send request (ctrl/cmd + enter)
useEffect(() => { useEffect(() => {
Mousetrap.bind(['command+enter', 'ctrl+enter'], (e) => { Mousetrap.bind([...getKeyBindingsForActionAllOS('sendRequest')], (e) => {
const activeTab = find(tabs, (t) => t.uid === activeTabUid); const activeTab = find(tabs, (t) => t.uid === activeTabUid);
if (activeTab) { if (activeTab) {
const collection = findCollectionByUid(collections, activeTab.collectionUid); const collection = findCollectionByUid(collections, activeTab.collectionUid);
@ -95,13 +96,13 @@ export const HotkeysProvider = (props) => {
}); });
return () => { return () => {
Mousetrap.unbind(['command+enter', 'ctrl+enter']); Mousetrap.unbind([...getKeyBindingsForActionAllOS('sendRequest')]);
}; };
}, [activeTabUid, tabs, saveRequest, collections]); }, [activeTabUid, tabs, saveRequest, collections]);
// edit environments (ctrl/cmd + e) // edit environments (ctrl/cmd + e)
useEffect(() => { useEffect(() => {
Mousetrap.bind(['command+e', 'ctrl+e'], (e) => { Mousetrap.bind([...getKeyBindingsForActionAllOS('editEnvironment')], (e) => {
const activeTab = find(tabs, (t) => t.uid === activeTabUid); const activeTab = find(tabs, (t) => t.uid === activeTabUid);
if (activeTab) { if (activeTab) {
const collection = findCollectionByUid(collections, activeTab.collectionUid); const collection = findCollectionByUid(collections, activeTab.collectionUid);
@ -115,13 +116,13 @@ export const HotkeysProvider = (props) => {
}); });
return () => { return () => {
Mousetrap.unbind(['command+e', 'ctrl+e']); Mousetrap.unbind([...getKeyBindingsForActionAllOS('editEnvironment')]);
}; };
}, [activeTabUid, tabs, collections, setShowEnvSettingsModal]); }, [activeTabUid, tabs, collections, setShowEnvSettingsModal]);
// new request (ctrl/cmd + b) // new request (ctrl/cmd + b)
useEffect(() => { useEffect(() => {
Mousetrap.bind(['command+b', 'ctrl+b'], (e) => { Mousetrap.bind([...getKeyBindingsForActionAllOS('newRequest')], (e) => {
const activeTab = find(tabs, (t) => t.uid === activeTabUid); const activeTab = find(tabs, (t) => t.uid === activeTabUid);
if (activeTab) { if (activeTab) {
const collection = findCollectionByUid(collections, activeTab.collectionUid); const collection = findCollectionByUid(collections, activeTab.collectionUid);
@ -135,13 +136,13 @@ export const HotkeysProvider = (props) => {
}); });
return () => { return () => {
Mousetrap.unbind(['command+b', 'ctrl+b']); Mousetrap.unbind([...getKeyBindingsForActionAllOS('newRequest')]);
}; };
}, [activeTabUid, tabs, collections, setShowNewRequestModal]); }, [activeTabUid, tabs, collections, setShowNewRequestModal]);
// close tab hotkey // close tab hotkey
useEffect(() => { useEffect(() => {
Mousetrap.bind(['command+w', 'ctrl+w'], (e) => { Mousetrap.bind([...getKeyBindingsForActionAllOS('closeTab')], (e) => {
dispatch( dispatch(
closeTabs({ closeTabs({
tabUids: [activeTabUid] tabUids: [activeTabUid]
@ -152,13 +153,13 @@ export const HotkeysProvider = (props) => {
}); });
return () => { return () => {
Mousetrap.unbind(['command+w', 'ctrl+w']); Mousetrap.unbind([...getKeyBindingsForActionAllOS('closeTab')]);
}; };
}, [activeTabUid]); }, [activeTabUid]);
// Switch to the previous tab // Switch to the previous tab
useEffect(() => { useEffect(() => {
Mousetrap.bind(['command+pageup', 'ctrl+pageup'], (e) => { Mousetrap.bind([...getKeyBindingsForActionAllOS('switchToPreviousTab')], (e) => {
dispatch( dispatch(
switchTab({ switchTab({
direction: 'pageup' direction: 'pageup'
@ -169,13 +170,13 @@ export const HotkeysProvider = (props) => {
}); });
return () => { return () => {
Mousetrap.unbind(['command+pageup', 'ctrl+pageup']); Mousetrap.unbind([...getKeyBindingsForActionAllOS('switchToPreviousTab')]);
}; };
}, [dispatch]); }, [dispatch]);
// Switch to the next tab // Switch to the next tab
useEffect(() => { useEffect(() => {
Mousetrap.bind(['command+pagedown', 'ctrl+pagedown'], (e) => { Mousetrap.bind([...getKeyBindingsForActionAllOS('switchToNextTab')], (e) => {
dispatch( dispatch(
switchTab({ switchTab({
direction: 'pagedown' direction: 'pagedown'
@ -186,13 +187,13 @@ export const HotkeysProvider = (props) => {
}); });
return () => { return () => {
Mousetrap.unbind(['command+pagedown', 'ctrl+pagedown']); Mousetrap.unbind([...getKeyBindingsForActionAllOS('switchToNextTab')]);
}; };
}, [dispatch]); }, [dispatch]);
// Close all tabs // Close all tabs
useEffect(() => { useEffect(() => {
Mousetrap.bind(['command+shift+w', 'ctrl+shift+w'], (e) => { Mousetrap.bind([...getKeyBindingsForActionAllOS('closeAllTabs')], (e) => {
const activeTab = find(tabs, (t) => t.uid === activeTabUid); const activeTab = find(tabs, (t) => t.uid === activeTabUid);
if (activeTab) { if (activeTab) {
const collection = findCollectionByUid(collections, activeTab.collectionUid); const collection = findCollectionByUid(collections, activeTab.collectionUid);
@ -211,7 +212,7 @@ export const HotkeysProvider = (props) => {
}); });
return () => { return () => {
Mousetrap.unbind(['command+shift+w', 'ctrl+shift+w']); Mousetrap.unbind([...getKeyBindingsForActionAllOS('closeAllTabs')]);
}; };
}, [activeTabUid, tabs, collections, dispatch]); }, [activeTabUid, tabs, collections, dispatch]);

View File

@ -0,0 +1,60 @@
const KeyMapping = {
save: { mac: 'command+s', windows: 'ctrl+s', name: 'Save' },
sendRequest: { mac: 'command+enter', windows: 'ctrl+enter', name: 'Send Request' },
editEnvironment: { mac: 'command+e', windows: 'ctrl+e', name: 'Edit Environment' },
newRequest: { mac: 'command+b', windows: 'ctrl+b', name: 'New Request' },
closeTab: { mac: 'command+w', windows: 'ctrl+w', name: 'Close Tab' },
openPreferences: { mac: 'command+,', windows: 'ctrl+,', name: 'Open Preferences' },
minimizeWindow: {
mac: 'command+Shift+Q',
windows: 'control+Shift+Q',
name: 'Minimize Window'
},
switchToPreviousTab: {
mac: 'command+pageup',
windows: 'ctrl+pageup',
name: 'Switch to Previous Tab'
},
switchToNextTab: {
mac: 'command+pagedown',
windows: 'ctrl+pagedown',
name: 'Switch to Next Tab'
},
closeAllTabs: { mac: 'command+shift+w', windows: 'ctrl+shift+w', name: 'Close All Tabs' }
};
/**
* Retrieves the key bindings for a specific operating system.
*
* @param {string} os - The operating system (e.g., 'mac', 'windows').
* @returns {Object} An object containing the key bindings for the specified OS.
*/
export const getKeyBindingsForOS = (os) => {
const keyBindings = {};
for (const [action, { name, ...keys }] of Object.entries(KeyMapping)) {
if (keys[os]) {
keyBindings[action] = {
keys: keys[os],
name
};
}
}
return keyBindings;
};
/**
* Retrieves the key bindings for a specific action across all operating systems.
*
* @param {string} action - The action for which to retrieve key bindings.
* @returns {Object|null} An object containing the key bindings for macOS, Windows, or null if the action is not found.
*/
export const getKeyBindingsForActionAllOS = (action) => {
const actionBindings = KeyMapping[action];
if (!actionBindings) {
console.warn(`Action "${action}" not found in KeyMapping.`);
return null;
}
return [actionBindings.mac, actionBindings.windows];
};