diff --git a/web/packages/teleterm/src/services/config/configService.ts b/web/packages/teleterm/src/services/config/configService.ts index 2e153c59939de..11849542803ca 100644 --- a/web/packages/teleterm/src/services/config/configService.ts +++ b/web/packages/teleterm/src/services/config/configService.ts @@ -35,55 +35,55 @@ const createAppConfigSchema = (platform: Platform) => { return z.object({ 'usageReporting.enabled': z.boolean().default(false), 'keymap.tab1': omitStoredConfigValue( - z.string().default(defaultKeymap['tab-1']) + z.string().default(defaultKeymap['tab1']) ), 'keymap.tab2': omitStoredConfigValue( - z.string().default(defaultKeymap['tab-2']) + z.string().default(defaultKeymap['tab2']) ), 'keymap.tab3': omitStoredConfigValue( - z.string().default(defaultKeymap['tab-3']) + z.string().default(defaultKeymap['tab3']) ), 'keymap.tab4': omitStoredConfigValue( - z.string().default(defaultKeymap['tab-4']) + z.string().default(defaultKeymap['tab4']) ), 'keymap.tab5': omitStoredConfigValue( - z.string().default(defaultKeymap['tab-5']) + z.string().default(defaultKeymap['tab5']) ), 'keymap.tab6': omitStoredConfigValue( - z.string().default(defaultKeymap['tab-6']) + z.string().default(defaultKeymap['tab6']) ), 'keymap.tab7': omitStoredConfigValue( - z.string().default(defaultKeymap['tab-7']) + z.string().default(defaultKeymap['tab7']) ), 'keymap.tab8': omitStoredConfigValue( - z.string().default(defaultKeymap['tab-8']) + z.string().default(defaultKeymap['tab8']) ), 'keymap.tab9': omitStoredConfigValue( - z.string().default(defaultKeymap['tab-9']) + z.string().default(defaultKeymap['tab9']) ), - 'keymap.tabClose': omitStoredConfigValue( - z.string().default(defaultKeymap['tab-close']) + 'keymap.closeTab': omitStoredConfigValue( + z.string().default(defaultKeymap['closeTab']) ), - 'keymap.tabNew': omitStoredConfigValue( - z.string().default(defaultKeymap['tab-new']) + 'keymap.newTab': omitStoredConfigValue( + z.string().default(defaultKeymap['newTab']) ), - 'keymap.tabPrevious': omitStoredConfigValue( - z.string().default(defaultKeymap['tab-previous']) + 'keymap.previousTab': omitStoredConfigValue( + z.string().default(defaultKeymap['previousTab']) ), - 'keymap.tabNext': omitStoredConfigValue( - z.string().default(defaultKeymap['tab-next']) + 'keymap.nextTab': omitStoredConfigValue( + z.string().default(defaultKeymap['nextTab']) ), - 'keymap.toggleConnections': omitStoredConfigValue( - z.string().default(defaultKeymap['toggle-connections']) + 'keymap.openConnections': omitStoredConfigValue( + z.string().default(defaultKeymap['openConnections']) ), - 'keymap.toggleClusters': omitStoredConfigValue( - z.string().default(defaultKeymap['toggle-clusters']) + 'keymap.openClusters': omitStoredConfigValue( + z.string().default(defaultKeymap['openClusters']) ), - 'keymap.toggleIdentity': omitStoredConfigValue( - z.string().default(defaultKeymap['toggle-identity']) + 'keymap.openProfiles': omitStoredConfigValue( + z.string().default(defaultKeymap['openProfiles']) ), 'keymap.openQuickInput': omitStoredConfigValue( - z.string().default(defaultKeymap['open-quick-input']) + z.string().default(defaultKeymap['openQuickInput']) ), /** * This value can be provided by the user and is unsanitized. This means that it cannot be directly interpolated @@ -106,87 +106,86 @@ export type AppConfig = z.infer>; * Command-Control-Option-Shift for macOS * Ctrl-Alt-Shift for other platforms */ -export type KeyboardShortcutType = - | 'tab-1' - | 'tab-2' - | 'tab-3' - | 'tab-4' - | 'tab-5' - | 'tab-6' - | 'tab-7' - | 'tab-8' - | 'tab-9' - | 'tab-close' - | 'tab-new' - | 'tab-previous' - | 'tab-next' - | 'open-quick-input' - | 'toggle-connections' - | 'toggle-clusters' - | 'toggle-identity'; +export type KeyboardShortcutAction = + | 'tab1' + | 'tab2' + | 'tab3' + | 'tab4' + | 'tab5' + | 'tab6' + | 'tab7' + | 'tab8' + | 'tab9' + | 'closeTab' + | 'newTab' + | 'previousTab' + | 'nextTab' + | 'openQuickInput' + | 'openConnections' + | 'openClusters' + | 'openProfiles'; -export type KeyboardShortcutsConfig = Record; const getDefaultKeymap = (platform: Platform) => { switch (platform) { case 'win32': return { - 'tab-1': 'Ctrl-1', - 'tab-2': 'Ctrl-2', - 'tab-3': 'Ctrl-3', - 'tab-4': 'Ctrl-4', - 'tab-5': 'Ctrl-5', - 'tab-6': 'Ctrl-6', - 'tab-7': 'Ctrl-7', - 'tab-8': 'Ctrl-8', - 'tab-9': 'Ctrl-9', - 'tab-close': 'Ctrl-W', - 'tab-new': 'Ctrl-T', - 'tab-previous': 'Ctrl-Shift-Tab', - 'tab-next': 'Ctrl-Tab', - 'open-quick-input': 'Ctrl-K', - 'toggle-connections': 'Ctrl-P', - 'toggle-clusters': 'Ctrl-E', - 'toggle-identity': 'Ctrl-I', + tab1: 'Ctrl+1', + tab2: 'Ctrl+2', + tab3: 'Ctrl+3', + tab4: 'Ctrl+4', + tab5: 'Ctrl+5', + tab6: 'Ctrl+6', + tab7: 'Ctrl+7', + tab8: 'Ctrl+8', + tab9: 'Ctrl+9', + closeTab: 'Ctrl+W', + newTab: 'Ctrl+T', + previousTab: 'Ctrl+Shift+Tab', + nextTab: 'Ctrl+Tab', + openQuickInput: 'Ctrl+K', + openConnections: 'Ctrl+P', + openClusters: 'Ctrl+E', + openProfiles: 'Ctrl+I', }; case 'linux': return { - 'tab-1': 'Alt-1', - 'tab-2': 'Alt-2', - 'tab-3': 'Alt-3', - 'tab-4': 'Alt-4', - 'tab-5': 'Alt-5', - 'tab-6': 'Alt-6', - 'tab-7': 'Alt-7', - 'tab-8': 'Alt-8', - 'tab-9': 'Alt-9', - 'tab-close': 'Ctrl-W', - 'tab-new': 'Ctrl-T', - 'tab-previous': 'Ctrl-Shift-Tab', - 'tab-next': 'Ctrl-Tab', - 'open-quick-input': 'Ctrl-K', - 'toggle-connections': 'Ctrl-P', - 'toggle-clusters': 'Ctrl-E', - 'toggle-identity': 'Ctrl-I', + tab1: 'Alt+1', + tab2: 'Alt+2', + tab3: 'Alt+3', + tab4: 'Alt+4', + tab5: 'Alt+5', + tab6: 'Alt+6', + tab7: 'Alt+7', + tab8: 'Alt+8', + tab9: 'Alt+9', + closeTab: 'Ctrl+W', + newTab: 'Ctrl+T', + previousTab: 'Ctrl+Shift+Tab', + nextTab: 'Ctrl+Tab', + openQuickInput: 'Ctrl+K', + openConnections: 'Ctrl+P', + openClusters: 'Ctrl+E', + openProfiles: 'Ctrl+I', }; case 'darwin': return { - 'tab-1': 'Command-1', - 'tab-2': 'Command-2', - 'tab-3': 'Command-3', - 'tab-4': 'Command-4', - 'tab-5': 'Command-5', - 'tab-6': 'Command-6', - 'tab-7': 'Command-7', - 'tab-8': 'Command-8', - 'tab-9': 'Command-9', - 'tab-close': 'Command-W', - 'tab-new': 'Command-T', - 'tab-previous': 'Control-Shift-Tab', - 'tab-next': 'Control-Tab', - 'open-quick-input': 'Command-K', - 'toggle-connections': 'Command-P', - 'toggle-clusters': 'Command-E', - 'toggle-identity': 'Command-I', + tab1: 'Command+1', + tab2: 'Command+2', + tab3: 'Command+3', + tab4: 'Command+4', + tab5: 'Command+5', + tab6: 'Command+6', + tab7: 'Command+7', + tab8: 'Command+8', + tab9: 'Command+9', + closeTab: 'Command+W', + newTab: 'Command+T', + previousTab: 'Control+Shift+Tab', + nextTab: 'Control+Tab', + openQuickInput: 'Command+K', + openConnections: 'Command+P', + openClusters: 'Command+E', + openProfiles: 'Command+I', }; } }; diff --git a/web/packages/teleterm/src/ui/Documents/KeyboardShortcutsPanel.tsx b/web/packages/teleterm/src/ui/Documents/KeyboardShortcutsPanel.tsx index c62150a70bbab..89643c732c28f 100644 --- a/web/packages/teleterm/src/ui/Documents/KeyboardShortcutsPanel.tsx +++ b/web/packages/teleterm/src/ui/Documents/KeyboardShortcutsPanel.tsx @@ -21,31 +21,31 @@ import styled from 'styled-components'; import Document from 'teleterm/ui/Document'; import { useKeyboardShortcutFormatters } from 'teleterm/ui/services/keyboardShortcuts'; -import { KeyboardShortcutType } from 'teleterm/services/config'; +import { KeyboardShortcutAction } from 'teleterm/services/config'; export function KeyboardShortcutsPanel() { - const { getShortcut } = useKeyboardShortcutFormatters(); + const { getAccelerator } = useKeyboardShortcutFormatters(); - const items: { title: string; shortcutKey: KeyboardShortcutType }[] = [ + const items: { title: string; shortcutAction: KeyboardShortcutAction }[] = [ { title: 'Open New Tab', - shortcutKey: 'tab-new', + shortcutAction: 'newTab', }, { title: 'Go To Next Tab', - shortcutKey: 'tab-next', + shortcutAction: 'nextTab', }, { title: 'Open Connections', - shortcutKey: 'toggle-connections', + shortcutAction: 'openConnections', }, { title: 'Open Clusters', - shortcutKey: 'toggle-clusters', + shortcutAction: 'openClusters', }, { title: 'Open Profiles', - shortcutKey: 'toggle-identity', + shortcutAction: 'openProfiles', }, ]; @@ -55,10 +55,10 @@ export function KeyboardShortcutsPanel() { {items.map(item => ( ))} @@ -66,14 +66,14 @@ export function KeyboardShortcutsPanel() { ); } -function Entry(props: { title: string; shortcut: string }) { +function Entry(props: { title: string; accelerator: string }) { return ( <> {props.title} - {props.shortcut} + {props.accelerator} ); diff --git a/web/packages/teleterm/src/ui/QuickInput/useQuickInput.ts b/web/packages/teleterm/src/ui/QuickInput/useQuickInput.ts index b465f8dcb0e65..9c8bd01c915da 100644 --- a/web/packages/teleterm/src/ui/QuickInput/useQuickInput.ts +++ b/web/packages/teleterm/src/ui/QuickInput/useQuickInput.ts @@ -29,7 +29,7 @@ import { Suggestion, } from 'teleterm/ui/services/quickInput/types'; import { routing } from 'teleterm/ui/uri'; -import { KeyboardShortcutType } from 'teleterm/services/config'; +import { KeyboardShortcutAction } from 'teleterm/services/config'; import { assertUnreachable, retryWithRelogin } from '../utils'; @@ -67,14 +67,15 @@ export default function useQuickInput() { }); } } + get(); }, [parseResult]); const hasSuggestions = suggestionsAttempt.status === 'success' && suggestionsAttempt.data.length > 0; - const openQuickInputShortcutKey: KeyboardShortcutType = 'open-quick-input'; - const { getShortcut } = useKeyboardShortcutFormatters(); + const openQuickInputShortcutAction: KeyboardShortcutAction = 'openQuickInput'; + const { getAccelerator } = useKeyboardShortcutFormatters(); const onFocus = (e: any) => { if (e.relatedTarget) { @@ -162,7 +163,7 @@ export default function useQuickInput() { }; useKeyboardShortcuts({ - [openQuickInputShortcutKey]: () => { + [openQuickInputShortcutAction]: () => { quickInputService.show(); }, }); @@ -193,7 +194,7 @@ export default function useQuickInput() { onInputChange: quickInputService.setInputValue, onHide: quickInputService.hide, onShow: quickInputService.show, - keyboardShortcut: getShortcut(openQuickInputShortcutKey), + keyboardShortcut: getAccelerator(openQuickInputShortcutAction), }; } diff --git a/web/packages/teleterm/src/ui/TabHost/TabHost.test.tsx b/web/packages/teleterm/src/ui/TabHost/TabHost.test.tsx index 606dab1dd9930..e63b1ca20191f 100644 --- a/web/packages/teleterm/src/ui/TabHost/TabHost.test.tsx +++ b/web/packages/teleterm/src/ui/TabHost/TabHost.test.tsx @@ -67,12 +67,12 @@ function getTestSetup({ documents }: { documents: Document[] }) { // @ts-expect-error we don't provide entire config getShortcutsConfig() { return { - 'tab-close': 'Command-W', - 'tab-new': 'Command-T', - 'open-quick-input': 'Command-K', - 'toggle-connections': 'Command-P', - 'toggle-clusters': 'Command-E', - 'toggle-identity': 'Command-I', + closeTab: 'Command-W', + newTab: 'Command-T', + openQuickInput: 'Command-K', + openConnections: 'Command-P', + openClusters: 'Command-E', + openProfiles: 'Command-I', }; }, }; diff --git a/web/packages/teleterm/src/ui/TabHost/TabHost.tsx b/web/packages/teleterm/src/ui/TabHost/TabHost.tsx index 51d19782827f8..fdc544e0a49d9 100644 --- a/web/packages/teleterm/src/ui/TabHost/TabHost.tsx +++ b/web/packages/teleterm/src/ui/TabHost/TabHost.tsx @@ -51,7 +51,7 @@ export function TabHost({ ctx }: { ctx: IAppContext }) { localClusterUri: ctx.workspacesService.getActiveWorkspace()?.localClusterUri, }); - const { getLabelWithShortcut } = useKeyboardShortcutFormatters(); + const { getLabelWithAccelerator } = useKeyboardShortcutFormatters(); useTabShortcuts({ documentsService, @@ -108,8 +108,8 @@ export function TabHost({ ctx }: { ctx: IAppContext }) { onMoved={handleTabMoved} disableNew={false} onNew={openClusterTab} - newTabTooltip={getLabelWithShortcut('New Tab', 'tab-new')} - closeTabTooltip={getLabelWithShortcut('Close', 'tab-close')} + newTabTooltip={getLabelWithAccelerator('New Tab', 'newTab')} + closeTabTooltip={getLabelWithAccelerator('Close', 'closeTab')} /> diff --git a/web/packages/teleterm/src/ui/TabHost/useTabShortcuts.test.tsx b/web/packages/teleterm/src/ui/TabHost/useTabShortcuts.test.tsx index d6b75f1bb88a3..2960113e6c6ec 100644 --- a/web/packages/teleterm/src/ui/TabHost/useTabShortcuts.test.tsx +++ b/web/packages/teleterm/src/ui/TabHost/useTabShortcuts.test.tsx @@ -177,21 +177,21 @@ function getTestSetup({ documents }: { documents: Document[] }) { } test.each([ - { type: 'tab-1', value: 0 }, - { type: 'tab-2', value: 1 }, - { type: 'tab-3', value: 2 }, - { type: 'tab-4', value: 3 }, - { type: 'tab-5', value: 4 }, - { type: 'tab-6', value: 5 }, - { type: 'tab-7', value: 6 }, - { type: 'tab-8', value: 7 }, - { type: 'tab-9', value: 8 }, -])('open tab using $type shortcut', ({ type, value }) => { + { action: 'tab1', value: 0 }, + { action: 'tab2', value: 1 }, + { action: 'tab3', value: 2 }, + { action: 'tab4', value: 3 }, + { action: 'tab5', value: 4 }, + { action: 'tab6', value: 5 }, + { action: 'tab7', value: 6 }, + { action: 'tab8', value: 7 }, + { action: 'tab9', value: 8 }, +])('open tab using $type shortcut', ({ action, value }) => { const { emitKeyboardShortcutEvent, docsService } = getTestSetup({ documents: getMockDocuments(), }); - emitKeyboardShortcutEvent({ type } as KeyboardShortcutEvent); + emitKeyboardShortcutEvent({ action } as KeyboardShortcutEvent); expect(docsService.open).toHaveBeenCalledWith( docsService.getDocuments()[value].uri @@ -205,7 +205,7 @@ test('close active tab', () => { const documentToClose = docsService.getDocuments()[0]; docsService.getActive = () => documentToClose; - emitKeyboardShortcutEvent({ type: 'tab-close' }); + emitKeyboardShortcutEvent({ action: 'closeTab' }); expect(docsService.close).toHaveBeenCalledWith(documentToClose.uri); }); @@ -215,7 +215,7 @@ test('should ignore close command if no tabs are open', () => { documents: [], }); - emitKeyboardShortcutEvent({ type: 'tab-close' }); + emitKeyboardShortcutEvent({ action: 'closeTab' }); expect(docsService.close).not.toHaveBeenCalled(); }); @@ -231,7 +231,7 @@ test('open new tab', () => { kind: 'doc.cluster', }; docsService.createClusterDocument = () => mockedClusterDocument; - emitKeyboardShortcutEvent({ type: 'tab-new' }); + emitKeyboardShortcutEvent({ action: 'newTab' }); expect(docsService.add).toHaveBeenCalledWith(mockedClusterDocument); expect(docsService.open).toHaveBeenCalledWith(mockedClusterDocument.uri); @@ -245,7 +245,7 @@ describe('open next/previous tab', () => { const activeTabIndex = 2; docsService.getActive = () => docsService.getDocuments()[activeTabIndex]; - emitKeyboardShortcutEvent({ type: 'tab-next' }); + emitKeyboardShortcutEvent({ action: 'nextTab' }); expect(docsService.open).toHaveBeenCalledWith( docsService.getDocuments()[activeTabIndex + 1].uri @@ -259,7 +259,7 @@ describe('open next/previous tab', () => { const activeTabIndex = docsService.getDocuments().length - 1; docsService.getActive = () => docsService.getDocuments()[activeTabIndex]; - emitKeyboardShortcutEvent({ type: 'tab-next' }); + emitKeyboardShortcutEvent({ action: 'nextTab' }); expect(docsService.open).toHaveBeenCalledWith( docsService.getDocuments()[0].uri @@ -273,7 +273,7 @@ describe('open next/previous tab', () => { const activeTabIndex = 2; docsService.getActive = () => docsService.getDocuments()[activeTabIndex]; - emitKeyboardShortcutEvent({ type: 'tab-previous' }); + emitKeyboardShortcutEvent({ action: 'previousTab' }); expect(docsService.open).toHaveBeenCalledWith( docsService.getDocuments()[activeTabIndex - 1].uri @@ -287,7 +287,7 @@ describe('open next/previous tab', () => { const activeTabIndex = 0; docsService.getActive = () => docsService.getDocuments()[activeTabIndex]; - emitKeyboardShortcutEvent({ type: 'tab-previous' }); + emitKeyboardShortcutEvent({ action: 'previousTab' }); expect(docsService.open).toHaveBeenCalledWith( docsService.getDocuments()[docsService.getDocuments().length - 1].uri @@ -298,7 +298,7 @@ describe('open next/previous tab', () => { const { emitKeyboardShortcutEvent, docsService } = getTestSetup({ documents: [], }); - emitKeyboardShortcutEvent({ type: 'tab-next' }); + emitKeyboardShortcutEvent({ action: 'nextTab' }); expect(docsService.open).not.toHaveBeenCalled(); }); diff --git a/web/packages/teleterm/src/ui/TabHost/useTabShortcuts.ts b/web/packages/teleterm/src/ui/TabHost/useTabShortcuts.ts index 36afb53ee20d0..74f14b962d80c 100644 --- a/web/packages/teleterm/src/ui/TabHost/useTabShortcuts.ts +++ b/web/packages/teleterm/src/ui/TabHost/useTabShortcuts.ts @@ -78,18 +78,18 @@ function buildTabsShortcuts( documentService.open(allDocuments[indexToOpen].uri); }; return { - 'tab-1': handleTabIndex(0), - 'tab-2': handleTabIndex(1), - 'tab-3': handleTabIndex(2), - 'tab-4': handleTabIndex(3), - 'tab-5': handleTabIndex(4), - 'tab-6': handleTabIndex(5), - 'tab-7': handleTabIndex(6), - 'tab-8': handleTabIndex(7), - 'tab-9': handleTabIndex(8), - 'tab-close': handleActiveTabClose, - 'tab-previous': handleTabSwitch('previous'), - 'tab-next': handleTabSwitch('next'), - 'tab-new': openClusterTab, + tab1: handleTabIndex(0), + tab2: handleTabIndex(1), + tab3: handleTabIndex(2), + tab4: handleTabIndex(3), + tab5: handleTabIndex(4), + tab6: handleTabIndex(5), + tab7: handleTabIndex(6), + tab8: handleTabIndex(7), + tab9: handleTabIndex(8), + closeTab: handleActiveTabClose, + previousTab: handleTabSwitch('previous'), + nextTab: handleTabSwitch('next'), + newTab: openClusterTab, }; } diff --git a/web/packages/teleterm/src/ui/TopBar/Clusters/ClusterSelector/ClusterSelector.tsx b/web/packages/teleterm/src/ui/TopBar/Clusters/ClusterSelector/ClusterSelector.tsx index 66f2bfd635e75..4342cd61bfa11 100644 --- a/web/packages/teleterm/src/ui/TopBar/Clusters/ClusterSelector/ClusterSelector.tsx +++ b/web/packages/teleterm/src/ui/TopBar/Clusters/ClusterSelector/ClusterSelector.tsx @@ -30,7 +30,7 @@ interface ClusterSelectorProps { export const ClusterSelector = forwardRef( (props, ref) => { - const { getLabelWithShortcut } = useKeyboardShortcutFormatters(); + const { getLabelWithAccelerator } = useKeyboardShortcutFormatters(); const SortIcon = props.isOpened ? SortAsc : SortDesc; const text = props.clusterName || 'Select Cluster'; @@ -40,9 +40,9 @@ export const ClusterSelector = forwardRef( onClick={props.onClick} isOpened={props.isOpened} isClusterSelected={!!props.clusterName} - title={getLabelWithShortcut( + title={getLabelWithAccelerator( [props.clusterName, 'Open Clusters'].filter(Boolean).join('\n'), - 'toggle-clusters' + 'openClusters' )} > ({ - 'toggle-clusters': togglePopover, + openClusters: togglePopover, }), [togglePopover] ) diff --git a/web/packages/teleterm/src/ui/TopBar/Connections/Connections.tsx b/web/packages/teleterm/src/ui/TopBar/Connections/Connections.tsx index 28ce96225ab8e..73fd1007a0a11 100644 --- a/web/packages/teleterm/src/ui/TopBar/Connections/Connections.tsx +++ b/web/packages/teleterm/src/ui/TopBar/Connections/Connections.tsx @@ -45,7 +45,7 @@ export function Connections() { useKeyboardShortcuts( useMemo( () => ({ - 'toggle-connections': togglePopover, + openConnections: togglePopover, }), [togglePopover] ) diff --git a/web/packages/teleterm/src/ui/TopBar/Connections/ConnectionsIcon/ConnectionsIcon.tsx b/web/packages/teleterm/src/ui/TopBar/Connections/ConnectionsIcon/ConnectionsIcon.tsx index c1cd24bacbd8b..cdae59d4a4ee0 100644 --- a/web/packages/teleterm/src/ui/TopBar/Connections/ConnectionsIcon/ConnectionsIcon.tsx +++ b/web/packages/teleterm/src/ui/TopBar/Connections/ConnectionsIcon/ConnectionsIcon.tsx @@ -31,7 +31,7 @@ interface ConnectionsIconProps { export const ConnectionsIcon = forwardRef( (props, ref) => { - const { getLabelWithShortcut } = useKeyboardShortcutFormatters(); + const { getLabelWithAccelerator } = useKeyboardShortcutFormatters(); return ( ( kind="secondary" size="small" m="auto" - title={getLabelWithShortcut('Open Connections', 'toggle-connections')} + title={getLabelWithAccelerator('Open Connections', 'openConnections')} > diff --git a/web/packages/teleterm/src/ui/TopBar/Identity/Identity.tsx b/web/packages/teleterm/src/ui/TopBar/Identity/Identity.tsx index 80722fdd1071a..831a87ea699c7 100644 --- a/web/packages/teleterm/src/ui/TopBar/Identity/Identity.tsx +++ b/web/packages/teleterm/src/ui/TopBar/Identity/Identity.tsx @@ -45,23 +45,23 @@ export function IdentityContainer() { logout, addCluster, } = useIdentity(); - const { getLabelWithShortcut } = useKeyboardShortcutFormatters(); + const { getLabelWithAccelerator } = useKeyboardShortcutFormatters(); const presenterRef = useRef(); useKeyboardShortcuts( useMemo( () => ({ - 'toggle-identity': presenterRef.current?.togglePopover, + openProfiles: presenterRef.current?.togglePopover, }), [presenterRef.current?.togglePopover] ) ); const makeTitle = (userWithClusterName: string | undefined) => - getLabelWithShortcut( + getLabelWithAccelerator( [userWithClusterName, 'Open Profiles'].filter(Boolean).join('\n'), - 'toggle-identity' + 'openProfiles' ); return ( diff --git a/web/packages/teleterm/src/ui/services/keyboardShortcuts/keyboardShortcutsService.test.ts b/web/packages/teleterm/src/ui/services/keyboardShortcuts/keyboardShortcutsService.test.ts index 91a3bf25634a0..f64a34cdd22b4 100644 --- a/web/packages/teleterm/src/ui/services/keyboardShortcuts/keyboardShortcutsService.test.ts +++ b/web/packages/teleterm/src/ui/services/keyboardShortcuts/keyboardShortcutsService.test.ts @@ -21,7 +21,7 @@ import { KeyboardShortcutsService } from './keyboardShortcutsService'; test('call subscriber on event', () => { const { subscriber } = getTestSetup(); dispatchEventCommand1(); - expect(subscriber).toHaveBeenCalledWith({ type: 'tab-1' }); + expect(subscriber).toHaveBeenCalledWith({ action: 'tab1' }); }); test('do not call subscriber on unknown event', () => { @@ -42,7 +42,7 @@ test('do not call subscriber after it has been unsubscribed', () => { function getTestSetup() { const service = new KeyboardShortcutsService( 'darwin', - createMockConfigService({ 'keymap.tab1': 'Command-1' }) + createMockConfigService({ 'keymap.tab1': 'Command+1' }) ); const subscriber = jest.fn(); service.subscribeToEvents(subscriber); diff --git a/web/packages/teleterm/src/ui/services/keyboardShortcuts/keyboardShortcutsService.ts b/web/packages/teleterm/src/ui/services/keyboardShortcuts/keyboardShortcutsService.ts index 1be88de80b3ba..07afc5081f0ba 100644 --- a/web/packages/teleterm/src/ui/services/keyboardShortcuts/keyboardShortcutsService.ts +++ b/web/packages/teleterm/src/ui/services/keyboardShortcuts/keyboardShortcutsService.ts @@ -16,8 +16,7 @@ import { Platform } from 'teleterm/mainProcess/types'; import { - KeyboardShortcutsConfig, - KeyboardShortcutType, + KeyboardShortcutAction, ConfigService, } from 'teleterm/services/config'; @@ -28,34 +27,36 @@ import { export class KeyboardShortcutsService { private eventsSubscribers = new Set(); - private keysToShortcuts = new Map(); - private readonly shortcutsConfig: Record; + private readonly acceleratorsToActions = new Map< + string, + KeyboardShortcutAction + >(); + private readonly shortcutsConfig: Record; constructor( private platform: Platform, private configService: ConfigService ) { this.shortcutsConfig = { - 'tab-1': this.configService.get('keymap.tab1').value, - 'tab-2': this.configService.get('keymap.tab2').value, - 'tab-3': this.configService.get('keymap.tab3').value, - 'tab-4': this.configService.get('keymap.tab4').value, - 'tab-5': this.configService.get('keymap.tab5').value, - 'tab-6': this.configService.get('keymap.tab6').value, - 'tab-7': this.configService.get('keymap.tab7').value, - 'tab-8': this.configService.get('keymap.tab8').value, - 'tab-9': this.configService.get('keymap.tab9').value, - 'tab-close': this.configService.get('keymap.tabClose').value, - 'tab-previous': this.configService.get('keymap.tabPrevious').value, - 'tab-next': this.configService.get('keymap.tabNext').value, - 'tab-new': this.configService.get('keymap.tabNew').value, - 'open-quick-input': this.configService.get('keymap.openQuickInput').value, - 'toggle-connections': this.configService.get('keymap.toggleConnections') - .value, - 'toggle-clusters': this.configService.get('keymap.toggleClusters').value, - 'toggle-identity': this.configService.get('keymap.toggleIdentity').value, + tab1: this.configService.get('keymap.tab1').value, + tab2: this.configService.get('keymap.tab2').value, + tab3: this.configService.get('keymap.tab3').value, + tab4: this.configService.get('keymap.tab4').value, + tab5: this.configService.get('keymap.tab5').value, + tab6: this.configService.get('keymap.tab6').value, + tab7: this.configService.get('keymap.tab7').value, + tab8: this.configService.get('keymap.tab8').value, + tab9: this.configService.get('keymap.tab9').value, + closeTab: this.configService.get('keymap.closeTab').value, + previousTab: this.configService.get('keymap.previousTab').value, + nextTab: this.configService.get('keymap.nextTab').value, + newTab: this.configService.get('keymap.newTab').value, + openQuickInput: this.configService.get('keymap.openQuickInput').value, + openConnections: this.configService.get('keymap.openConnections').value, + openClusters: this.configService.get('keymap.openClusters').value, + openProfiles: this.configService.get('keymap.openProfiles').value, }; - this.recalculateKeysToShortcuts(this.shortcutsConfig); + this.acceleratorsToActions = mapAcceleratorsToActions(this.shortcutsConfig); this.attachKeydownHandler(); } @@ -73,14 +74,14 @@ export class KeyboardShortcutsService { private attachKeydownHandler(): void { const handleKeydown = (event: KeyboardEvent): void => { - const shortcutType = this.getShortcut(event); - if (!shortcutType) { + const shortcutAction = this.getShortcutAction(event); + if (!shortcutAction) { return; } event.preventDefault(); event.stopPropagation(); - this.notifyEventsSubscribers({ type: shortcutType }); + this.notifyEventsSubscribers({ action: shortcutAction }); }; window.addEventListener('keydown', handleKeydown, { @@ -88,15 +89,17 @@ export class KeyboardShortcutsService { }); } - private getShortcut(event: KeyboardEvent): KeyboardShortcutType | undefined { + private getShortcutAction( + event: KeyboardEvent + ): KeyboardShortcutAction | undefined { const getEventKey = () => event.key.length === 1 ? event.key.toUpperCase() : event.key; - const key = [...this.getPlatformModifierKeys(event), getEventKey()] + const accelerator = [...this.getPlatformModifierKeys(event), getEventKey()] .filter(Boolean) - .join('-'); + .join('+'); - return this.keysToShortcuts.get(key); + return this.acceleratorsToActions.get(accelerator); } private getPlatformModifierKeys(event: KeyboardEvent): string[] { @@ -117,19 +120,19 @@ export class KeyboardShortcutsService { } } - /** - * Inverts shortcuts-keys pairs to allow accessing shortcut by a key - */ - private recalculateKeysToShortcuts( - toInvert: Partial - ): void { - this.keysToShortcuts.clear(); - Object.entries(toInvert).forEach(([shortcutType, key]) => { - this.keysToShortcuts.set(key, shortcutType as KeyboardShortcutType); - }); - } - private notifyEventsSubscribers(event: KeyboardShortcutEvent): void { this.eventsSubscribers.forEach(subscriber => subscriber(event)); } } + +/** Inverts shortcuts-keys pairs to allow accessing shortcut by an accelerator. */ +function mapAcceleratorsToActions( + shortcutsConfig: Record +): Map { + const acceleratorsToActions = new Map(); + Object.entries(shortcutsConfig).forEach(([action, accelerator]) => { + acceleratorsToActions.set(accelerator, action as KeyboardShortcutAction); + }); + + return acceleratorsToActions; +} diff --git a/web/packages/teleterm/src/ui/services/keyboardShortcuts/types.ts b/web/packages/teleterm/src/ui/services/keyboardShortcuts/types.ts index ce6142925cbb9..b5fa6b864475b 100644 --- a/web/packages/teleterm/src/ui/services/keyboardShortcuts/types.ts +++ b/web/packages/teleterm/src/ui/services/keyboardShortcuts/types.ts @@ -14,10 +14,10 @@ * limitations under the License. */ -import { KeyboardShortcutType } from 'teleterm/services/config'; +import { KeyboardShortcutAction } from 'teleterm/services/config'; export interface KeyboardShortcutEvent { - type: KeyboardShortcutType; + action: KeyboardShortcutAction; } export type KeyboardShortcutEventSubscriber = ( @@ -25,5 +25,5 @@ export type KeyboardShortcutEventSubscriber = ( ) => void; export type KeyboardShortcutHandlers = Partial< - Record void> + Record void> >; diff --git a/web/packages/teleterm/src/ui/services/keyboardShortcuts/useKeyboardShortcutFormatters.ts b/web/packages/teleterm/src/ui/services/keyboardShortcuts/useKeyboardShortcutFormatters.ts index 94e232eed4ef4..5d929404aef77 100644 --- a/web/packages/teleterm/src/ui/services/keyboardShortcuts/useKeyboardShortcutFormatters.ts +++ b/web/packages/teleterm/src/ui/services/keyboardShortcuts/useKeyboardShortcutFormatters.ts @@ -14,19 +14,19 @@ * limitations under the License. */ -import { KeyboardShortcutType } from '../../../services/config'; +import { KeyboardShortcutAction } from '../../../services/config'; import { useAppContext } from '../../appContextProvider'; import { Platform } from '../../../mainProcess/types'; interface KeyboardShortcutFormatters { - getLabelWithShortcut( + getLabelWithAccelerator( label: string, - shortcutKey: KeyboardShortcutType, + action: KeyboardShortcutAction, options?: KeyboardShortcutFormattingOptions ): string; - getShortcut( - shortcutKey: KeyboardShortcutType, + getAccelerator( + action: KeyboardShortcutAction, options?: KeyboardShortcutFormattingOptions ): string; } @@ -41,41 +41,40 @@ export function useKeyboardShortcutFormatters(): KeyboardShortcutFormatters { const keyboardShortcuts = keyboardShortcutsService.getShortcutsConfig(); return { - getLabelWithShortcut(label, shortcutKey, options) { - const formattedShortcut = formatKeyboardShortcut({ + getLabelWithAccelerator(label, action, options) { + const formattedAccelerator = formatAccelerator({ platform, - shortcutValue: keyboardShortcuts[shortcutKey], + accelerator: keyboardShortcuts[action], ...options, }); - return `${label} (${formattedShortcut})`; + return `${label} (${formattedAccelerator})`; }, - getShortcut(shortcutKey, options) { - return formatKeyboardShortcut({ + getAccelerator(action, options) { + return formatAccelerator({ platform, - shortcutValue: keyboardShortcuts[shortcutKey], + accelerator: keyboardShortcuts[action], ...options, }); }, }; } -function formatKeyboardShortcut(options: { +function formatAccelerator(options: { platform: Platform; - shortcutValue: string; + accelerator: string; useWhitespaceSeparator?: boolean; }): string { switch (options.platform) { case 'darwin': - return options.shortcutValue - .replace('-', options.useWhitespaceSeparator ? ' ' : '') + return options.accelerator + .replaceAll('+', options.useWhitespaceSeparator ? ' ' : '') .replace('Command', '⌘') .replace('Control', '⌃') .replace('Option', '⌥') .replace('Shift', '⇧'); default: - return options.shortcutValue.replace( - '-', - options.useWhitespaceSeparator ? ' + ' : '+' - ); + return options.useWhitespaceSeparator + ? options.accelerator.replaceAll('+', ' + ') + : options.accelerator; } } diff --git a/web/packages/teleterm/src/ui/services/keyboardShortcuts/useKeyboardShortcuts.test.tsx b/web/packages/teleterm/src/ui/services/keyboardShortcuts/useKeyboardShortcuts.test.tsx index 59b18206a588f..84477287aa340 100644 --- a/web/packages/teleterm/src/ui/services/keyboardShortcuts/useKeyboardShortcuts.test.tsx +++ b/web/packages/teleterm/src/ui/services/keyboardShortcuts/useKeyboardShortcuts.test.tsx @@ -30,9 +30,9 @@ import { KeyboardShortcutEventSubscriber } from './types'; test('call handler on its event type', () => { const { handler, getEventEmitter, wrapper } = getTestSetup(); - renderHook(() => useKeyboardShortcuts({ 'tab-1': handler }), { wrapper }); + renderHook(() => useKeyboardShortcuts({ tab1: handler }), { wrapper }); const emitEvent = getEventEmitter(); - emitEvent({ type: 'tab-1' }); + emitEvent({ action: 'tab1' }); expect(handler).toHaveBeenCalled(); }); @@ -40,9 +40,9 @@ test('call handler on its event type', () => { test('do not call handler on other event type', () => { const { handler, getEventEmitter, wrapper } = getTestSetup(); - renderHook(() => useKeyboardShortcuts({ 'tab-1': handler }), { wrapper }); + renderHook(() => useKeyboardShortcuts({ tab1: handler }), { wrapper }); const emitEvent = getEventEmitter(); - emitEvent({ type: 'tab-2' }); + emitEvent({ action: 'tab2' }); expect(handler).not.toHaveBeenCalled(); }); diff --git a/web/packages/teleterm/src/ui/services/keyboardShortcuts/useKeyboardShortcuts.ts b/web/packages/teleterm/src/ui/services/keyboardShortcuts/useKeyboardShortcuts.ts index b944a57b0fd13..94162b4f4eaca 100644 --- a/web/packages/teleterm/src/ui/services/keyboardShortcuts/useKeyboardShortcuts.ts +++ b/web/packages/teleterm/src/ui/services/keyboardShortcuts/useKeyboardShortcuts.ts @@ -28,11 +28,11 @@ export function useKeyboardShortcuts(handlers: KeyboardShortcutHandlers): void { useEffect(() => { const handleShortcutEvent: KeyboardShortcutEventSubscriber = event => { - handlers[event.type]?.(); + handlers[event.action]?.(); }; keyboardShortcutsService.subscribeToEvents(handleShortcutEvent); return () => keyboardShortcutsService.unsubscribeFromEvents(handleShortcutEvent); - }, [handlers]); + }, [handlers, keyboardShortcutsService]); }