Skip to content

Commit 824dce7

Browse files
feat(desktop): url focus and mru tab shortcuts (hoppscotch#5683)
Co-authored-by: James George <[email protected]>
1 parent 745fc9d commit 824dce7

File tree

14 files changed

+508
-6
lines changed

14 files changed

+508
-6
lines changed

packages/hoppscotch-common/locales/en.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1412,7 +1412,8 @@
14121412
"send_request": "Send Request",
14131413
"share_request": "Share Request",
14141414
"show_code": "Generate code snippet",
1415-
"title": "Request"
1415+
"title": "Request",
1416+
"focus_url": "Focus URL bar"
14161417
},
14171418
"response": {
14181419
"copy": "Copy response to clipboard",
@@ -1427,7 +1428,9 @@
14271428
"next_tab": "Next Tab",
14281429
"previous_tab": "Previous Tab",
14291430
"first_tab": "Switch to First Tab",
1430-
"last_tab": "Switch to Last Tab"
1431+
"last_tab": "Switch to Last Tab",
1432+
"mru_switch": "Switch to recent tab (MRU)",
1433+
"mru_switch_reverse": "Switch to previous recent tab (MRU)"
14311434
},
14321435
"theme": {
14331436
"black": "Switch theme to Black Mode",
@@ -1524,6 +1527,8 @@
15241527
"previous": "Switch to previous tab",
15251528
"switch_to_first": "Switch to first tab",
15261529
"switch_to_last": "Switch to last tab",
1530+
"mru_switch": "Switch to recent tab",
1531+
"mru_switch_reverse": "Switch to previous recent tab",
15271532
"title": "Tabs"
15281533
},
15291534
"workspace": {

packages/hoppscotch-common/src/components/http/Request.vue

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
class="flex flex-1 whitespace-nowrap rounded-r border-l border-divider bg-primaryLight transition"
5757
>
5858
<SmartEnvInput
59+
ref="urlInput"
5960
v-model="tab.document.request.endpoint"
6061
:placeholder="`${t('request.url_placeholder')}`"
6162
:auto-complete-source="userHistories"
@@ -322,6 +323,7 @@ const show = ref<any | null>(null)
322323
const clearAll = ref<any | null>(null)
323324
const copyRequestAction = ref<any | null>(null)
324325
const saveRequestAction = ref<any | null>(null)
326+
const urlInput = ref<{ focus: () => void } | null>(null)
325327
326328
const history = useReadonlyStream<RESTHistoryEntry[]>(restHistory$, [])
327329
@@ -667,6 +669,10 @@ defineActionHandler("request.show-code", () => {
667669
showCodegenModal.value = true
668670
})
669671
672+
defineActionHandler("request.focus-url", () => {
673+
urlInput.value?.focus()
674+
})
675+
670676
const isCustomMethod = computed(() => {
671677
return (
672678
tab.value.document.request.method === "CUSTOM" ||

packages/hoppscotch-common/src/components/smart/EnvInput.vue

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,18 @@ const triggerTextSelection = () => {
658658
})
659659
})
660660
}
661+
662+
/**
663+
* Focuses the input editor
664+
*/
665+
const focusInput = () => {
666+
view.value?.focus()
667+
}
668+
669+
defineExpose({
670+
focus: focusInput,
671+
})
672+
661673
onMounted(() => {
662674
if (editor.value) {
663675
if (!view.value) initView(editor.value)

packages/hoppscotch-common/src/helpers/actions.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ export type HoppAction =
7070
| "tab.switch-to-first" // Switch to first tab
7171
| "tab.switch-to-last" // Switch to last tab
7272
| "tab.reopen-closed" // Reopen recently closed tab
73+
| "tab.mru-switch" // Switch to MRU tab (Ctrl/Cmd+Alt+])
74+
| "tab.mru-switch-reverse" // Switch to previous MRU tab (Ctrl/Cmd+Alt+[)
75+
| "request.focus-url" // Focus the URL bar
7376
| "collection.new" // Create root collection
7477
| "flyouts.chat.open" // Shows the keybinds flyout
7578
| "flyouts.keybinds.toggle" // Shows the keybinds flyout

packages/hoppscotch-common/src/helpers/keybindings.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ type Key =
4444
| "u" | "v" | "w" | "x" | "y" | "z" | "0" | "1" | "2" | "3"
4545
| "4" | "5" | "6" | "7" | "8" | "9" | "up" | "down" | "left"
4646
| "right" | "/" | "?" | "." | "enter" | "tab" | "delete" | "backspace"
47+
| "[" | "]"
4748
/* eslint-enable */
4849

4950
type ModifierBasedShortcutKey = `${ModifierKeys}-${Key}`
@@ -108,6 +109,9 @@ const desktopBindings: {
108109
"ctrl-alt-0": "tab.switch-to-last",
109110
"ctrl-alt-9": "tab.switch-to-first",
110111
"ctrl-q": "app.quit",
112+
"ctrl-alt-u": "request.focus-url",
113+
"ctrl-alt-]": "tab.mru-switch",
114+
"ctrl-alt-[": "tab.mru-switch-reverse",
111115
}
112116

113117
/**
@@ -314,6 +318,8 @@ function getPressedKey(ev: KeyboardEvent): Key | null {
314318
// Check if slash, period or enter
315319
if (key === "/" || key === "." || key === "enter") return key
316320

321+
if (key === "[" || key === "]") return key
322+
317323
// If no other cases match, this is not a valid key
318324
return null
319325
}

packages/hoppscotch-common/src/helpers/shortcuts.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,11 @@ export function getShortcuts(t: (x: string) => string): ShortcutDef[] {
174174

175175
// Desktop-only shortcuts
176176
const desktopShortcuts: ShortcutDef[] = [
177+
{
178+
keys: [getPlatformSpecialKey(), getPlatformAlternateKey(), "U"],
179+
label: t("shortcut.request.focus_url"),
180+
section: t("shortcut.request.title"),
181+
},
177182
{
178183
keys: [getPlatformSpecialKey(), "T"],
179184
label: t("shortcut.tabs.new_tab"),
@@ -204,6 +209,16 @@ export function getShortcuts(t: (x: string) => string): ShortcutDef[] {
204209
label: t("shortcut.tabs.last_tab"),
205210
section: t("shortcut.tabs.title"),
206211
},
212+
{
213+
keys: [getPlatformSpecialKey(), getPlatformAlternateKey(), "]"],
214+
label: t("shortcut.tabs.mru_switch"),
215+
section: t("shortcut.tabs.title"),
216+
},
217+
{
218+
keys: [getPlatformSpecialKey(), getPlatformAlternateKey(), "["],
219+
label: t("shortcut.tabs.mru_switch_reverse"),
220+
section: t("shortcut.tabs.title"),
221+
},
207222
]
208223

209224
// Return base shortcuts + platform-specific shortcuts

packages/hoppscotch-common/src/pages/graphql.vue

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,4 +270,12 @@ defineActionHandler("tab.switch-to-last", () => {
270270
defineActionHandler("tab.reopen-closed", () => {
271271
tabs.reopenClosedTab()
272272
})
273+
274+
defineActionHandler("tab.mru-switch", () => {
275+
tabs.goToMRUTab()
276+
})
277+
278+
defineActionHandler("tab.mru-switch-reverse", () => {
279+
tabs.goToPreviousMRUTab()
280+
})
273281
</script>

packages/hoppscotch-common/src/pages/index.vue

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,14 @@ defineActionHandler("tab.reopen-closed", () => {
448448
tabs.reopenClosedTab()
449449
})
450450
451+
defineActionHandler("tab.mru-switch", () => {
452+
tabs.goToMRUTab()
453+
})
454+
455+
defineActionHandler("tab.mru-switch-reverse", () => {
456+
tabs.goToPreviousMRUTab()
457+
})
458+
451459
useService(RequestInspectorService)
452460
useService(EnvironmentInspectorService)
453461
useService(ResponseInspectorService)

packages/hoppscotch-common/src/services/spotlight/searchers/tab.searcher.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,31 @@ export class TabSpotlightSearcherService extends StaticSpotlightSearcherService<
146146
this.isOnlyTab.value
147147
),
148148
},
149+
tab_mru_switch: {
150+
text: [this.t("spotlight.tab.title"), this.t("spotlight.tab.mru_switch")],
151+
alternates: ["tab", "recent", "mru", "switch"],
152+
icon: markRaw(IconArrowRight),
153+
excludeFromSearch: computed(
154+
() =>
155+
!this.showAction.value ||
156+
!this.isDesktopMode.value ||
157+
this.isOnlyTab.value
158+
),
159+
},
160+
tab_mru_switch_reverse: {
161+
text: [
162+
this.t("spotlight.tab.title"),
163+
this.t("spotlight.tab.mru_switch_reverse"),
164+
],
165+
alternates: ["tab", "recent", "mru", "previous", "switch"],
166+
icon: markRaw(IconArrowLeft),
167+
excludeFromSearch: computed(
168+
() =>
169+
!this.showAction.value ||
170+
!this.isDesktopMode.value ||
171+
this.isOnlyTab.value
172+
),
173+
},
149174
})
150175

151176
// TODO: Constructors are no longer recommended as of dioc > 3, use onServiceInit instead
@@ -184,5 +209,7 @@ export class TabSpotlightSearcherService extends StaticSpotlightSearcherService<
184209
if (id === "tab_next") invokeAction("tab.next")
185210
if (id === "tab_switch_to_first") invokeAction("tab.switch-to-first")
186211
if (id === "tab_switch_to_last") invokeAction("tab.switch-to-last")
212+
if (id === "tab_mru_switch") invokeAction("tab.mru-switch")
213+
if (id === "tab_mru_switch_reverse") invokeAction("tab.mru-switch-reverse")
187214
}
188215
}

0 commit comments

Comments
 (0)