Skip to content

Commit 9e27202

Browse files
fix: defer column options save to modal close and report config errors
Avoid race condition from concurrent saves on each keypress by deferring saveColumnOptions() to when the modal closes (esc). Report config load/save failures via flash message instead of silently swallowing them. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent d64b8b6 commit 9e27202

File tree

4 files changed

+17
-5
lines changed

4 files changed

+17
-5
lines changed

cmd/roborev/tui/handlers_queue.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,10 @@ func (m model) handleColumnOptionsInput(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
199199
switch msg.String() {
200200
case "esc":
201201
m.currentView = m.colOptionsReturnView
202+
if m.colOptionsDirty {
203+
m.colOptionsDirty = false
204+
return m, m.saveColumnOptions()
205+
}
202206
return m, nil
203207
case "ctrl+c":
204208
return m, tea.Quit
@@ -219,7 +223,7 @@ func (m model) handleColumnOptionsInput(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
219223
m.colOptionsList[m.colOptionsIdx+1], m.colOptionsList[m.colOptionsIdx]
220224
m.colOptionsIdx++
221225
m.syncColumnOrderFromOptions()
222-
return m, m.saveColumnOptions()
226+
m.colOptionsDirty = true
223227
}
224228
return m, nil
225229
case "k":
@@ -229,7 +233,7 @@ func (m model) handleColumnOptionsInput(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
229233
m.colOptionsList[m.colOptionsIdx-1], m.colOptionsList[m.colOptionsIdx]
230234
m.colOptionsIdx--
231235
m.syncColumnOrderFromOptions()
232-
return m, m.saveColumnOptions()
236+
m.colOptionsDirty = true
233237
}
234238
return m, nil
235239
case " ", "enter":
@@ -238,6 +242,7 @@ func (m model) handleColumnOptionsInput(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
238242
if opt.id == colOptionBorders {
239243
opt.enabled = !opt.enabled
240244
m.colBordersOn = opt.enabled
245+
m.colOptionsDirty = true
241246
} else if m.colOptionsReturnView == viewTasks {
242247
// Tasks view: no visibility toggle (all columns always shown)
243248
return m, nil
@@ -251,8 +256,8 @@ func (m model) handleColumnOptionsInput(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
251256
}
252257
m.hiddenColumns[opt.id] = true
253258
}
259+
m.colOptionsDirty = true
254260
}
255-
return m, m.saveColumnOptions()
256261
}
257262
return m, nil
258263
}

cmd/roborev/tui/render_queue.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -777,13 +777,15 @@ func (m model) saveColumnOptions() tea.Cmd {
777777
return func() tea.Msg {
778778
cfg, err := config.LoadGlobal()
779779
if err != nil {
780-
return nil
780+
return configSaveErrMsg{err: fmt.Errorf("load config: %w", err)}
781781
}
782782
cfg.HiddenColumns = hidden
783783
cfg.ColumnBorders = borders
784784
cfg.ColumnOrder = colOrd
785785
cfg.TaskColumnOrder = taskColOrd
786-
config.SaveGlobal(cfg)
786+
if err := config.SaveGlobal(cfg); err != nil {
787+
return configSaveErrMsg{err: fmt.Errorf("save config: %w", err)}
788+
}
787789
return nil
788790
}
789791
}

cmd/roborev/tui/tui.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,7 @@ type model struct {
388388
// Column options modal
389389
colOptionsIdx int // Cursor in modal
390390
colOptionsList []columnOption // Items in modal (columns + borders toggle)
391+
colOptionsDirty bool // True if options changed since modal opened
391392
colBordersOn bool // Column borders enabled
392393
hiddenColumns map[int]bool // Set of hidden column IDs
393394
columnOrder []int // Ordered toggleable queue columns
@@ -659,6 +660,9 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
659660
return m.handlePatchResultMsg(msg)
660661
case applyPatchResultMsg:
661662
return m.handleApplyPatchResultMsg(msg)
663+
case configSaveErrMsg:
664+
m.setFlash("Config save failed: "+msg.err.Error(), 5*time.Second, m.currentView)
665+
return m, nil
662666
}
663667
return m, nil
664668
}

cmd/roborev/tui/types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ type rerunResultMsg struct {
148148
err error
149149
}
150150
type errMsg error
151+
type configSaveErrMsg struct{ err error }
151152
type jobsErrMsg struct {
152153
err error
153154
seq int // fetch sequence number for staleness check

0 commit comments

Comments
 (0)