diff --git a/internal/tui/chart.go b/internal/tui/chart.go index b7be10c..9e56852 100644 --- a/internal/tui/chart.go +++ b/internal/tui/chart.go @@ -1,36 +1,98 @@ package tui import ( + "fmt" + "strings" "time" - "github.com/NimbleMarkets/ntcharts/canvas/runes" - "github.com/NimbleMarkets/ntcharts/linechart/streamlinechart" + "github.com/NimbleMarkets/ntcharts/sparkline" "github.com/charmbracelet/lipgloss" ) func (m Model) latencyChart(latencies []time.Duration, statuses []bool, width, height int) string { - if len(latencies) == 0 || width < 10 || height < 3 { + if len(latencies) == 0 || width < 20 || height < 2 { return "" } - chartW := len(latencies) - if chartW > width { - chartW = width + var minMs, maxMs, sumMs int64 + minMs = latencies[0].Milliseconds() + maxMs = minMs + for i, l := range latencies { + ms := l.Milliseconds() + if i < len(statuses) && !statuses[i] { + continue + } + if ms < minMs { + minMs = ms + } + if ms > maxMs { + maxMs = ms + } + sumMs += ms + } + upCount := 0 + for _, s := range statuses { + if s { + upCount++ + } + } + var avgMs int64 + if upCount > 0 { + avgMs = sumMs / int64(upCount) } - lineStyle := lipgloss.NewStyle().Foreground(m.theme.Accent) - slc := streamlinechart.New(chartW, height, - streamlinechart.WithStyles(runes.ThinLineStyle, lineStyle), - ) + maxLabel := fmt.Sprintf("%dms", maxMs) + minLabel := fmt.Sprintf("%dms", minMs) + labelW := len(maxLabel) + if len(minLabel) > labelW { + labelW = len(minLabel) + } + labelW += 1 + chartW := width - labelW + if chartW > len(latencies) { + chartW = len(latencies) + } + if chartW < 10 { + chartW = 10 + } + + style := lipgloss.NewStyle().Foreground(m.theme.Accent) + sl := sparkline.New(chartW, height, sparkline.WithStyle(style)) + + vals := make([]float64, len(latencies)) for i, l := range latencies { ms := float64(l.Milliseconds()) if i < len(statuses) && !statuses[i] { ms = 0 } - slc.Push(ms) + vals[i] = ms } - slc.Draw() + sl.PushAll(vals) + sl.Draw() - return slc.View() + chartLines := strings.Split(sl.View(), "\n") + + var result []string + labelStyle := m.st.subtleStyle + for i, line := range chartLines { + var label string + if i == 0 { + label = fmt.Sprintf("%*s", labelW, maxLabel) + } else if i == len(chartLines)-1 { + label = fmt.Sprintf("%*s", labelW, minLabel) + } else { + label = strings.Repeat(" ", labelW) + } + result = append(result, labelStyle.Render(label)+line) + } + + stats := fmt.Sprintf("%*s Min %s Avg %s Max %s", + labelW, "", + m.fmtLatency(time.Duration(minMs)*time.Millisecond), + m.fmtLatency(time.Duration(avgMs)*time.Millisecond), + m.fmtLatency(time.Duration(maxMs)*time.Millisecond)) + result = append(result, stats) + + return strings.Join(result, "\n") } diff --git a/internal/tui/update.go b/internal/tui/update.go index 543f935..c028bff 100644 --- a/internal/tui/update.go +++ b/internal/tui/update.go @@ -142,7 +142,7 @@ func (m *Model) handleFormMsg(msg tea.Msg) (tea.Model, tea.Cmd) { return m, nil } -const detailInlineHeight = 12 +const detailInlineHeight = 10 func (m *Model) recalcLayout() { chrome := chromeBase diff --git a/internal/tui/view_detail_inline.go b/internal/tui/view_detail_inline.go index 4bf394d..77dc15f 100644 --- a/internal/tui/view_detail_inline.go +++ b/internal/tui/view_detail_inline.go @@ -71,31 +71,10 @@ func (m Model) viewDetailInline(width int) string { if chartW < 20 { chartW = 20 } - chartH := 4 - chart := m.latencyChart(hist.Latencies, hist.Statuses, chartW, chartH) + chart := m.latencyChart(hist.Latencies, hist.Statuses, chartW, 2) if chart != "" { b.WriteString(chart + "\n") } - - minMs := hist.Latencies[0].Milliseconds() - maxMs := hist.Latencies[0].Milliseconds() - var sumMs int64 - for _, l := range hist.Latencies { - ms := l.Milliseconds() - if ms < minMs { - minMs = ms - } - if ms > maxMs { - maxMs = ms - } - sumMs += ms - } - avgMs := sumMs / int64(len(hist.Latencies)) - stats := fmt.Sprintf(" Min %s Avg %s Max %s", - m.fmtLatency(time.Duration(minMs)*time.Millisecond), - m.fmtLatency(time.Duration(avgMs)*time.Millisecond), - m.fmtLatency(time.Duration(maxMs)*time.Millisecond)) - b.WriteString(stats + "\n") } keys := m.st.subtleStyle.Render("[h] History [s] SLA [e] Edit [esc] Close")