Skip to content

Commit 9d5eff1

Browse files
committed
refactor: implement recent activity table with structured rows and improved rendering
1 parent 0f78205 commit 9d5eff1

1 file changed

Lines changed: 41 additions & 51 deletions

File tree

ui/tui/views/dashboard/model.go

Lines changed: 41 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@ import (
1111
"time"
1212

1313
"github.com/charmbracelet/bubbles/help"
14+
"github.com/charmbracelet/bubbles/table"
1415
tea "github.com/charmbracelet/bubbletea"
1516
"github.com/charmbracelet/lipgloss"
1617
"github.com/toeirei/keymaster/client"
1718
"github.com/toeirei/keymaster/core"
1819
"github.com/toeirei/keymaster/core/model"
1920
"github.com/toeirei/keymaster/i18n"
21+
"github.com/toeirei/keymaster/ui/tui/helpers/tablecontroll"
2022
"github.com/toeirei/keymaster/ui/tui/util"
2123
"github.com/toeirei/keymaster/uiadapters"
2224
"github.com/toeirei/keymaster/util/slicest"
@@ -38,6 +40,12 @@ type Data = struct {
3840
// copied from keymaster core for now
3941
type AuditLogEntry = model.AuditLogEntry
4042

43+
type recentActivityRow struct {
44+
Timestamp string
45+
Action string
46+
Details string
47+
}
48+
4149
type Model struct {
4250
data Data
4351
err error
@@ -99,6 +107,8 @@ func (m Model) View() string {
99107
height = 24
100108
}
101109

110+
recentActivityRows := recentActivityTableRows(m.data.RecentLogs)
111+
102112
lines := []string{
103113
sectionTitleStyle.Render(i18n.T("dashboard.system_status")),
104114
"",
@@ -119,17 +129,31 @@ func (m Model) View() string {
119129
"",
120130
}
121131

122-
if len(m.data.RecentLogs) == 0 {
132+
if len(recentActivityRows) == 0 {
123133
lines = append(lines, bodyStyle.Italic(true).Render(i18n.T("dashboard.no_recent_activity")))
124134
} else {
125135
maxLogRows := util.Clamp(3, height-14, 10)
126-
entryWidth := contentWidth - 4
127-
for i, al := range m.data.RecentLogs {
128-
if i >= maxLogRows {
129-
break
130-
}
131-
lines = append(lines, bodyStyle.Render(formatLogEntry(al, entryWidth)))
136+
if len(recentActivityRows) > maxLogRows {
137+
recentActivityRows = recentActivityRows[:maxLogRows]
132138
}
139+
140+
recentActivityControll := tablecontroll.New(tablecontroll.Columns[recentActivityRow]{
141+
{Title: i18n.T("dashboard.log_col_time"), View: func(row recentActivityRow) string { return row.Timestamp }, MaxWidth: 0.18},
142+
{Title: i18n.T("dashboard.log_col_action"), View: func(row recentActivityRow) string { return row.Action }, MaxWidth: 0.24},
143+
{Title: i18n.T("dashboard.log_col_details"), View: func(row recentActivityRow) string { return row.Details }, MaxWidth: 0.58},
144+
})
145+
146+
tableWidth := recentActivityControll.PreferredWidth(recentActivityRows, contentWidth)
147+
columns, rows := recentActivityControll.RenderBubblesTable(recentActivityRows, tableWidth)
148+
149+
tableModel := table.New()
150+
tableModel.SetColumns(columns)
151+
tableModel.SetRows(rows)
152+
tableModel.SetCursor(-1)
153+
tableModel.SetWidth(tableWidth)
154+
tableModel.SetHeight(len(rows) + 1)
155+
156+
lines = append(lines, strings.Split(tableModel.View(), "\n")...)
133157
}
134158

135159
return lipgloss.JoinVertical(lipgloss.Left, lines...)
@@ -149,28 +173,6 @@ func formatSystemKeySerial(serial int) string {
149173
return fmt.Sprintf(i18n.T("dashboard.system_key_serial"), serial)
150174
}
151175

152-
func formatLogEntry(al AuditLogEntry, width int) string {
153-
ts := parseTimestamp(al.Timestamp)
154-
action := titleFromUnderscore(strings.TrimSpace(al.Action))
155-
details := strings.TrimSpace(strings.ReplaceAll(al.Details, "\n", " "))
156-
width = max(width, 38)
157-
actionWidth := 20
158-
// TODO use bubbles table (like everywhere else)
159-
base := fmt.Sprintf("%s | %s | ", ts, action)
160-
maxDetails := width - lipgloss.Width(base)
161-
maxDetails = max(maxDetails, 8)
162-
if lipgloss.Width(details) > maxDetails {
163-
details = truncateRight(details, maxDetails)
164-
}
165-
166-
timestampStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("8"))
167-
actionStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("6")).Bold(true)
168-
detailStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("7"))
169-
170-
actionPadded := padRight(action, actionWidth)
171-
return timestampStyle.Render(padRight(ts, 12)) + " | " + actionStyle.Render(actionPadded) + " | " + detailStyle.Render(details)
172-
}
173-
174176
func formatAlgoSpread(algoCounts map[string]int, style lipgloss.Style) string {
175177
if len(algoCounts) == 0 {
176178
return "-"
@@ -189,6 +191,16 @@ func formatAlgoSpread(algoCounts map[string]int, style lipgloss.Style) string {
189191
return strings.Join(parts, ", ")
190192
}
191193

194+
func recentActivityTableRows(logs []AuditLogEntry) []recentActivityRow {
195+
return slicest.Map(logs, func(al AuditLogEntry) recentActivityRow {
196+
return recentActivityRow{
197+
Timestamp: parseTimestamp(al.Timestamp),
198+
Action: titleFromUnderscore(strings.TrimSpace(al.Action)),
199+
Details: strings.TrimSpace(strings.ReplaceAll(al.Details, "\n", " ")),
200+
}
201+
})
202+
}
203+
192204
// TODO decide if this function handles date, time or datetime
193205
func parseTimestamp(raw string) string {
194206
raw = strings.TrimSpace(raw)
@@ -207,18 +219,6 @@ func parseTimestamp(raw string) string {
207219
return raw
208220
}
209221

210-
// TODO use lipgloss
211-
func truncateRight(s string, max int) string {
212-
if max <= 1 || lipgloss.Width(s) <= max {
213-
return s
214-
}
215-
r := []rune(s)
216-
if len(r) >= max {
217-
return string(r[:max-3]) + "..."
218-
}
219-
return s
220-
}
221-
222222
// TODO use lipgloss
223223
func titleFromUnderscore(action string) string {
224224
if action == "" {
@@ -235,16 +235,6 @@ func titleFromUnderscore(action string) string {
235235
}
236236
return strings.Join(parts, " ")
237237
}
238-
239-
// TODO use lipgloss
240-
func padRight(s string, width int) string {
241-
w := lipgloss.Width(s)
242-
if w >= width {
243-
return s
244-
}
245-
return s + strings.Repeat(" ", width-w)
246-
}
247-
248238
func (m *Model) Focus(parentKeyMap help.KeyMap) tea.Cmd {
249239
return tea.Batch(
250240
m.reload(),

0 commit comments

Comments
 (0)