fix: ensure header visibility with explicit newline and nil checks
This commit is contained in:
parent
8619a7f35c
commit
9fec5df6f7
@ -212,17 +212,18 @@ func (m *Model) updateLayout() {
|
|||||||
|
|
||||||
rightWidth := 42
|
rightWidth := 42
|
||||||
leftWidth := m.width - rightWidth - 3
|
leftWidth := m.width - rightWidth - 3
|
||||||
headerHeight := 3
|
|
||||||
mainHeight := m.height - headerHeight - 1
|
headerHeight := 2
|
||||||
inputHeight := 5
|
mainHeight := m.height - headerHeight
|
||||||
chatHeight := mainHeight - inputHeight
|
if mainHeight < 10 {
|
||||||
if chatHeight < 10 {
|
mainHeight = 10
|
||||||
chatHeight = 10
|
}
|
||||||
|
chatHeight := mainHeight - 9
|
||||||
|
if chatHeight < 5 {
|
||||||
|
chatHeight = 5
|
||||||
}
|
}
|
||||||
|
|
||||||
m.textarea.SetWidth(leftWidth)
|
m.textarea.SetWidth(leftWidth)
|
||||||
m.viewport.Width = leftWidth
|
|
||||||
m.viewport.Height = chatHeight
|
|
||||||
|
|
||||||
if !m.ready {
|
if !m.ready {
|
||||||
m.viewport = viewport.New(leftWidth, chatHeight)
|
m.viewport = viewport.New(leftWidth, chatHeight)
|
||||||
@ -265,33 +266,18 @@ func (m Model) View() string {
|
|||||||
return "Initializing..."
|
return "Initializing..."
|
||||||
}
|
}
|
||||||
|
|
||||||
rightWidth := 42
|
rightWidth := 40
|
||||||
leftWidth := m.width - rightWidth - 3
|
leftWidth := m.width - rightWidth - 2
|
||||||
|
|
||||||
header := m.renderHeader()
|
header := m.renderHeader()
|
||||||
headerHeight := lipgloss.Height(header)
|
|
||||||
mainHeight := m.height - headerHeight
|
|
||||||
inputHeight := 5
|
|
||||||
chatHeight := mainHeight - inputHeight
|
|
||||||
if chatHeight < 10 {
|
|
||||||
chatHeight = 10
|
|
||||||
}
|
|
||||||
|
|
||||||
chatBox := boxStyle.Width(leftWidth).Height(chatHeight).Render(m.viewport.View())
|
chatBox := boxStyle.Width(leftWidth).Height(m.height - 8).Render(m.viewport.View())
|
||||||
inputBox := boxStyle.Width(leftWidth).Render(m.textarea.View())
|
inputBox := boxStyle.Width(leftWidth).Render(m.textarea.View())
|
||||||
leftPanel := lipgloss.JoinVertical(lipgloss.Left, chatBox, inputBox)
|
leftPanel := lipgloss.JoinVertical(lipgloss.Left, chatBox, inputBox)
|
||||||
|
|
||||||
stats := m.renderStats()
|
stats := m.renderStats()
|
||||||
agents := m.renderAgents()
|
agents := m.renderAgents()
|
||||||
|
empty := boxStyle.Width(rightWidth - 2).Height(m.height - lipgloss.Height(stats) - lipgloss.Height(agents) - 5).Render("")
|
||||||
statsHeight := lipgloss.Height(stats)
|
|
||||||
agentsHeight := lipgloss.Height(agents)
|
|
||||||
remainingHeight := mainHeight - statsHeight - agentsHeight - 2
|
|
||||||
if remainingHeight < 3 {
|
|
||||||
remainingHeight = 3
|
|
||||||
}
|
|
||||||
|
|
||||||
empty := boxStyle.Width(rightWidth - 4).Height(remainingHeight).Render("")
|
|
||||||
rightPanel := lipgloss.JoinVertical(lipgloss.Left, stats, agents, empty)
|
rightPanel := lipgloss.JoinVertical(lipgloss.Left, stats, agents, empty)
|
||||||
|
|
||||||
if m.loading {
|
if m.loading {
|
||||||
@ -299,19 +285,21 @@ func (m Model) View() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
body := lipgloss.JoinHorizontal(lipgloss.Top, leftPanel, rightPanel)
|
body := lipgloss.JoinHorizontal(lipgloss.Top, leftPanel, rightPanel)
|
||||||
return lipgloss.JoinVertical(lipgloss.Left, header, body)
|
return header + "\n" + body
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Model) renderHeader() string {
|
func (m Model) renderHeader() string {
|
||||||
version := "v0.1.0"
|
version := "v0.1.0"
|
||||||
title := titleStyle.Render("orca.agent ") + mutedStyle.Render(version)
|
title := "orca.agent " + version
|
||||||
|
line := strings.Repeat("─", m.width-2)
|
||||||
return lipgloss.NewStyle().
|
return lipgloss.NewStyle().
|
||||||
Width(m.width).
|
Width(m.width).
|
||||||
Padding(0, 1).
|
Padding(0, 1).
|
||||||
BorderBottom(true).
|
Bold(true).
|
||||||
BorderStyle(lipgloss.NormalBorder()).
|
Foreground(lipgloss.Color(colors.primary)).
|
||||||
BorderForeground(lipgloss.Color(colors.border)).
|
Render(title) + "\n" + lipgloss.NewStyle().
|
||||||
Render(title)
|
Foreground(lipgloss.Color(colors.border)).
|
||||||
|
Render(line)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Model) renderStats() string {
|
func (m Model) renderStats() string {
|
||||||
@ -319,17 +307,23 @@ func (m Model) renderStats() string {
|
|||||||
b.WriteString(titleStyle.Render("Statistics") + "\n\n")
|
b.WriteString(titleStyle.Render("Statistics") + "\n\n")
|
||||||
|
|
||||||
tools := 0
|
tools := 0
|
||||||
|
if m.kernel != nil {
|
||||||
if tm := m.kernel.ToolManager(); tm != nil {
|
if tm := m.kernel.ToolManager(); tm != nil {
|
||||||
tools = tm.Count()
|
tools = tm.Count()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
skills := 0
|
skills := 0
|
||||||
|
if m.kernel != nil {
|
||||||
if sm := m.kernel.SkillManager(); sm != nil {
|
if sm := m.kernel.SkillManager(); sm != nil {
|
||||||
skills = len(sm.ListSkills())
|
skills = len(sm.ListSkills())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
agents := 0
|
agents := 0
|
||||||
|
if m.kernel != nil {
|
||||||
if as := m.kernel.ActorSystem(); as != nil {
|
if as := m.kernel.ActorSystem(); as != nil {
|
||||||
agents = as.AgentCount()
|
agents = as.AgentCount()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
b.WriteString(statLabelStyle.Render("Tools: "))
|
b.WriteString(statLabelStyle.Render("Tools: "))
|
||||||
b.WriteString(statValueStyle.Render(fmt.Sprintf("%d", tools)) + "\n")
|
b.WriteString(statValueStyle.Render(fmt.Sprintf("%d", tools)) + "\n")
|
||||||
@ -345,6 +339,7 @@ func (m Model) renderAgents() string {
|
|||||||
var b strings.Builder
|
var b strings.Builder
|
||||||
b.WriteString(titleStyle.Render("Active Agents") + "\n\n")
|
b.WriteString(titleStyle.Render("Active Agents") + "\n\n")
|
||||||
|
|
||||||
|
if m.kernel != nil {
|
||||||
if as := m.kernel.ActorSystem(); as != nil {
|
if as := m.kernel.ActorSystem(); as != nil {
|
||||||
for _, info := range as.AgentInfos() {
|
for _, info := range as.AgentInfos() {
|
||||||
status := "idle"
|
status := "idle"
|
||||||
@ -356,6 +351,7 @@ func (m Model) renderAgents() string {
|
|||||||
b.WriteString(fmt.Sprintf("• %s: %s\n", info.ID, style.Render(status)))
|
b.WriteString(fmt.Sprintf("• %s: %s\n", info.ID, style.Render(status)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return boxStyle.Width(38).Render(b.String())
|
return boxStyle.Width(38).Render(b.String())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
package tui
|
package tui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/charmbracelet/bubbles/textarea"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestEventWriter(t *testing.T) {
|
func TestEventWriter(t *testing.T) {
|
||||||
@ -74,3 +77,26 @@ func TestModelFormatMessage(t *testing.T) {
|
|||||||
t.Error("system message should not be empty")
|
t.Error("system message should not be empty")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestViewContainsHeader(t *testing.T) {
|
||||||
|
ta := textarea.New()
|
||||||
|
ta.ShowLineNumbers = false
|
||||||
|
ta.KeyMap.InsertNewline.SetEnabled(false)
|
||||||
|
|
||||||
|
m := Model{
|
||||||
|
width: 120,
|
||||||
|
height: 40,
|
||||||
|
textarea: ta,
|
||||||
|
messages: []ChatMessage{},
|
||||||
|
events: make(chan Event, 10),
|
||||||
|
agentRuns: make(map[string]bool),
|
||||||
|
}
|
||||||
|
m.updateLayout()
|
||||||
|
view := m.View()
|
||||||
|
if view == "Initializing..." {
|
||||||
|
t.Fatal("view should not be initializing")
|
||||||
|
}
|
||||||
|
if !strings.Contains(view, "orca.agent") {
|
||||||
|
t.Errorf("view should contain 'orca.agent', got:\n%s", view[:min(200, len(view))])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user