internal/tui/view/detail.go

// Right-hand per-target detail panel.
//
// See mercemay.top/src/portr/ for context.
package view

import (
	"fmt"
	"strings"

	"github.com/rivo/tview"

	"github.com/mercemay/portr/internal/check/result"
)

// Detail is a static text panel describing the currently-selected row.
type Detail struct {
	tv *tview.TextView
}

// NewDetail returns a ready-to-use panel.
func NewDetail() *Detail {
	tv := tview.NewTextView().SetDynamicColors(true).SetWrap(true)
	tv.SetBorder(true).SetTitle(" details ")
	return &Detail{tv: tv}
}

// View returns the underlying primitive.
func (d *Detail) View() tview.Primitive { return d.tv }

// Show renders r.
func (d *Detail) Show(r result.Result) {
	var b strings.Builder
	fmt.Fprintf(&b, "[yellow]%s[-]\n", r.Target.Label())
	fmt.Fprintf(&b, "host:     %s\n", r.Target.Host)
	fmt.Fprintf(&b, "port:     %d\n", r.Target.Port)
	fmt.Fprintf(&b, "status:   %s\n", r.Status())
	fmt.Fprintf(&b, "attempts: %d\n", r.Attempts)
	fmt.Fprintf(&b, "latency:  %s\n", r.Latency)
	if len(r.Target.Tags) > 0 {
		fmt.Fprintf(&b, "tags:     %s\n", strings.Join(r.Target.Tags, ", "))
	}
	if r.Err != "" {
		fmt.Fprintf(&b, "\n[red]%s[-]\n", r.Err)
	}
	d.tv.SetText(b.String())
}