Skip to content

Commit 1a9ca96

Browse files
authored
feat: add shortcut for navigate and reopen tabs (Kong#9642)
1 parent 405b3c0 commit 1a9ca96

File tree

5 files changed

+219
-74
lines changed

5 files changed

+219
-74
lines changed

packages/insomnia/src/common/hotkeys.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ export const keyboardShortcutDescriptions: Record<KeyboardShortcut, string> = {
3636
beautifyRequestBody: 'Beautify Active Code Editors',
3737
graphql_explorer_focus_filter: 'Focus GraphQL Explorer Filter',
3838
close_tab: 'Close Tab',
39+
tab_nextTab: 'Next Tab',
40+
tab_previousTab: 'Previous Tab',
41+
tab_reopenClosedTab: 'Reopen Closed Tab',
3942
};
4043

4144
/**
@@ -168,6 +171,18 @@ const defaultRegistry: HotKeyRegistry = {
168171
macKeys: [{ meta: true, keyCode: keyboardKeys.w.keyCode }],
169172
winLinuxKeys: [{ ctrl: true, keyCode: keyboardKeys.w.keyCode }],
170173
},
174+
tab_nextTab: {
175+
macKeys: [{ alt: true, meta: true, keyCode: keyboardKeys.rightarrow.keyCode }],
176+
winLinuxKeys: [{ ctrl: true, keyCode: keyboardKeys.tab.keyCode }],
177+
},
178+
tab_previousTab: {
179+
macKeys: [{ alt: true, meta: true, keyCode: keyboardKeys.leftarrow.keyCode }],
180+
winLinuxKeys: [{ ctrl: true, shift: true, keyCode: keyboardKeys.tab.keyCode }],
181+
},
182+
tab_reopenClosedTab: {
183+
macKeys: [{ shift: true, meta: true, keyCode: keyboardKeys.t.keyCode }],
184+
winLinuxKeys: [{ ctrl: true, shift: true, keyCode: keyboardKeys.t.keyCode }],
185+
},
171186
};
172187

173188
/**

packages/insomnia/src/common/settings.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,10 @@ export type KeyboardShortcut =
5656
| 'environment_showVariableSourceAndValue'
5757
| 'beautifyRequestBody'
5858
| 'graphql_explorer_focus_filter'
59-
| 'close_tab';
59+
| 'close_tab'
60+
| 'tab_nextTab'
61+
| 'tab_previousTab'
62+
| 'tab_reopenClosedTab';
6063

6164
/**
6265
* The collection of defined hotkeys.

packages/insomnia/src/ui/components/keydown-binder.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@ export function useKeyboardShortcuts(
4646
.map(({ tinyKeyString, action }) => [tinyKeyString, action]),
4747
);
4848

49-
const unsubscribe = tinykeys(target, keyBindingMap);
49+
const unsubscribe = tinykeys(target, keyBindingMap, {
50+
capture: true, // use capture phase to ensure hotkeys can be triggered to avoid being blocked by aria-components
51+
});
5052
return unsubscribe;
5153
}, [hotKeyRegistry, listeners, getTarget]);
5254
}

packages/insomnia/src/ui/components/tabs/tab-list.tsx

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { INSOMNIA_TAB_HEIGHT } from '../../constant';
2727
import { useInsomniaTabContext } from '../../context/app/insomnia-tab-context';
2828
import { type Size, useResizeObserver } from '../../hooks/use-resize-observer';
2929
import { Icon } from '../icon';
30+
import { useDocBodyKeyboardShortcuts } from '../keydown-binder';
3031
import { AddRequestToCollectionModal } from '../modals/add-request-to-collection-modal';
3132
import { formatMethodName, getRequestMethodShortHand } from '../tags/method-tag';
3233
import { type BaseTab, InsomniaTab, type TabType } from './tab';
@@ -79,10 +80,29 @@ export const OrganizationTabList = ({ showActiveStatus = true, currentPage = ''
7980
moveBefore,
8081
batchUpdateTabs,
8182
currentOrgTabs,
83+
goToNextTab,
84+
goToPreviousTab,
85+
reopenClosedTab,
8286
} = useInsomniaTabContext();
8387

8488
const { tabList, activeTabId } = currentOrgTabs;
8589

90+
// Register keyboard shortcuts for tab navigation
91+
useDocBodyKeyboardShortcuts({
92+
tab_nextTab: event => {
93+
event.preventDefault();
94+
goToNextTab?.();
95+
},
96+
tab_previousTab: event => {
97+
event.preventDefault();
98+
goToPreviousTab?.();
99+
},
100+
tab_reopenClosedTab: event => {
101+
event.preventDefault();
102+
reopenClosedTab?.();
103+
},
104+
});
105+
86106
const handleSelectionChange = (keys: Selection) => {
87107
if (keys !== 'all') {
88108
const key = [...keys.values()]?.[0] as string;
@@ -115,17 +135,16 @@ export const OrganizationTabList = ({ showActiveStatus = true, currentPage = ''
115135
(docId: string, docType: string) => {
116136
if (docType === models.project.type) {
117137
// delete all tabs of this project
118-
closeAllTabsUnderProject?.(docId);
119-
}
120-
if (docType === models.workspace.type) {
138+
closeAllTabsUnderProject?.(docId, { removeFromClosedTabs: true });
139+
} else if (docType === models.workspace.type) {
121140
// delete all tabs of this workspace
122-
closeAllTabsUnderWorkspace?.(docId);
141+
closeAllTabsUnderWorkspace?.(docId, { removeFromClosedTabs: true });
123142
} else if (docType === models.requestGroup.type) {
124143
// when delete a folder, we need also delete the corresponding folder runner tab(if exists)
125-
batchCloseTabs?.([docId, `runner_${docId}`]);
144+
batchCloseTabs?.([docId, `runner_${docId}`], { removeFromClosedTabs: true });
126145
} else {
127146
// delete tab by id
128-
closeTabById(docId);
147+
closeTabById(docId, { removeFromClosedTabs: true });
129148
}
130149
},
131150
[batchCloseTabs, closeAllTabsUnderProject, closeAllTabsUnderWorkspace, closeTabById],

0 commit comments

Comments
 (0)