fix: panel memangkas judul/meta · footer kembali utuh · tes aksi tab lebih tabah
CI / test (push) Successful in 26s
CI / test (push) Successful in 26s
Temuan CI (runner bersih, nama kontainer 112 char): - panel(): judul/meta panjang melebihi lebar panel dan mendorong kolom kanan (Aksi Tab) keluar layar — sekarang dipangkas + jaring pengaman ansiTruncate; unit test TestPanelTitleFits menutup kasus ini. - footer: aturan 'buang status dulu' membuat 'audio:'/animasi hilang di runner tanpa audio device — dikembalikan ke perilaku truncate semula. - TestTabActionColumn menunggu panel detail tampil dulu (hapus balapan muat). - TestToolbarSearch memilih prefix yang benar-benar unik + 'j' dulu.
This commit is contained in:
1 parent
5450a89a80
commit
b7866f917b
3 files changed
+37
-17
No files matched your search
+7
-5
@@ -633,17 +633,17 @@ func TestToolbarSearch(t *testing.T) {
|
||||
t.Skipf("butuh >= 2 kontainer (err=%v, n=%d)", err, len(items))
|
||||
}
|
||||
|
||||
// Target: prefix nama yang tidak termuat di nama kontainer sebelumnya —
|
||||
// pencarian melompat ke kecocokan pertama dari atas.
|
||||
// Target: prefix nama yang tidak termuat di nama kontainer mana pun —
|
||||
// supaya lompatan kursor tidak ambigu (kecocokan pertama = target).
|
||||
target := ""
|
||||
for i, it := range items {
|
||||
for _, it := range items {
|
||||
q := it.Name
|
||||
if len(q) > 6 {
|
||||
q = q[:6]
|
||||
}
|
||||
unique := true
|
||||
for k := 0; k < i; k++ {
|
||||
if strings.Contains(strings.ToLower(items[k].Name), strings.ToLower(q)) {
|
||||
for _, other := range items {
|
||||
if other.Name != it.Name && strings.Contains(strings.ToLower(other.Name), strings.ToLower(q)) {
|
||||
unique = false
|
||||
break
|
||||
}
|
||||
@@ -661,6 +661,7 @@ func TestToolbarSearch(t *testing.T) {
|
||||
u.waitContains("beranda", 5*time.Second)
|
||||
u.send("2")
|
||||
u.waitContains("[1-5]", 3*time.Second)
|
||||
u.send("j") // kursor pindah dari item pertama → lompatan cari terlihat
|
||||
if !u.clickText("Cari") {
|
||||
t.Fatal("pill Cari tidak ditemukan")
|
||||
}
|
||||
@@ -697,6 +698,7 @@ func TestTabActionColumn(t *testing.T) {
|
||||
u.waitContains("beranda", 5*time.Second)
|
||||
u.send("2")
|
||||
u.waitContains("[1-5]", 3*time.Second)
|
||||
u.waitContains("Statistik", 5*time.Second) // detail kontainer terpilih tampil
|
||||
u.waitContains("Aksi Tab", 3*time.Second)
|
||||
u.waitContains("ikut ekor", 3*time.Second)
|
||||
if !u.clickText("[S]") {
|
||||
|
||||
+14
-12
@@ -901,12 +901,21 @@ func panel(title, meta string, lines []string, w, h int, focused bool) string {
|
||||
bc = th.Accent
|
||||
}
|
||||
border := lipgloss.NewStyle().Foreground(lipgloss.Color(string(bc)))
|
||||
titleS := text(title)
|
||||
|
||||
left := border.Render("╭─ ") + titleS
|
||||
// Judul/meta dipangkas agar baris border TIDAK pernah melebihi lebar panel
|
||||
// (nama kontainer panjang dulu mendorong kolom kanan keluar layar).
|
||||
avail := w - 6
|
||||
if meta != "" {
|
||||
avail = w - 8
|
||||
}
|
||||
metaW := 0
|
||||
if meta != "" && avail > 4 {
|
||||
metaW = min(len([]rune(meta)), max(avail/3, 2))
|
||||
}
|
||||
left := border.Render("╭─ ") + text(truncate(title, max(avail-metaW, 1)))
|
||||
right := border.Render("─╮")
|
||||
if meta != "" {
|
||||
right = " " + dim(meta) + border.Render(" ─╮")
|
||||
right = " " + dim(truncate(meta, metaW)) + border.Render(" ─╮")
|
||||
}
|
||||
gap := w - lipgloss.Width(left) - lipgloss.Width(right)
|
||||
if gap < 1 {
|
||||
@@ -914,9 +923,7 @@ func panel(title, meta string, lines []string, w, h int, focused bool) string {
|
||||
}
|
||||
|
||||
var b strings.Builder
|
||||
b.WriteString(left)
|
||||
b.WriteString(border.Render(strings.Repeat("─", gap)))
|
||||
b.WriteString(right)
|
||||
b.WriteString(ansiTruncate(left+border.Render(strings.Repeat("─", gap))+right, w))
|
||||
|
||||
content := lipgloss.NewStyle().Width(w - 4)
|
||||
for i := 0; i < h-2; i++ {
|
||||
@@ -984,12 +991,7 @@ func (m Model) footerPlain() string {
|
||||
if m.animating {
|
||||
anim = fmt.Sprintf("%d", m.fps)
|
||||
}
|
||||
full := i18n.Tf("footer.status", hints, anim, m.sound.Status())
|
||||
if lipgloss.Width(full) > m.width {
|
||||
// Hint aksi lebih penting daripada status diagnostik: buang status dulu.
|
||||
full = truncate(hints, m.width)
|
||||
}
|
||||
return full
|
||||
return truncate(i18n.Tf("footer.status", hints, anim, m.sound.Status()), m.width)
|
||||
}
|
||||
|
||||
func (m Model) footerLine() string { return dim(m.footerPlain()) }
|
||||
|
||||
@@ -47,6 +47,22 @@ func TestToolbarPlain(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestPanelTitleFits — judul/meta panjang tidak boleh melebihi lebar panel:
|
||||
// nama kontainer/stack panjang pernah mendorong kolom kanan keluar layar.
|
||||
func TestPanelTitleFits(t *testing.T) {
|
||||
long := strings.Repeat("GITEA-ACTIONS-TASK-", 8)
|
||||
for _, w := range []int{6, 10, 40, 100} {
|
||||
for _, meta := range []string{"", "running", long} {
|
||||
out := panel(long, meta, []string{"isi"}, w, 4, false)
|
||||
for _, line := range strings.Split(out, "\n") {
|
||||
if got := lipgloss.Width(line); got > w {
|
||||
t.Fatalf("w=%d meta=%q: baris lebar %d > %d: %q", w, meta, got, w, line)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestSearchJump — pencarian melompat ke item pertama yang cocok (daftar tetap
|
||||
// utuh), dan nama item mengikuti seksi aktif.
|
||||
func TestSearchJump(t *testing.T) {
|
||||
|
||||
Reference in new issue
Block a user