fix(ui/chat): ensure all guilds appear in tree including orphans (#741)

This commit is contained in:
Ayyan 2026-02-09 01:29:09 -05:00 • committed by GitHub
parent 7af199b5a3
commit 4c61e7c67a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 51 additions and 25 deletions

View file

@ -59,7 +59,7 @@ func (gt *guildsTree) resetNodeIndex() {
gt.dmRootNode = nil
}
func (gt *guildsTree) createFolderNode(folder gateway.GuildFolder) {
func (gt *guildsTree) createFolderNode(folder gateway.GuildFolder, guildsByID map[discord.GuildID]*gateway.GuildCreateEvent) {
name := "Folder"
if folder.Name != "" {
name = folder.Name
@ -72,14 +72,10 @@ func (gt *guildsTree) createFolderNode(folder gateway.GuildFolder) {
}
gt.GetRoot().AddChild(folderNode)
for _, gID := range folder.GuildIDs {
guild, err := gt.chatView.state.Cabinet.Guild(gID)
if err != nil {
slog.Error("failed to get guild from state", "guild_id", gID, "err", err)
continue
for _, guildID := range folder.GuildIDs {
if guildEvent, ok := guildsByID[guildID]; ok {
gt.createGuildNode(folderNode, guildEvent.Guild)
}
gt.createGuildNode(folderNode, *guild)
}
}

View file

@ -80,34 +80,64 @@ func (v *View) onRaw(event *ws.RawEvent) {
)
}
func (v *View) onReady(r *gateway.ReadyEvent) {
dmNode := tview.NewTreeNode("Direct Messages").SetReference(dmNode{})
func (v *View) onReady(event *gateway.ReadyEvent) {
// Rebuild indexes from scratch so reconnects and account switches do not
// retain stale pointers to detached tree nodes.
v.guildsTree.resetNodeIndex()
dmNode := tview.NewTreeNode("Direct Messages").SetReference(dmNode{})
v.guildsTree.dmRootNode = dmNode
root := v.guildsTree.
GetRoot().
ClearChildren().
AddChild(dmNode)
for _, folder := range r.UserSettings.GuildFolders {
if folder.ID == 0 && len(folder.GuildIDs) == 1 {
guild, err := v.state.Cabinet.Guild(folder.GuildIDs[0])
if err != nil {
slog.Error(
"failed to get guild from state",
"guild_id",
folder.GuildIDs[0],
"err",
err,
)
continue
}
// Track guilds already in folders to find orphans (newly joined guilds may not be synced to GuildFolders yet but always appear in GuildPositions)
guildsInFolders := make(map[discord.GuildID]bool)
for _, folder := range event.UserSettings.GuildFolders {
for _, guildID := range folder.GuildIDs {
guildsInFolders[guildID] = true
}
}
v.guildsTree.createGuildNode(root, *guild)
// Build index of all available guilds.
guildsByID := make(map[discord.GuildID]*gateway.GuildCreateEvent, len(event.Guilds))
for index := range event.Guilds {
guildsByID[event.Guilds[index].ID] = &event.Guilds[index]
}
// Use GuildPositions for ordering (it's the canonical order).
// Guilds not in any folder are "orphans" - add them directly to root.
positions := event.UserSettings.GuildPositions
// Fallback: GuildPositions shouldn't be nil but handle gracefully
if len(positions) == 0 {
positions = make([]discord.GuildID, 0, len(event.Guilds))
for _, guildEvent := range event.Guilds {
positions = append(positions, guildEvent.ID)
}
}
for _, guildID := range positions {
// Already handled in folder processing below
if guildsInFolders[guildID] {
continue
}
// Orphan guild - add directly to root in order
if guildEvent, ok := guildsByID[guildID]; ok {
v.guildsTree.createGuildNode(root, guildEvent.Guild)
}
}
// Process folders (real folders and single-guild "folders")
for _, folder := range event.UserSettings.GuildFolders {
if folder.ID == 0 && len(folder.GuildIDs) == 1 {
if guild, ok := guildsByID[folder.GuildIDs[0]]; ok {
v.guildsTree.createGuildNode(root, guild.Guild)
}
} else {
v.guildsTree.createFolderNode(folder)
v.guildsTree.createFolderNode(folder, guildsByID)
}
}