fix(desktop): recover missing topic indexes#3228
Conversation
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1a9dd63cf5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
6d92890 to
fbdcf36
Compare
|
Updated this PR after resolving the merge conflict with the latest What changed:
Verified:
|
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fbdcf36ee5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if path != "" { | ||
| a.persistTabSessionPath(tab, path) | ||
| if strings.TrimSpace(tab.TopicID) != "" { | ||
| if err := ensureTopicIndexed(tab.Scope, tab.WorkspaceRoot, tab.TopicID, tab.TopicTitle, loadTopicTitleSource(topicTitleRoot(tab.Scope, tab.WorkspaceRoot), tab.TopicID)); err == nil { |
There was a problem hiding this comment.
Recover title from session meta before writing defaults
When a persisted tab is restored after its topic title index was deleted, createTabEntryWithID synthesizes tab.TopicTitle as defaultTopicTitle; this new recovery path then indexes that synthetic title. Because persistTabSessionPath immediately above also saves tab.TopicTitle into the session metadata, the original BranchMeta.TopicTitle that could have repaired the index is overwritten before recovery, so users with an open saved tab lose the real topic title and the sidebar is restored as “新的会话” instead of the session's title.
Useful? React with 👍 / 👎.
| if topicID == "" { | ||
| return fmt.Errorf("topicID is required") | ||
| } | ||
| topicIndexMu.Lock() |
There was a problem hiding this comment.
Share the project-index lock with legacy migration
This lock only serializes ensureTopicIndexed calls, but migrateLegacySessionsIntoGlobalTopics uses a different mutex while doing the same load/modify/save of desktop-projects.json. During startup one restored tab can be repairing its topic index while another tab or ListProjectTree is migrating legacy sessions, so the later save can overwrite the earlier update and drop either recovered project topics or migrated global topics.
Useful? React with 👍 / 👎.
| } | ||
| for i, p := range f.Projects { | ||
| if p.Root == workspaceRoot { | ||
| f.Projects[i].Topics = prependUniqueString(p.Topics, topicID) |
There was a problem hiding this comment.
Avoid moving already-indexed topics during recovery
When this recovery path runs for an existing project topic, prependUniqueString rewrites the ordered topic list by moving that topic to the front. Because buildTabController now calls ensureTopicIndexed for every restored open tab, simply reopening the app can reorder the sidebar's saved topic order based on startup timing instead of only repairing genuinely missing entries.
Useful? React with 👍 / 👎.
| try { | ||
| await renameTopic(topicId, nextTitle); | ||
| } catch { |
There was a problem hiding this comment.
Surface non-stale rename failures
This catches every RenameTopic failure, not just the stale-topic case mentioned in the comment. If the backend fails to write the title or projects file because of permissions, disk space, or a config I/O error, the edit mode is dismissed and the draft is discarded without refreshing or telling the user that the rename did not persist.
Useful? React with 👍 / 👎.
Summary
Testing
cd desktop && go test ./...cd desktop/frontend && pnpm typecheck(fails in this worktree because generated Wailswailsjsbindings are missing:../../wailsjs/go/main/Appand runtime imports)