Skip to content

Commit 8e6d58c

Browse files
gitcoder89431claude
andcommitted
feat: show conflict and error badges in header
meshd | mini | ⚠ 2 | ✗ 1 — yellow conflict count and red error count appear next to device name, separated by pipes, only when nonzero. Conflict count updates from ConflictsLoadedMsg; error count from FolderStatus.Errors (already polled by the dashboard event loop). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 8e5f690 commit 8e6d58c

6 files changed

Lines changed: 24 additions & 6 deletions

File tree

internal/app/app.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ type Model struct {
5555
currentSyncItem string // file currently being transferred, shown in header
5656
transferIn int64 // session bytes received
5757
transferOut int64 // session bytes sent
58+
conflictCount int
59+
errorCount int
5860
}
5961

6062
func New(meta BuildInfo, client *syncthing.Client, syncthingURL string) Model {

internal/app/update.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
6060
case screens.DashboardLoadedMsg:
6161
if msg.Err == nil {
6262
m.lastFolderStatus = msg.FolderStatus
63+
m.errorCount = msg.FolderStatus.Errors
6364
m.syncStatus = formatSyncStatus(msg.FolderStatus, m.spinnerFrame, m.currentSyncItem, m.theme)
6465
// seed activity log with current state on first load
6566
if !m.activitySeeded {
@@ -77,6 +78,7 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
7778
return m, nil
7879
case screens.DashboardEventMsg:
7980
m.lastFolderStatus = msg.FolderStatus
81+
m.errorCount = msg.FolderStatus.Errors
8082
m.activity, m.currentSyncItem = appendActivity(m.activity, msg.Events, &m.lastActivityState, m.currentSyncItem)
8183
m.syncStatus = formatSyncStatus(msg.FolderStatus, m.spinnerFrame, m.currentSyncItem, m.theme)
8284
var cmds []tea.Cmd
@@ -117,6 +119,9 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
117119
}
118120
return m, nil
119121
case screens.ConflictsLoadedMsg, screens.ConflictResolvedMsg:
122+
if loaded, ok := msg.(screens.ConflictsLoadedMsg); ok && loaded.Err == nil {
123+
m.conflictCount = len(loaded.Conflicts)
124+
}
120125
if s, ok := m.screens["conflicts"].(screens.Conflicts); ok {
121126
updated, cmd := s.Update(msg)
122127
m.screens["conflicts"] = updated

internal/app/view.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ func (m Model) View() tea.View {
2323
dims := layout.Calculate(m.width, m.height, m.showSidebar)
2424
active := m.screens[m.activeScreen]
2525

26-
head := clipHeight(header.View(header.Model{AppName: config.AppName, DeviceID: m.deviceID, DeviceName: m.deviceName, TransferIn: m.transferIn, TransferOut: m.transferOut}, dims.Header.Width, dims.Header.Height, m.theme), dims.Header.Height)
26+
head := clipHeight(header.View(header.Model{AppName: config.AppName, DeviceID: m.deviceID, DeviceName: m.deviceName, TransferIn: m.transferIn, TransferOut: m.transferOut, ConflictCount: m.conflictCount, ErrorCount: m.errorCount}, dims.Header.Width, dims.Header.Height, m.theme), dims.Header.Height)
2727

2828
footBindings := m.keys.ShortHelp()
2929
type footerBinder interface{ FooterBindings() []key.Binding }

internal/components/header/header.go

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@ import (
99
)
1010

1111
type Model struct {
12-
AppName string
13-
DeviceID string // full device ID (fallback if no name)
14-
DeviceName string // human-readable device name (preferred)
15-
TransferIn int64 // session bytes received
16-
TransferOut int64 // session bytes sent
12+
AppName string
13+
DeviceID string // full device ID (fallback if no name)
14+
DeviceName string // human-readable device name (preferred)
15+
TransferIn int64 // session bytes received
16+
TransferOut int64 // session bytes sent
17+
ConflictCount int
18+
ErrorCount int
1719
}
1820

1921
func View(m Model, width, height int, t theme.Theme) string {
@@ -32,6 +34,12 @@ func View(m Model, width, height int, t theme.Theme) string {
3234
if label != "" {
3335
left += t.Border.Render(" | ") + t.Muted.Render(label)
3436
}
37+
if m.ConflictCount > 0 {
38+
left += t.Border.Render(" | ") + t.Warn.Render(fmt.Sprintf("⚠ %d", m.ConflictCount))
39+
}
40+
if m.ErrorCount > 0 {
41+
left += t.Border.Render(" | ") + t.Error.Render(fmt.Sprintf("✗ %d", m.ErrorCount))
42+
}
3543
outStr, inStr := "—", "—"
3644
if m.TransferOut >= 1024 {
3745
outStr = formatBytes(m.TransferOut)

internal/syncthing/client.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,7 @@ func (c *Client) GetFolderStatus() (FolderStatus, error) {
489489
State string `json:"state"`
490490
StateChanged string `json:"stateChanged"`
491491
NeedFiles int `json:"needFiles"`
492+
Errors int `json:"errors"`
492493
Completion float64 `json:"completion"`
493494
}
494495
if err := c.get("/rest/db/status?folder="+MeshdFolderID, &raw); err != nil {
@@ -499,6 +500,7 @@ func (c *Client) GetFolderStatus() (FolderStatus, error) {
499500
State: FolderState(raw.State),
500501
Completion: raw.Completion,
501502
NeedFiles: raw.NeedFiles,
503+
Errors: raw.Errors,
502504
StateChangedAt: changedAt,
503505
}, nil
504506
}

internal/syncthing/types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ type FolderStatus struct {
2828
State FolderState
2929
Completion float64
3030
NeedFiles int
31+
Errors int
3132
StateChangedAt time.Time
3233
ScanTotal int64
3334
ScanCurrent int64

0 commit comments

Comments
 (0)