All checks were successful
CI / build (push) Successful in 2m41s
Split monolithic app.go into focused modules (dashboard, chat, workflow, config, agents, terminal, commands, handlers). Add proper error handling for installer commands, proxy pipes, and MCP config parsing. Fix daemon channel buffer, cap orchestrator history, compile think regex once, and set HTTP timeouts on preview server. Improve CI with Go module caching, dependency download step, and test stage with race detection. 😘 Generated with Crush Assisted-by: GLM-5-Turbo via Crush <crush@charm.land>
162 lines
4.5 KiB
Go
162 lines
4.5 KiB
Go
package tui
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/charmbracelet/lipgloss"
|
|
)
|
|
|
|
func (m Model) renderDashboard() string {
|
|
colWidth := m.width / 2
|
|
if colWidth < 30 {
|
|
colWidth = 30
|
|
}
|
|
|
|
var left, right strings.Builder
|
|
|
|
left.WriteString(sectionStyle.Render("System"))
|
|
left.WriteString("\n")
|
|
if m.scanResult != nil {
|
|
sysInfo := m.scanResult.System.String()
|
|
left.WriteString(" ")
|
|
left.WriteString(lipgloss.NewStyle().Foreground(lipgloss.Color("#E0E0E0")).Render(sysInfo))
|
|
}
|
|
left.WriteString("\n\n")
|
|
|
|
left.WriteString(sectionStyle.Render("Tools"))
|
|
left.WriteString("\n")
|
|
if m.scanResult != nil {
|
|
installed := 0
|
|
total := len(m.scanResult.Tools)
|
|
for _, t := range m.scanResult.Tools {
|
|
if t.Installed {
|
|
installed++
|
|
left.WriteString(" ")
|
|
left.WriteString(itemOKStyle.Render(" "))
|
|
left.WriteString(fmt.Sprintf(" %-12s %s\n", t.Name, extractVersion(t.Version)))
|
|
} else {
|
|
left.WriteString(" ")
|
|
left.WriteString(itemMissingStyle.Render(" "))
|
|
left.WriteString(fmt.Sprintf(" %-12s %s\n", t.Name, itemPendingStyle.Render("(not installed)")))
|
|
}
|
|
}
|
|
barWidth := 20
|
|
pct := 0
|
|
if total > 0 {
|
|
pct = (installed * barWidth) / total
|
|
}
|
|
bar := lipgloss.NewStyle().Foreground(successColor).Render(strings.Repeat("█", pct)) +
|
|
lipgloss.NewStyle().Foreground(dimColor).Render(strings.Repeat("░", barWidth-pct))
|
|
left.WriteString(fmt.Sprintf("\n %s %d/%d\n", bar, installed, total))
|
|
}
|
|
left.WriteString("\n")
|
|
|
|
if m.installing {
|
|
left.WriteString(sectionStyle.Render("Installing..."))
|
|
left.WriteString("\n")
|
|
progBar := m.progressBar.View()
|
|
label := ""
|
|
if m.installTool != "" {
|
|
label = fmt.Sprintf(" %d/%d - %s", m.installCurrent+1, m.installTotal, m.installTool)
|
|
} else {
|
|
label = fmt.Sprintf(" %d/%d", m.installCurrent, m.installTotal)
|
|
}
|
|
left.WriteString(fmt.Sprintf(" %s%s\n", progBar, label))
|
|
left.WriteString("\n")
|
|
}
|
|
|
|
if len(m.installLog) > 0 {
|
|
left.WriteString(sectionStyle.Render("Install Log"))
|
|
left.WriteString("\n")
|
|
for _, l := range m.installLog {
|
|
left.WriteString(l + "\n")
|
|
}
|
|
left.WriteString("\n")
|
|
}
|
|
|
|
right.WriteString(sectionStyle.Render("Quick Actions"))
|
|
right.WriteString("\n")
|
|
actions := []struct {
|
|
key string
|
|
desc string
|
|
}{
|
|
{"i", "Install missing tools"},
|
|
{"u", "Check for updates"},
|
|
{"s", "Rescan system"},
|
|
{"l", "Scan LSP servers"},
|
|
{"m", "Configure MCP servers"},
|
|
}
|
|
for _, a := range actions {
|
|
right.WriteString(fmt.Sprintf(" %s %s\n",
|
|
lipgloss.NewStyle().Foreground(baseColor).Bold(true).Render("["+a.key+"]"),
|
|
a.desc))
|
|
}
|
|
right.WriteString("\n")
|
|
|
|
if len(m.updateStatus) > 0 {
|
|
right.WriteString(sectionStyle.Render("Updates"))
|
|
right.WriteString("\n")
|
|
for _, s := range m.updateStatus {
|
|
if s.NeedsUpdate {
|
|
right.WriteString(" ")
|
|
right.WriteString(itemWarnStyle.Render(" "))
|
|
right.WriteString(fmt.Sprintf(" %s: %s -> %s\n", s.Tool, s.Current, s.Latest))
|
|
} else if s.Error == "" {
|
|
right.WriteString(" ")
|
|
right.WriteString(itemOKStyle.Render(" "))
|
|
right.WriteString(fmt.Sprintf(" %s: up to date\n", s.Tool))
|
|
}
|
|
}
|
|
right.WriteString("\n")
|
|
}
|
|
|
|
if len(m.lspServers) > 0 {
|
|
right.WriteString(sectionStyle.Render("LSP Servers"))
|
|
right.WriteString("\n")
|
|
lspInstalled := 0
|
|
for _, s := range m.lspServers {
|
|
if s.Installed {
|
|
lspInstalled++
|
|
right.WriteString(" ")
|
|
right.WriteString(itemOKStyle.Render(" "))
|
|
right.WriteString(fmt.Sprintf(" %-22s (%s)\n", s.Name, s.Language))
|
|
} else {
|
|
right.WriteString(" ")
|
|
right.WriteString(itemPendingStyle.Render(" "))
|
|
right.WriteString(fmt.Sprintf(" %-22s (%s)\n", s.Name, s.Language))
|
|
}
|
|
}
|
|
right.WriteString(fmt.Sprintf("\n Installed: %d/%d\n", lspInstalled, len(m.lspServers)))
|
|
right.WriteString("\n")
|
|
}
|
|
|
|
if m.daemon != nil {
|
|
right.WriteString(sectionStyle.Render("Daemon"))
|
|
right.WriteString("\n")
|
|
if m.daemon.IsRunning() {
|
|
right.WriteString(" ")
|
|
right.WriteString(itemOKStyle.Render("running"))
|
|
lastCheck := m.daemon.LastCheck()
|
|
if !lastCheck.IsZero() {
|
|
right.WriteString(fmt.Sprintf(" last: %s", lastCheck.Format("15:04:05")))
|
|
}
|
|
} else {
|
|
right.WriteString(" ")
|
|
right.WriteString(itemPendingStyle.Render("stopped"))
|
|
}
|
|
right.WriteString("\n\n")
|
|
}
|
|
|
|
mcpStatus := itemPendingStyle.Render("not configured")
|
|
if m.mcpConfigured {
|
|
mcpStatus = itemOKStyle.Render("configured")
|
|
}
|
|
right.WriteString(fmt.Sprintf("MCP: %s\n", mcpStatus))
|
|
|
|
leftCol := lipgloss.NewStyle().Width(colWidth).Render(left.String())
|
|
rightCol := lipgloss.NewStyle().Width(colWidth).Render(right.String())
|
|
|
|
return lipgloss.JoinHorizontal(lipgloss.Top, leftCol, rightCol)
|
|
}
|