From cd6ee718b6f3faa749dfe91e717f6cfd480c0bbd Mon Sep 17 00:00:00 2001 From: t8y2 <1156263951@qq.com> Date: Tue, 8 Sep 2026 17:49:32 +0800 Subject: [PATCH] fix(editor): optimize tab group rendering --- .../components/layout/EditorGroupTabBar.vue | 22 +++++++++++++------ .../EditorGroupTabBar.groups.spec.ts | 14 ++++++++++++ 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/apps/desktop/src/components/layout/EditorGroupTabBar.vue b/apps/desktop/src/components/layout/EditorGroupTabBar.vue index 3c8b7f799e..ed10e545fd 100644 --- a/apps/desktop/src/components/layout/EditorGroupTabBar.vue +++ b/apps/desktop/src/components/layout/EditorGroupTabBar.vue @@ -469,10 +469,13 @@ function isTabGroupCollapsed(tab: QueryTab) { return collapsedTabGroups.value.has(tabGroupId(tab)); } +const activeTabGroupId = computed(() => { + const activeTab = props.tabs.find((item) => isTabActive(item)); + return activeTab ? tabGroupId(activeTab) : null; +}); + function isTabGroupActive(tab: QueryTab) { - const section = tab.pinned ? sortedPinnedTabs.value : sortedRegularTabs.value; - const groupKey = tabGroupKey(tab); - return section.some((item) => tabGroupKey(item) === groupKey && isTabActive(item)); + return activeTabGroupId.value === tabGroupId(tab); } function preserveTabScrollPosition() { @@ -734,12 +737,17 @@ const filteredRegularTabs = computed(() => { function buildStripEntries(section: QueryTab[], pinned: boolean): StripEntry[] { const entries: StripEntry[] = []; const grouping = settingsStore.editorSettings.tabGroupMode !== "none"; + const groupKeys = grouping ? section.map(tabGroupKey) : []; + const groupCounts = new Map(); + for (const groupKey of groupKeys) { + groupCounts.set(groupKey, (groupCounts.get(groupKey) ?? 0) + 1); + } section.forEach((tab, index) => { - const first = grouping && (index === 0 || tabGroupKey(section[index - 1]!) !== tabGroupKey(tab)); - const last = grouping && (index === section.length - 1 || tabGroupKey(section[index + 1]!) !== tabGroupKey(tab)); + const groupKey = groupKeys[index]; + const first = grouping && (index === 0 || groupKeys[index - 1] !== groupKey); + const last = grouping && (index === section.length - 1 || groupKeys[index + 1] !== groupKey); if (first) { - const groupKey = tabGroupKey(tab); - entries.push({ kind: "header", key: `header:${tab.id}`, tab, pinned, count: section.filter((item) => tabGroupKey(item) === groupKey).length }); + entries.push({ kind: "header", key: `header:${tab.id}`, tab, pinned, count: groupCounts.get(groupKey!) ?? 0 }); } entries.push({ kind: "tab", key: tab.id, tab, groupFirst: first, groupLast: last, grouping }); }); diff --git a/apps/desktop/src/components/layout/__tests__/EditorGroupTabBar.groups.spec.ts b/apps/desktop/src/components/layout/__tests__/EditorGroupTabBar.groups.spec.ts index 30a871a68a..9066e6799a 100644 --- a/apps/desktop/src/components/layout/__tests__/EditorGroupTabBar.groups.spec.ts +++ b/apps/desktop/src/components/layout/__tests__/EditorGroupTabBar.groups.spec.ts @@ -34,6 +34,20 @@ describe("EditorGroupTabBar semantic tab groups", () => { expect(source).toContain(':aria-expanded="!isTabGroupCollapsed(entry.tab)"'); }); + it("counts group entries in linear time instead of rescanning the section", () => { + const builder = sourceBetween("function buildStripEntries", "const pinnedStripEntries"); + expect(builder).toContain("const groupKeys = grouping ? section.map(tabGroupKey) : [];"); + expect(builder).toContain("const groupCounts = new Map();"); + expect(builder).toContain("groupCounts.get(groupKey!) ?? 0"); + expect(builder).not.toContain("section.filter("); + }); + + it("computes the active group once instead of scanning every group", () => { + const activeGroup = sourceBetween("const activeTabGroupId", "function isTabGroupActive"); + expect(activeGroup).toContain("const activeTab = props.tabs.find((item) => isTabActive(item));"); + expect(source).toContain("return activeTabGroupId.value === tabGroupId(tab);"); + }); + it("expands a collapsed group when one of its tabs becomes active", () => { expect(source).toContain("expandTabGroupForTab(tabId);"); });