table.go 2.6 KB

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