fix(tui): clamp member scroll and footer width
This commit is contained in:
parent
b2a52f4418
commit
fa3e56e1db
@ -525,8 +525,9 @@ func (m clusterBrowserModel) renderHeader(width int) string {
|
||||
if m.payload.InferredRepository {
|
||||
line += " inferred"
|
||||
}
|
||||
style := lipgloss.NewStyle().Width(width).Height(1).Background(lipgloss.Color("#0d1321")).Foreground(lipgloss.Color("#f7f7ff")).Bold(true).Padding(0, 1)
|
||||
return style.Render(truncateCells(line, maxInt(1, width-2)))
|
||||
content := padCells(" "+truncateCells(line, maxInt(1, width-2)), width)
|
||||
style := lipgloss.NewStyle().Width(width).Height(1).Background(lipgloss.Color("#0d1321")).Foreground(lipgloss.Color("#f7f7ff")).Bold(true)
|
||||
return style.Render(content)
|
||||
}
|
||||
|
||||
func (m clusterBrowserModel) renderFooter(width int) string {
|
||||
@ -548,7 +549,9 @@ func (m clusterBrowserModel) renderFooter(width int) string {
|
||||
line = strings.TrimSpace(line + " " + location)
|
||||
}
|
||||
bg, fg := footerPalette(m.payload.DBSource)
|
||||
return lipgloss.NewStyle().Width(width).Height(2).Background(bg).Foreground(fg).Padding(0, 1).Render(truncateCells(line, width-2) + "\n" + truncateCells(controls, maxInt(1, width-2)))
|
||||
statusLine := padCells(" "+truncateCells(line, maxInt(1, width-2)), width)
|
||||
controlsLine := padCells(" "+truncateCells(controls, maxInt(1, width-2)), width)
|
||||
return lipgloss.NewStyle().Width(width).Height(2).Background(bg).Foreground(fg).Render(statusLine + "\n" + controlsLine)
|
||||
}
|
||||
|
||||
func loadingFrame(index int) string {
|
||||
@ -3085,18 +3088,14 @@ func (m clusterBrowserModel) nextSelectableMemberIndex(current, delta int) int {
|
||||
}
|
||||
index := current
|
||||
for moved := 0; moved < steps; moved++ {
|
||||
for attempts := 0; attempts < len(m.memberRows); attempts++ {
|
||||
index += step
|
||||
if index < 0 {
|
||||
index = len(m.memberRows) - 1
|
||||
}
|
||||
if index >= len(m.memberRows) {
|
||||
index = 0
|
||||
}
|
||||
if m.memberRows[index].selectable {
|
||||
break
|
||||
}
|
||||
next := index + step
|
||||
for next >= 0 && next < len(m.memberRows) && !m.memberRows[next].selectable {
|
||||
next += step
|
||||
}
|
||||
if next < 0 || next >= len(m.memberRows) {
|
||||
return index
|
||||
}
|
||||
index = next
|
||||
}
|
||||
return index
|
||||
}
|
||||
|
||||
@ -76,6 +76,22 @@ func TestTUIHeaderShowsDetailMode(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTUIHeaderDoesNotWrapAtTerminalWidth(t *testing.T) {
|
||||
model := newClusterBrowserModel(context.Background(), nil, 0, clusterBrowserPayload{
|
||||
Repository: strings.Repeat("openclaw/", 20),
|
||||
Sort: "recent",
|
||||
Clusters: sampleTUIClusters(),
|
||||
})
|
||||
header := model.renderHeader(80)
|
||||
lines := strings.Split(header, "\n")
|
||||
if len(lines) != 1 {
|
||||
t.Fatalf("header rendered %d lines, want 1:\n%s", len(lines), header)
|
||||
}
|
||||
if width := lipgloss.Width(lines[0]); width > 80 {
|
||||
t.Fatalf("header width = %d, want <= 80: %q", width, lines[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestTUIViewKeepsEssentialFooterHintsNarrow(t *testing.T) {
|
||||
model := newClusterBrowserModel(context.Background(), nil, 0, clusterBrowserPayload{
|
||||
Repository: "openclaw/openclaw",
|
||||
@ -151,6 +167,31 @@ func TestTUIFooterShowsRemoteRefreshLoadingState(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTUIFooterDoesNotWrapLongRemoteLocation(t *testing.T) {
|
||||
model := newClusterBrowserModel(context.Background(), nil, 0, clusterBrowserPayload{
|
||||
Repository: "openclaw/openclaw",
|
||||
DBSource: "remote",
|
||||
DBLocation: "openclaw/gitcrawl-store:" + strings.Repeat("openclaw__openclaw.sync.db", 6),
|
||||
Sort: "recent",
|
||||
Clusters: sampleTUIClusters(),
|
||||
})
|
||||
model.status = "Cluster 14316"
|
||||
|
||||
footer := model.renderFooter(80)
|
||||
lines := strings.Split(footer, "\n")
|
||||
if len(lines) != 2 {
|
||||
t.Fatalf("footer rendered %d lines, want 2:\n%s", len(lines), footer)
|
||||
}
|
||||
if !strings.Contains(lines[1], "? help") || !strings.Contains(lines[1], "q quit") {
|
||||
t.Fatalf("footer controls were displaced:\n%s", footer)
|
||||
}
|
||||
for index, line := range lines {
|
||||
if width := lipgloss.Width(line); width > 80 {
|
||||
t.Fatalf("footer line %d width = %d, want <= 80: %q", index, width, line)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTUIViewFitsTerminalFrame(t *testing.T) {
|
||||
model := newClusterBrowserModel(context.Background(), nil, 0, clusterBrowserPayload{
|
||||
Repository: "openclaw/openclaw",
|
||||
@ -517,6 +558,29 @@ func TestTUIWideLayoutToggle(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTUIMemberMovementDoesNotWrapPastEdges(t *testing.T) {
|
||||
model := newClusterBrowserModel(context.Background(), nil, 0, clusterBrowserPayload{
|
||||
Repository: "openclaw/openclaw",
|
||||
Sort: "recent",
|
||||
Clusters: sampleTUIClusters(),
|
||||
})
|
||||
model.memberRows = []memberRow{
|
||||
{label: "ISSUES (2)"},
|
||||
{selectable: true, member: store.ClusterMemberDetail{Thread: store.Thread{Number: 1, State: "open"}}},
|
||||
{selectable: true, member: store.ClusterMemberDetail{Thread: store.Thread{Number: 2, State: "open"}}},
|
||||
}
|
||||
|
||||
if got := model.nextSelectableMemberIndex(2, 1); got != 2 {
|
||||
t.Fatalf("member down from last = %d, want last row", got)
|
||||
}
|
||||
if got := model.nextSelectableMemberIndex(1, -1); got != 1 {
|
||||
t.Fatalf("member up from first = %d, want first row", got)
|
||||
}
|
||||
if got := model.nextSelectableMemberIndex(1, 10); got != 2 {
|
||||
t.Fatalf("member page down = %d, want last row", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTUIRightClickOpensFloatingMenu(t *testing.T) {
|
||||
model := newClusterBrowserModel(context.Background(), nil, 0, clusterBrowserPayload{
|
||||
Repository: "openclaw/openclaw",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user