table.go

  1package logs
  2
  3import (
  4	"encoding/json"
  5	"slices"
  6
  7	"github.com/charmbracelet/bubbles/key"
  8	"github.com/charmbracelet/bubbles/table"
  9	tea "github.com/charmbracelet/bubbletea"
 10	"github.com/kujtimiihoxha/termai/internal/logging"
 11	"github.com/kujtimiihoxha/termai/internal/pubsub"
 12	"github.com/kujtimiihoxha/termai/internal/tui/layout"
 13)
 14
 15type TableComponent interface {
 16	tea.Model
 17	layout.Focusable
 18	layout.Sizeable
 19	layout.Bindings
 20}
 21
 22var logger = logging.Get()
 23
 24type tableCmp struct {
 25	table table.Model
 26}
 27
 28func (i *tableCmp) Init() tea.Cmd {
 29	i.setRows()
 30	return nil
 31}
 32
 33func (i *tableCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 34	if i.table.Focused() {
 35		switch msg := msg.(type) {
 36		case pubsub.Event[logging.Message]:
 37			i.setRows()
 38			return i, nil
 39		case tea.KeyMsg:
 40			if msg.String() == "ctrl+s" {
 41				logger.Info("Saving logs...",
 42					"rows", len(i.table.Rows()),
 43				)
 44			}
 45		}
 46		t, cmd := i.table.Update(msg)
 47		i.table = t
 48		return i, cmd
 49	}
 50	return i, nil
 51}
 52
 53func (i *tableCmp) View() string {
 54	return i.table.View()
 55}
 56
 57func (i *tableCmp) Blur() tea.Cmd {
 58	i.table.Blur()
 59	return nil
 60}
 61
 62func (i *tableCmp) Focus() tea.Cmd {
 63	i.table.Focus()
 64	return nil
 65}
 66
 67func (i *tableCmp) IsFocused() bool {
 68	return i.table.Focused()
 69}
 70
 71func (i *tableCmp) GetSize() (int, int) {
 72	return i.table.Width(), i.table.Height()
 73}
 74
 75func (i *tableCmp) SetSize(width int, height int) {
 76	i.table.SetWidth(width)
 77	i.table.SetHeight(height)
 78	cloumns := i.table.Columns()
 79	for i, col := range cloumns {
 80		col.Width = (width / len(cloumns)) - 2
 81		cloumns[i] = col
 82	}
 83	i.table.SetColumns(cloumns)
 84}
 85
 86func (i *tableCmp) BindingKeys() []key.Binding {
 87	return layout.KeyMapToSlice(i.table.KeyMap)
 88}
 89
 90func (i *tableCmp) setRows() {
 91	rows := []table.Row{}
 92
 93	logs := logger.List()
 94	slices.SortFunc(logs, func(a, b logging.Message) int {
 95		if a.Time.Before(b.Time) {
 96			return 1
 97		}
 98		if a.Time.After(b.Time) {
 99			return -1
100		}
101		return 0
102	})
103
104	for _, log := range logs {
105		bm, _ := json.Marshal(log.Attributes)
106
107		row := table.Row{
108			log.Time.Format("15:04:05"),
109			log.Level,
110			log.Message,
111			string(bm),
112		}
113		rows = append(rows, row)
114	}
115	i.table.SetRows(rows)
116}
117
118func NewLogsTable() TableComponent {
119	columns := []table.Column{
120		{Title: "Time", Width: 4},
121		{Title: "Level", Width: 10},
122		{Title: "Message", Width: 10},
123		{Title: "Attributes", Width: 10},
124	}
125	tableModel := table.New(
126		table.WithColumns(columns),
127	)
128	return &tableCmp{
129		table: tableModel,
130	}
131}