feat(tui): show chat thread state column
This commit is contained in:
parent
eb3235c351
commit
1ccc241eb9
34
tui/tui.go
34
tui/tui.go
@ -3374,6 +3374,8 @@ func (m model) memberTableRows(columns []tableColumn, members []int) []tableRow
|
||||
row = append(row, rowWhere(item))
|
||||
case "author":
|
||||
row = append(row, itemAuthor(item))
|
||||
case "relation":
|
||||
row = append(row, chatRelationForColumn(item, column.Width))
|
||||
default:
|
||||
row = append(row, title)
|
||||
}
|
||||
@ -3516,11 +3518,13 @@ func (m model) memberColumns(width int) []tableColumn {
|
||||
{Key: "title", Title: activeLabel("title", active == sortTitle), Width: titleW},
|
||||
}
|
||||
}
|
||||
authorW := minInt(maxInt(5, width/6), 9)
|
||||
titleW := maxInt(1, width-whenW-ageW-authorW-3)
|
||||
relationW := 3
|
||||
authorW := minInt(maxInt(5, width/7), 9)
|
||||
titleW := maxInt(1, width-whenW-ageW-relationW-authorW-4)
|
||||
return []tableColumn{
|
||||
{Key: "time", Title: activeTimeLabel(m.memberTimeLabel(), active), Width: whenW},
|
||||
{Key: "age", Title: activeTimeLabel("age", active), Width: ageW},
|
||||
{Key: "relation", Title: "rel", Width: relationW},
|
||||
{Key: "author", Title: activeLabel("who", active == sortAuthor), Width: authorW},
|
||||
{Key: "title", Title: activeLabel("title", active == sortTitle), Width: titleW},
|
||||
}
|
||||
@ -3540,10 +3544,12 @@ func (m model) memberColumns(width int) []tableColumn {
|
||||
}
|
||||
}
|
||||
authorW := minInt(maxInt(8, width/7), 18)
|
||||
titleW := maxInt(1, width-whenW-ageW-authorW-3)
|
||||
relationW := 5
|
||||
titleW := maxInt(1, width-whenW-ageW-relationW-authorW-4)
|
||||
return []tableColumn{
|
||||
{Key: "time", Title: activeTimeLabel("time", active), Width: whenW},
|
||||
{Key: "age", Title: activeTimeLabel("age", active), Width: ageW},
|
||||
{Key: "relation", Title: "type", Width: relationW},
|
||||
{Key: "author", Title: activeLabel("who", active == sortAuthor), Width: authorW},
|
||||
{Key: "title", Title: activeLabel("title", active == sortTitle), Width: titleW},
|
||||
}
|
||||
@ -3831,6 +3837,28 @@ func chatReplyCountLabel(item Item) string {
|
||||
return value + " replies"
|
||||
}
|
||||
|
||||
func chatRelationForColumn(item Item, width int) string {
|
||||
label := "msg"
|
||||
if strings.TrimSpace(item.ParentID) != "" {
|
||||
label = "reply"
|
||||
} else if chatReplyCountLabel(item) != "" {
|
||||
label = "thread"
|
||||
} else if thread := strings.TrimSpace(fieldValue(item, "thread", "reply_to")); thread != "" && thread != strings.TrimSpace(item.ID) && thread != strings.TrimSpace(fieldValue(item, "ts")) {
|
||||
label = "thread"
|
||||
}
|
||||
if width <= 3 {
|
||||
switch label {
|
||||
case "reply":
|
||||
return "rep"
|
||||
case "thread":
|
||||
return "thr"
|
||||
default:
|
||||
return "msg"
|
||||
}
|
||||
}
|
||||
return label
|
||||
}
|
||||
|
||||
func chatThreadLabel(item Item) string {
|
||||
parent := strings.TrimSpace(item.ParentID)
|
||||
thread := strings.TrimSpace(fieldValue(item, "thread", "reply_to"))
|
||||
|
||||
@ -10,6 +10,7 @@ import (
|
||||
"testing"
|
||||
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
)
|
||||
|
||||
func stripANSI(value string) string {
|
||||
@ -766,6 +767,30 @@ func TestChatMembersDefaultToNewestFirstLikeGitcrawl(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestChatMemberColumnsExposeThreadState(t *testing.T) {
|
||||
m := newModel(Options{
|
||||
Title: "discrawl archive",
|
||||
Layout: LayoutChat,
|
||||
Items: []Item{
|
||||
Row{Kind: "message", ID: "root", Container: "general", Author: "alice", Title: "root", CreatedAt: "2026-05-01T10:00:00Z", Fields: map[string]string{"reply_count": "2"}}.ItemForLayout(LayoutChat),
|
||||
Row{Kind: "message", ID: "reply", ParentID: "root", Container: "general", Author: "alice", Title: "reply", CreatedAt: "2026-05-01T10:01:00Z"}.ItemForLayout(LayoutChat),
|
||||
},
|
||||
})
|
||||
columns := m.memberColumns(52)
|
||||
header := stripANSI(renderTableHeader(columns, 52, "#9bc53d"))
|
||||
if !strings.Contains(header, "rel") {
|
||||
t.Fatalf("chat member header should expose relation column:\n%s", header)
|
||||
}
|
||||
rows := m.memberTableRows(columns, m.currentGroupMembers())
|
||||
rendered := stripANSI(strings.Join([]string{
|
||||
renderTableRow(columns, rows[0], 52, lipgloss.NewStyle()),
|
||||
renderTableRow(columns, rows[1], 52, lipgloss.NewStyle()),
|
||||
}, "\n"))
|
||||
if !strings.Contains(rendered, "thr") || !strings.Contains(rendered, "rep") {
|
||||
t.Fatalf("chat member rows should show thread/reply state:\n%s", rendered)
|
||||
}
|
||||
}
|
||||
|
||||
func TestChatGroupScopeSortUsesScopeNotContainer(t *testing.T) {
|
||||
m := newModel(Options{
|
||||
Title: "slacrawl archive",
|
||||
@ -1928,9 +1953,14 @@ func TestClickingContextHeaderUsesContextPaneColumns(t *testing.T) {
|
||||
m.height = 24
|
||||
layout := m.layout()
|
||||
contextWidth := paneContentWidth(layout.context.w)
|
||||
whenW := minInt(maxInt(10, contextWidth/6), 16)
|
||||
ageW := minInt(maxInt(4, contextWidth/16), 7)
|
||||
authorX := whenW + 1 + ageW + 1
|
||||
columns := m.memberColumns(contextWidth)
|
||||
authorX := 0
|
||||
for index, column := range columns {
|
||||
if column.Key == "author" {
|
||||
authorX = columnLeftEdge(columns, index)
|
||||
break
|
||||
}
|
||||
}
|
||||
updated, _ := m.Update(tea.MouseMsg{
|
||||
X: layout.context.x + 2 + authorX,
|
||||
Y: layout.context.y + 2,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user