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}