Add ordering for threads

This commit is contained in:
2026-07-28 09:52:57 +02:00
parent 80f24bcfa8
commit 60d64dedb2
6 changed files with 196 additions and 1 deletions

85
tui.go
View File

@@ -73,6 +73,8 @@ type App struct {
pathScroll bool
pathScrollInterval time.Duration
pathScrollStep int
threadStatusOrder []string
threadWithinStatus string
}
type AppSettings struct {
@@ -80,6 +82,8 @@ type AppSettings struct {
ThreadListWidthPercent int
PathScroll bool
PathScrollInterval time.Duration
ThreadStatusOrder []string
ThreadWithinStatus string
}
func defaultAppSettings() AppSettings {
@@ -87,6 +91,8 @@ func defaultAppSettings() AppSettings {
FoldResolved: true,
ThreadListWidthPercent: 33,
PathScrollInterval: 350 * time.Millisecond,
ThreadStatusOrder: []string{"unresolved", "outdated", "resolved"},
ThreadWithinStatus: "file",
}
}
@@ -107,6 +113,8 @@ func NewAppWithSettings(
folded: make(map[string]bool), loading: true,
foldResolved: settings.FoldResolved, threadListWidthPercent: settings.ThreadListWidthPercent,
pathScroll: settings.PathScroll, pathScrollInterval: settings.PathScrollInterval,
threadStatusOrder: append([]string(nil), settings.ThreadStatusOrder...),
threadWithinStatus: settings.ThreadWithinStatus,
}
}
@@ -203,6 +211,7 @@ func (m App) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
if m.threadIndex < len(m.details.Threads) {
selected = m.details.Threads[m.threadIndex].ID
}
sortReviewThreads(msg.details.Threads, m.threadStatusOrder, m.threadWithinStatus)
m.details = msg.details
m.threadIndex = indexThread(m.details.Threads, selected)
if selected != "" && (len(m.details.Threads) == 0 || m.details.Threads[m.threadIndex].ID != selected) {
@@ -444,6 +453,82 @@ func (m App) matchingThreadIndices() []int {
return indices
}
func sortReviewThreads(threads []ReviewThread, statusOrder []string, withinStatus string) {
ranks := map[string]int{
"unresolved": 0,
"outdated": 1,
"resolved": 2,
}
for rank, status := range statusOrder {
ranks[status] = rank
}
if withinStatus == "" {
withinStatus = "file"
}
sort.SliceStable(threads, func(i, j int) bool {
left, right := threads[i], threads[j]
leftRank, rightRank := ranks[threadStatus(left)], ranks[threadStatus(right)]
if leftRank != rightRank {
return leftRank < rightRank
}
if withinStatus == "timestamp" {
if less, decided := compareThreadTimestamps(left, right); decided {
return less
}
}
leftPath, rightPath := strings.ToLower(left.Path), strings.ToLower(right.Path)
if leftPath != rightPath {
return leftPath < rightPath
}
if left.Line != right.Line {
return left.Line < right.Line
}
if withinStatus != "timestamp" {
if less, decided := compareThreadTimestamps(left, right); decided {
return less
}
}
return false
})
}
func threadStatus(thread ReviewThread) string {
if thread.IsResolved {
return "resolved"
}
if thread.IsOutdated {
return "outdated"
}
return "unresolved"
}
func threadOpenedAt(thread ReviewThread) time.Time {
var opened time.Time
for _, comment := range thread.Comments {
if comment.CreatedAt.IsZero() || (!opened.IsZero() && !comment.CreatedAt.Before(opened)) {
continue
}
opened = comment.CreatedAt
}
return opened
}
func compareThreadTimestamps(left, right ReviewThread) (less, decided bool) {
leftTime, rightTime := threadOpenedAt(left), threadOpenedAt(right)
switch {
case leftTime.IsZero() && rightTime.IsZero():
return false, false
case leftTime.IsZero():
return false, true
case rightTime.IsZero():
return true, true
case !leftTime.Equal(rightTime):
return leftTime.Before(rightTime), true
default:
return false, false
}
}
func (m *App) toStart() {
if m.screen == prScreen {
m.prIndex = 0