Skip to content

Commit 9d353ea

Browse files
committed
refactor: enhance dashboard view styles and streamline log entry rendering
1 parent fa9a90e commit 9d353ea

1 file changed

Lines changed: 49 additions & 58 deletions

File tree

ui/tui/views/dashboard/model.go

Lines changed: 49 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,10 @@ func (m Model) View() string {
7777
}
7878

7979
contentWidth := util.Clamp(36, width-4, 76)
80-
81-
borderStyle := lipgloss.NewStyle().
82-
BorderStyle(lipgloss.RoundedBorder()).
83-
BorderForeground(lipgloss.Color("6")).
84-
Padding(0, 1).
85-
Width(contentWidth)
80+
sectionTitleStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("6")).Bold(true)
81+
bodyStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("8"))
82+
valueStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("10")).Bold(true)
83+
warnValueStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("3")).Bold(true)
8684

8785
if m.err != nil {
8886
errTitle := lipgloss.NewStyle().
@@ -91,68 +89,50 @@ func (m Model) View() string {
9189
Render(i18n.T("dashboard.error_title"))
9290
errBody := lipgloss.NewStyle().
9391
Foreground(lipgloss.Color("8")).
94-
Width(contentWidth - 2).
92+
Width(contentWidth).
9593
Render(m.err.Error())
96-
return borderStyle.Render(lipgloss.JoinVertical(lipgloss.Left, errTitle, "", errBody))
94+
return lipgloss.JoinVertical(lipgloss.Left, errTitle, "", errBody)
9795
}
9896

99-
titleStyle := lipgloss.NewStyle().
100-
Foreground(lipgloss.Color("6")).
101-
Bold(true)
102-
labelStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("8"))
103-
valueStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("10")).Bold(true)
104-
warnValueStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("3")).Bold(true)
97+
height := m.size.Height
98+
if height <= 0 {
99+
height = 24
100+
}
105101

106-
metricsPanel := borderStyle.Render(lipgloss.JoinVertical(
107-
lipgloss.Left,
108-
titleStyle.Render(i18n.T("dashboard.system_metrics")),
102+
lines := []string{
103+
sectionTitleStyle.Render(i18n.T("dashboard.system_status")),
104+
"",
105+
valueStyle.Render(fmt.Sprintf(i18n.T("dashboard.accounts"), m.data.AccountCount, m.data.ActiveAccountCount)),
106+
valueStyle.Render(fmt.Sprintf(i18n.T("dashboard.public_keys"), m.data.PublicKeyCount, m.data.GlobalKeyCount)),
107+
valueStyle.Render(fmt.Sprintf(i18n.T("dashboard.system_key"), formatSystemKeySerial(m.data.SystemKeySerial))),
108+
"",
109+
sectionTitleStyle.Render(i18n.T("dashboard.deployment_status")),
109110
"",
110-
formatKeyValue(i18n.T("dashboard.label.accounts"), fmt.Sprintf(i18n.T("dashboard.accounts_summary"), m.data.AccountCount, m.data.ActiveAccountCount), labelStyle, valueStyle),
111-
formatKeyValue(i18n.T("dashboard.label.hosts"), formatHostStatus(m.data.HostsUpToDate, m.data.HostsOutdated), labelStyle, chooseOutdatedStyle(m.data.HostsOutdated, valueStyle, warnValueStyle)),
112-
formatKeyValue(i18n.T("dashboard.label.system_key"), formatSystemKeySerial(m.data.SystemKeySerial), labelStyle, valueStyle),
113-
))
111+
valueStyle.Render(fmt.Sprintf(i18n.T("dashboard.hosts_current_key"), m.data.HostsUpToDate)),
112+
valueStyle.Render(fmt.Sprintf(i18n.T("dashboard.hosts_past_keys"), m.data.HostsOutdated)),
113+
"",
114+
sectionTitleStyle.Render(i18n.T("dashboard.security_posture")),
115+
"",
116+
bodyStyle.Render(fmt.Sprintf(i18n.T("dashboard.key_type_spread"), formatAlgoSpread(m.data.AlgoCounts, warnValueStyle))),
117+
"",
118+
sectionTitleStyle.Render(i18n.T("dashboard.recent_activity")),
119+
"",
120+
}
114121

115-
// TODO use bubbles table (like everywhere else)
116-
logsTitle := titleStyle.Render(i18n.T("dashboard.recent_audit_logs"))
117-
logsBody := ""
118122
if len(m.data.RecentLogs) == 0 {
119-
logsBody = lipgloss.NewStyle().Foreground(lipgloss.Color("8")).Italic(true).Render(i18n.T("dashboard.no_recent_entries"))
123+
lines = append(lines, bodyStyle.Italic(true).Render(i18n.T("dashboard.no_recent_activity")))
120124
} else {
121-
height := m.size.Height
122-
if height <= 0 {
123-
height = 24
124-
}
125125
maxLogRows := util.Clamp(3, height-14, 10)
126-
logLines := make([]string, 0, min(len(m.data.RecentLogs), maxLogRows+1))
127126
entryWidth := contentWidth - 4
128-
logTimeCol := padRight(i18n.T("dashboard.log_col_time"), 12)
129-
logActionCol := padRight(i18n.T("dashboard.log_col_action"), 20)
130-
logDetailsCol := i18n.T("dashboard.log_col_details")
131-
head := lipgloss.NewStyle().Foreground(lipgloss.Color("8")).Bold(true).Render(
132-
fmt.Sprintf("%s | %s | %s", logTimeCol, logActionCol, logDetailsCol),
133-
)
134-
logLines = append(logLines, head)
135127
for i, al := range m.data.RecentLogs {
136128
if i >= maxLogRows {
137129
break
138130
}
139-
logLines = append(logLines, formatLogEntry(al, entryWidth))
131+
lines = append(lines, bodyStyle.Render(formatLogEntry(al, entryWidth)))
140132
}
141-
logsBody = lipgloss.JoinVertical(lipgloss.Left, logLines...)
142133
}
143134

144-
logsPanel := borderStyle.Render(lipgloss.JoinVertical(
145-
lipgloss.Left,
146-
logsTitle,
147-
"",
148-
logsBody,
149-
))
150-
151-
return lipgloss.JoinVertical(lipgloss.Left, metricsPanel, "", logsPanel)
152-
}
153-
154-
func formatKeyValue(label, value string, labelStyle, valueStyle lipgloss.Style) string {
155-
return labelStyle.Render(label+":") + " " + valueStyle.Render(value)
135+
return lipgloss.JoinVertical(lipgloss.Left, lines...)
156136
}
157137

158138
func formatHostStatus(upToDate, outdated int) string {
@@ -169,13 +149,6 @@ func formatSystemKeySerial(serial int) string {
169149
return fmt.Sprintf(i18n.T("dashboard.system_key_serial"), serial)
170150
}
171151

172-
func chooseOutdatedStyle(outdated int, normal, warn lipgloss.Style) lipgloss.Style {
173-
if outdated > 0 {
174-
return warn
175-
}
176-
return normal
177-
}
178-
179152
func formatLogEntry(al AuditLogEntry, width int) string {
180153
ts := parseTimestamp(al.Timestamp)
181154
action := titleFromUnderscore(strings.TrimSpace(al.Action))
@@ -198,6 +171,24 @@ func formatLogEntry(al AuditLogEntry, width int) string {
198171
return timestampStyle.Render(padRight(ts, 12)) + " | " + actionStyle.Render(actionPadded) + " | " + detailStyle.Render(details)
199172
}
200173

174+
func formatAlgoSpread(algoCounts map[string]int, style lipgloss.Style) string {
175+
if len(algoCounts) == 0 {
176+
return "-"
177+
}
178+
179+
algorithms := make([]string, 0, len(algoCounts))
180+
for algorithm := range algoCounts {
181+
algorithms = append(algorithms, algorithm)
182+
}
183+
slices.Sort(algorithms)
184+
185+
parts := make([]string, 0, len(algorithms))
186+
for _, algorithm := range algorithms {
187+
parts = append(parts, style.Render(fmt.Sprintf("%s: %d", algorithm, algoCounts[algorithm])))
188+
}
189+
return strings.Join(parts, ", ")
190+
}
191+
201192
// TODO decide if this function handles date, time or datetime
202193
func parseTimestamp(raw string) string {
203194
raw = strings.TrimSpace(raw)

0 commit comments

Comments
 (0)