feat(shortcuts): add configurable Close All Tabs action

This commit is contained in:
弈秋
2026-10-11 08:48:41 +08:00
committed by GitHub
parent 5cfdf10e5c
commit 67847fed2a
5 changed files with 46 additions and 1 deletions
+7
View File
@@ -117,6 +117,7 @@ import { restoreGlobalNavigationEntry } from "@/lib/navigation/globalNavigationE
import {
isBrowserReloadShortcut,
isBrowserTaskManagerShortcut,
isCloseAllTabsShortcut,
isCloseOtherTabsShortcut,
isCloseTabShortcut,
isCloseWindowShortcut,
@@ -4360,6 +4361,12 @@ async function handleKeydown(e: KeyboardEvent) {
appTabBarRef.value?.closeOtherActiveTabs();
return;
}
if (isCloseAllTabsShortcut(e, shortcuts)) {
e.preventDefault();
e.stopPropagation();
appTabBarRef.value?.closeAllTabs();
return;
}
if (isDisconnectAllActiveConnectionsShortcut(e, shortcuts)) {
e.preventDefault();
e.stopPropagation();
@@ -177,7 +177,12 @@ function closeOtherActiveTabs() {
queryStore.closeTab(activeTabId);
}
defineExpose({ closeOtherActiveTabs });
function closeAllTabs() {
closeSpecialRegularSurfaces();
queryStore.closeAllTabs();
}
defineExpose({ closeOtherActiveTabs, closeAllTabs });
function handleSaveAndClose() {
const id = queryStore.saveAndClosePendingTab();
@@ -1,4 +1,5 @@
import { describe, expect, it } from "vitest";
import { isCloseAllTabsShortcut } from "@/lib/editor/keyboardShortcuts";
import {
closeOtherTabsDefaultShortcut,
countShortcutConflictPairs,
@@ -291,6 +292,25 @@ describe("shortcutRegistry editor actions", () => {
expect(normalizeShortcutSettings({ closeWindow: "" }).closeWindow).toBe("");
});
it("registers closeAllTabs as an unbound global shortcut that users can assign", () => {
const definition = SHORTCUT_DEFINITIONS.find((item) => item.id === "closeAllTabs");
expect(definition).toMatchObject({
id: "closeAllTabs",
labelKey: "contextMenu.closeAllTabs",
scope: "global",
defaultShortcut: "",
});
// 无默认键位:保持未绑定状态,由用户在设置里自行分配
expect(DEFAULT_SHORTCUT_SETTINGS.closeAllTabs).toBe("");
expect(normalizeShortcutSettings({}).closeAllTabs).toBe("");
expect(normalizeShortcutSettings({ closeAllTabs: "Shift+Mod+Alt+W" }).closeAllTabs).toBe("Shift+Mod+Alt+W");
expect(normalizeShortcutSettings({ closeAllTabs: "" }).closeAllTabs).toBe("");
const event = { key: "w", shiftKey: true, metaKey: true, altKey: true };
// 显式分配后生效;默认未绑定时永不触发
expect(isCloseAllTabsShortcut(event, { closeAllTabs: "Shift+Mod+Alt+W" }, "MacIntel")).toBe(true);
expect(isCloseAllTabsShortcut(event, {}, "MacIntel")).toBe(false);
});
it("normalizes custom, cleared, and invalid modifier-only shortcuts", () => {
expect(normalizeShortcutSettings({ openDataInNewTab: "Shift" }).openDataInNewTab).toBe("Shift");
expect(normalizeShortcutSettings({ openDataInNewTab: "" }).openDataInNewTab).toBe("");
@@ -188,6 +188,10 @@ export function isCloseOtherTabsShortcut(event: ShortcutLikeEvent, shortcuts?: P
return matchesShortcut(event, actionShortcut("closeOtherTabs", shortcuts), platform);
}
export function isCloseAllTabsShortcut(event: ShortcutLikeEvent, shortcuts?: Partial<ShortcutSettings>, platform = globalThis.navigator?.platform || ""): boolean {
return matchesShortcut(event, actionShortcut("closeAllTabs", shortcuts), platform);
}
export function isCloseWindowShortcut(event: ShortcutLikeEvent, shortcuts?: Partial<ShortcutSettings>): boolean {
return matchesShortcut(event, actionShortcut("closeWindow", shortcuts));
}
@@ -52,6 +52,7 @@ export type ShortcutActionId =
| "openSettings"
| "closeTab"
| "closeOtherTabs"
| "closeAllTabs"
| "closeWindow"
| "focusSearch"
| "quickOpen"
@@ -477,6 +478,14 @@ export const SHORTCUT_DEFINITIONS: ShortcutDefinition[] = [
scope: "global",
defaultShortcut: closeOtherTabsDefaultShortcut(),
},
{
// VS Code's close-all-tabs chord (Cmd/Ctrl+K W) needs chord support the
// registry doesn't have, so this action ships unbound and stays optional.
id: "closeAllTabs",
labelKey: "contextMenu.closeAllTabs",
scope: "global",
defaultShortcut: "",
},
{
id: "closeWindow",
labelKey: "settings.shortcutCloseWindow",