feat(tabs): add close tabs to the left action
This commit is contained in:
1 parent
40a806a24a
commit
662037295c
11 files changed
+67
No files matched your search
@@ -209,6 +209,20 @@ function closeTabsToRightFromTab(tab: QueryTab) {
|
||||
});
|
||||
}
|
||||
|
||||
function tabsToLeftInGroup(tab: QueryTab) {
|
||||
const groupedTabs = tab.pinned ? fixedTabs.value : regularTabs.value;
|
||||
const targetIndex = groupedTabs.findIndex((item) => item.id === tab.id);
|
||||
return targetIndex < 0 ? [] : groupedTabs.slice(0, targetIndex);
|
||||
}
|
||||
|
||||
function hasTabsToLeft(tab: QueryTab) {
|
||||
return tabsToLeftInGroup(tab).length > 0;
|
||||
}
|
||||
|
||||
function closeTabsToLeftFromTab(tab: QueryTab) {
|
||||
queryStore.closeLeftTabs(tab.id);
|
||||
}
|
||||
|
||||
function hasSpecialRegularSurfaceToRight(surface: SpecialRegularSurface) {
|
||||
return surface === "settings" && !!props.driverStoreOpen;
|
||||
}
|
||||
@@ -345,6 +359,12 @@ function getTabMenuItems(tab: QueryTab): ContextMenuItem[] {
|
||||
icon: X,
|
||||
shortcut: settingsStore.editorSettings.shortcuts.closeOtherTabs,
|
||||
},
|
||||
{
|
||||
label: t("contextMenu.closeLeftTabs"),
|
||||
action: () => closeTabsToLeftFromTab(tab),
|
||||
disabled: !hasTabsToLeft(tab),
|
||||
icon: X,
|
||||
},
|
||||
{
|
||||
label: t("contextMenu.closeRightTabs"),
|
||||
action: () => closeTabsToRightFromTab(tab),
|
||||
|
||||
@@ -108,6 +108,27 @@ describe("AppTabBar right-side close action", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("AppTabBar left-side close action", () => {
|
||||
it("places the action after close-other, before close-right, and disables it when the target has no tabs to its left", () => {
|
||||
expect(tabBarSource).toContain('label: t("contextMenu.closeLeftTabs")');
|
||||
expect(tabBarSource).toContain("action: () => closeTabsToLeftFromTab(tab)");
|
||||
expect(tabBarSource).toContain("disabled: !hasTabsToLeft(tab)");
|
||||
|
||||
const closeOtherPositions = [...tabBarSource.matchAll(/label: closeOtherLabel,/g)].map((match) => match.index);
|
||||
const closeLeftPositions = [...tabBarSource.matchAll(/label: t\("contextMenu\.closeLeftTabs"\),/g)].map((match) => match.index);
|
||||
const closeRightPositions = [...tabBarSource.matchAll(/label: t\("contextMenu\.closeRightTabs"\),/g)].map((match) => match.index);
|
||||
expect(closeOtherPositions).toHaveLength(2);
|
||||
// The special-surface menu has no left-side action: settings and the
|
||||
// driver store sit at the rightmost end of the tab bar, so nothing can be
|
||||
// to the left of them. Only the regular/pinned tab menu gets the item.
|
||||
expect(closeLeftPositions).toHaveLength(1);
|
||||
expect(closeRightPositions).toHaveLength(2);
|
||||
const closeLeftPosition = closeLeftPositions[0];
|
||||
expect(closeLeftPosition).toBeGreaterThan(closeOtherPositions[1]);
|
||||
expect(closeLeftPosition).toBeLessThan(closeRightPositions[1]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("AppTabBar special page selection", () => {
|
||||
it("shows the active settings or driver-manager tab with the same ring used by regular tabs", () => {
|
||||
expect(tabBarSource).toContain("function specialTabActiveStyle(active: boolean | undefined)");
|
||||
|
||||
@@ -2971,6 +2971,7 @@ export default {
|
||||
fullTabTitle: "Show Full Tab Titles",
|
||||
closeTab: "Close Tab",
|
||||
closeFixedTab: "Close Fixed Tab",
|
||||
closeLeftTabs: "Close Tabs to the Left",
|
||||
closeRightTabs: "Close Tabs to the Right",
|
||||
closeOtherTabs: "Close Other Tabs",
|
||||
closeOtherRegularTabs: "Close Other Regular Tabs",
|
||||
|
||||
@@ -3195,6 +3195,7 @@ export default withEnglishFallback({
|
||||
createFunction: "Nueva función",
|
||||
createTrigger: "Nuevo disparador",
|
||||
changeOpenMode: "Modificar modo de apertura",
|
||||
closeLeftTabs: "Cerrar pestañas a la izquierda",
|
||||
closeRightTabs: "Cerrar pestañas a la derecha",
|
||||
viewObject: "View",
|
||||
eventEditorTitle: "MySQL Event",
|
||||
|
||||
@@ -3193,6 +3193,7 @@ export default withEnglishFallback({
|
||||
createFunction: "Nuova funzione",
|
||||
createTrigger: "Nuovo trigger",
|
||||
changeOpenMode: "Modifica modalità apertura",
|
||||
closeLeftTabs: "Chiudi le schede a sinistra",
|
||||
closeRightTabs: "Chiudi le schede a destra",
|
||||
viewObject: "View",
|
||||
eventEditorTitle: "MySQL Event",
|
||||
|
||||
@@ -3219,6 +3219,7 @@ export default withEnglishFallback({
|
||||
createFunction: "新規関数",
|
||||
createTrigger: "新規トリガー",
|
||||
changeOpenMode: "開き方を変更",
|
||||
closeLeftTabs: "左側のタブを閉じる",
|
||||
closeRightTabs: "右側のタブを閉じる",
|
||||
viewObject: "View",
|
||||
eventEditorTitle: "MySQL Event",
|
||||
|
||||
@@ -2790,6 +2790,8 @@ export default withEnglishFallback({
|
||||
fullTabTitle: "전체 탭 제목 표시",
|
||||
closeTab: "탭 닫기",
|
||||
closeFixedTab: "고정 탭 닫기",
|
||||
closeLeftTabs: "왼쪽 탭 닫기",
|
||||
closeRightTabs: "오른쪽 탭 닫기",
|
||||
closeOtherTabs: "다른 탭 닫기",
|
||||
closeOtherRegularTabs: "다른 일반 탭 닫기",
|
||||
closeOtherFixedTabs: "다른 고정 탭 닫기",
|
||||
|
||||
@@ -3191,6 +3191,7 @@ export default withEnglishFallback({
|
||||
createFunction: "Nova função",
|
||||
createTrigger: "Novo gatilho",
|
||||
changeOpenMode: "Alterar modo de abertura",
|
||||
closeLeftTabs: "Fechar abas à esquerda",
|
||||
closeRightTabs: "Fechar abas à direita",
|
||||
viewObject: "View",
|
||||
eventEditorTitle: "MySQL Event",
|
||||
|
||||
@@ -2894,6 +2894,7 @@ export default withEnglishFallback({
|
||||
fullTabTitle: "完整标签标题",
|
||||
closeTab: "关闭标签页",
|
||||
closeFixedTab: "关闭固定标签页",
|
||||
closeLeftTabs: "关闭左侧标签页",
|
||||
closeRightTabs: "关闭右侧标签页",
|
||||
closeOtherTabs: "关闭其他标签页",
|
||||
closeOtherRegularTabs: "关闭其他普通标签页",
|
||||
|
||||
@@ -3192,6 +3192,7 @@ export default withEnglishFallback({
|
||||
createFunction: "新增函數",
|
||||
createTrigger: "新增觸發器",
|
||||
changeOpenMode: "修改開啟方式",
|
||||
closeLeftTabs: "關閉左側標籤頁",
|
||||
closeRightTabs: "關閉右側標籤頁",
|
||||
viewObject: "View",
|
||||
eventEditorTitle: "MySQL Event",
|
||||
|
||||
@@ -2858,6 +2858,22 @@ export const useQueryStore = defineStore("query", () => {
|
||||
);
|
||||
}
|
||||
|
||||
function closeLeftTabs(id: string, onComplete?: () => void) {
|
||||
const target = tabs.value.find((tab) => tab.id === id);
|
||||
if (!target) return;
|
||||
|
||||
const groupedTabs = tabs.value.filter((tab) => Boolean(tab.pinned) === Boolean(target.pinned));
|
||||
const targetIndex = groupedTabs.findIndex((tab) => tab.id === id);
|
||||
const ids = groupedTabs.slice(0, targetIndex).map((tab) => tab.id);
|
||||
if (ids.length === 0) {
|
||||
onComplete?.();
|
||||
return;
|
||||
}
|
||||
|
||||
const finalActiveTabId = activeTabId.value && !ids.includes(activeTabId.value) ? activeTabId.value : id;
|
||||
beginBatchClose(ids, finalActiveTabId, onComplete);
|
||||
}
|
||||
|
||||
function closeRightTabs(id: string, onComplete?: () => void) {
|
||||
const target = tabs.value.find((tab) => tab.id === id);
|
||||
if (!target) return;
|
||||
@@ -6813,6 +6829,7 @@ export const useQueryStore = defineStore("query", () => {
|
||||
discardTabChanges,
|
||||
requestAppCloseConfirmation,
|
||||
closeOtherTabs,
|
||||
closeLeftTabs,
|
||||
closeRightTabs,
|
||||
closeOtherRegularTabs,
|
||||
closeRegularTabs,
|
||||
|
||||
Reference in new issue
Block a user