@@ -108,17 +108,23 @@ func (m Model) View() string {
108108 }
109109
110110 recentActivityRows := recentActivityTableRows (m .data .RecentLogs )
111+ accountsLine := fmt .Sprintf (i18n .T ("dashboard.accounts" ), m .data .ActiveAccountCount , m .data .AccountCount )
112+ publicKeysLine := fmt .Sprintf (i18n .T ("dashboard.public_keys" ), m .data .PublicKeyCount , m .data .GlobalKeyCount )
113+ currentLine := fmt .Sprintf (i18n .T ("dashboard.hosts_current_key" ), m .data .HostsUpToDate )
114+ dirtyLine := fmt .Sprintf (i18n .T ("dashboard.hosts_past_keys" ), m .data .HostsOutdated )
115+ accountsRendered , publicKeysRendered := renderAlignedPair (accountsLine , publicKeysLine , valueStyle , valueStyle , false )
116+ currentRendered , dirtyRendered := renderAlignedPair (currentLine , dirtyLine , valueStyle , warnValueStyle , true )
111117
112118 lines := []string {
113119 sectionTitleStyle .Render (i18n .T ("dashboard.system_status" )),
114120 "" ,
115- valueStyle . Render ( fmt . Sprintf ( i18n . T ( "dashboard.accounts" ), m . data . ActiveAccountCount , m . data . AccountCount )) ,
116- valueStyle . Render ( fmt . Sprintf ( i18n . T ( "dashboard.public_keys" ), m . data . PublicKeyCount , m . data . GlobalKeyCount )) ,
121+ accountsRendered ,
122+ publicKeysRendered ,
117123 "" ,
118124 sectionTitleStyle .Render (i18n .T ("dashboard.deployment_status" )),
119125 "" ,
120- valueStyle . Render ( fmt . Sprintf ( i18n . T ( "dashboard.hosts_current_key" ), m . data . HostsUpToDate )) ,
121- warnValueStyle . Render ( fmt . Sprintf ( i18n . T ( "dashboard.hosts_past_keys" ), m . data . HostsOutdated )) ,
126+ currentRendered ,
127+ dirtyRendered ,
122128 "" ,
123129 sectionTitleStyle .Render (i18n .T ("dashboard.security_posture" )),
124130 "" ,
@@ -186,6 +192,36 @@ func recentActivityTableRows(logs []AuditLogEntry) []recentActivityRow {
186192 })
187193}
188194
195+ func renderAlignedPair (line1 , line2 string , style1 , style2 lipgloss.Style , alignValueRight bool ) (string , string ) {
196+ label1 , value1 := splitLabelValue (line1 )
197+ label2 , value2 := splitLabelValue (line2 )
198+ labelWidth := max (lipgloss .Width (label1 ), lipgloss .Width (label2 ))
199+ labelRenderer := lipgloss .NewStyle ().Width (labelWidth )
200+
201+ valueRenderer := lipgloss .NewStyle ()
202+ if alignValueRight {
203+ valueWidth := max (lipgloss .Width (value1 ), lipgloss .Width (value2 ))
204+ valueRenderer = valueRenderer .Width (valueWidth ).Align (lipgloss .Right )
205+ }
206+
207+ render := func (label , value string , style lipgloss.Style ) string {
208+ if value == "" {
209+ return style .Render (label )
210+ }
211+ return style .Render (labelRenderer .Render (label ) + " " + valueRenderer .Render (value ))
212+ }
213+
214+ return render (label1 , value1 , style1 ), render (label2 , value2 , style2 )
215+ }
216+
217+ func splitLabelValue (line string ) (string , string ) {
218+ parts := strings .SplitN (line , ":" , 2 )
219+ if len (parts ) < 2 {
220+ return line , ""
221+ }
222+ return parts [0 ] + ":" , strings .TrimSpace (parts [1 ])
223+ }
224+
189225// TODO decide if this function handles date, time or datetime
190226func parseTimestamp (raw string ) string {
191227 raw = strings .TrimSpace (raw )
0 commit comments