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) }