Skip to content

Commit a3e63f5

Browse files
authored
Merge pull request #4819 from SivanCola/fix/reusable-blank-tab-title
Fix reusable blank tab title reset / 修复复用空白标签页标题重置
2 parents 2cc29c5 + 259b3c8 commit a3e63f5

2 files changed

Lines changed: 120 additions & 0 deletions

File tree

desktop/app_session_dedup_test.go

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package main
22

33
import (
4+
"os"
45
"path/filepath"
56
"testing"
67

@@ -101,6 +102,102 @@ func TestEnsureBlankTabCreatesOneBlankPerProject(t *testing.T) {
101102
}
102103
}
103104

105+
func TestEnsureBlankTabResetsReusableAutoTopicTitle(t *testing.T) {
106+
isolateDesktopUserDirs(t)
107+
108+
projectRoot := t.TempDir()
109+
app := NewApp()
110+
topic, err := app.CreateTopic("project", projectRoot, "")
111+
if err != nil {
112+
t.Fatalf("create topic: %v", err)
113+
}
114+
if err := setTopicTitleWithSource(projectRoot, topic.ID, "Old auto title", topicTitleSourceAuto); err != nil {
115+
t.Fatalf("set stale auto title: %v", err)
116+
}
117+
tab := app.createTabEntryWithID("project", projectRoot, topic.ID, "tab1")
118+
app.tabs[tab.ID] = tab
119+
app.tabOrder = []string{tab.ID}
120+
app.activeTabID = tab.ID
121+
122+
meta, err := app.EnsureBlankTab("project", projectRoot)
123+
if err != nil {
124+
t.Fatalf("EnsureBlankTab: %v", err)
125+
}
126+
if got := meta.TopicTitle; got != defaultTopicTitle {
127+
t.Fatalf("reused auto topic title = %q, want %q", got, defaultTopicTitle)
128+
}
129+
if got := loadTopicTitle(projectRoot, topic.ID); got != defaultTopicTitle {
130+
t.Fatalf("stored title = %q, want %q", got, defaultTopicTitle)
131+
}
132+
if got := loadTopicTitleSource(projectRoot, topic.ID); got != topicTitleSourceAuto {
133+
t.Fatalf("title source = %q, want auto", got)
134+
}
135+
}
136+
137+
func TestEnsureBlankTabPreservesReusableManualTopicTitle(t *testing.T) {
138+
isolateDesktopUserDirs(t)
139+
140+
projectRoot := t.TempDir()
141+
app := NewApp()
142+
topic, err := app.CreateTopic("project", projectRoot, "Manual title")
143+
if err != nil {
144+
t.Fatalf("create topic: %v", err)
145+
}
146+
tab := app.createTabEntryWithID("project", projectRoot, topic.ID, "tab1")
147+
app.tabs[tab.ID] = tab
148+
app.tabOrder = []string{tab.ID}
149+
app.activeTabID = tab.ID
150+
151+
meta, err := app.EnsureBlankTab("project", projectRoot)
152+
if err != nil {
153+
t.Fatalf("EnsureBlankTab: %v", err)
154+
}
155+
if got := meta.TopicTitle; got != "Manual title" {
156+
t.Fatalf("reused manual topic title = %q, want Manual title", got)
157+
}
158+
if got := loadTopicTitle(projectRoot, topic.ID); got != "Manual title" {
159+
t.Fatalf("stored title = %q, want Manual title", got)
160+
}
161+
if got := loadTopicTitleSource(projectRoot, topic.ID); got != topicTitleSourceManual {
162+
t.Fatalf("title source = %q, want manual", got)
163+
}
164+
}
165+
166+
func TestEnsureBlankTabKeepsActiveTabWhenTitleResetFails(t *testing.T) {
167+
isolateDesktopUserDirs(t)
168+
169+
projectRoot := t.TempDir()
170+
app := NewApp()
171+
topic, err := app.CreateTopic("project", projectRoot, "")
172+
if err != nil {
173+
t.Fatalf("create topic: %v", err)
174+
}
175+
if err := setTopicTitleWithSource(projectRoot, topic.ID, "Old auto title", topicTitleSourceAuto); err != nil {
176+
t.Fatalf("set stale auto title: %v", err)
177+
}
178+
activeTab := app.createTabEntryWithID("global", globalTabWorkspaceRoot(), "", "active-tab")
179+
reusableTab := app.createTabEntryWithID("project", projectRoot, topic.ID, "reusable-tab")
180+
app.tabs[activeTab.ID] = activeTab
181+
app.tabs[reusableTab.ID] = reusableTab
182+
app.tabOrder = []string{activeTab.ID, reusableTab.ID}
183+
app.activeTabID = activeTab.ID
184+
185+
titlePath := topicTitlesPath(projectRoot)
186+
if err := os.Remove(titlePath); err != nil {
187+
t.Fatalf("remove title file: %v", err)
188+
}
189+
if err := os.Mkdir(titlePath, 0o755); err != nil {
190+
t.Fatalf("replace title file with directory: %v", err)
191+
}
192+
193+
if _, err := app.EnsureBlankTab("project", projectRoot); err == nil {
194+
t.Fatal("EnsureBlankTab succeeded, want title reset error")
195+
}
196+
if got := app.activeTabID; got != activeTab.ID {
197+
t.Fatalf("active tab after failed title reset = %q, want %q", got, activeTab.ID)
198+
}
199+
}
200+
104201
// EnsureBlankTab picks up an existing blank topic created in the sidebar
105202
// instead of creating a fresh topic, for global scope.
106203

desktop/tabs.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,6 +1114,10 @@ func (a *App) EnsureBlankTab(scope, workspaceRoot string) (TabMeta, error) {
11141114
for _, id := range a.orderedTabIDsLocked() {
11151115
tab := a.tabs[id]
11161116
if a.blankTabMatchesTargetLocked(tab, scope, workspaceRoot) {
1117+
if err := resetReusableBlankTabTitle(tab, scope, workspaceRoot); err != nil {
1118+
a.mu.Unlock()
1119+
return TabMeta{}, err
1120+
}
11171121
a.activeTabID = tab.ID
11181122
meta := a.tabMeta(tab, true)
11191123
a.saveTabsLocked()
@@ -1240,6 +1244,25 @@ func (a *App) blankTabMatchesTargetLocked(tab *WorkspaceTab, scope, workspaceRoo
12401244
return !messagesHaveConversationContent(tab.Ctrl.History())
12411245
}
12421246

1247+
func resetReusableBlankTabTitle(tab *WorkspaceTab, scope, workspaceRoot string) error {
1248+
if tab == nil {
1249+
return nil
1250+
}
1251+
topicID := strings.TrimSpace(tab.TopicID)
1252+
if topicID == "" {
1253+
return nil
1254+
}
1255+
titleRoot := topicTitleRoot(scope, workspaceRoot)
1256+
if source := loadTopicTitleSource(titleRoot, topicID); source != topicTitleSourceAuto {
1257+
return nil
1258+
}
1259+
if err := setTopicTitleWithSource(titleRoot, topicID, defaultTopicTitle, topicTitleSourceAuto); err != nil {
1260+
return err
1261+
}
1262+
tab.TopicTitle = defaultTopicTitle
1263+
return nil
1264+
}
1265+
12431266
// indexedBlankTopicIDLocked finds a blank topic ID that is indexed on disk
12441267
// but not open in any tab — for reusing without creating a new topic.
12451268
func (a *App) indexedBlankTopicIDLocked(scope, workspaceRoot string) string {

0 commit comments

Comments
 (0)