From 26210c4afb856f194fb040fb3eeec76b04a2ea47 Mon Sep 17 00:00:00 2001 From: Robin Olsen Date: Fri, 20 Mar 2026 12:42:48 +0100 Subject: [PATCH] centralize submission handling --- pkg/tui/views/dashboard/model.go | 12 ++++++++++ pkg/tui/views/dashboard/operations.go | 31 ++++++++++++++------------ pkg/tui/views/kanban/model.go | 11 +++++++++ pkg/tui/views/kanban/operations.go | 32 +++++++++++++++------------ 4 files changed, 58 insertions(+), 28 deletions(-) diff --git a/pkg/tui/views/dashboard/model.go b/pkg/tui/views/dashboard/model.go index 9ca4fce..a1bce80 100644 --- a/pkg/tui/views/dashboard/model.go +++ b/pkg/tui/views/dashboard/model.go @@ -143,6 +143,18 @@ func (m *Model) logAction(action string) { } } +// submitValidation sends a validation request to the submit channel. +// Call this after every successful user action that modifies issues. +func (m *Model) submitValidation() { + if m.submitChan != nil { + select { + case m.submitChan <- struct{}{}: + m.logAction("tui submitted validation") + default: + } + } +} + func (m *Model) startEditTitle(selected ListIssue) { m.editingTitle = true m.editingIssueID = selected.ID diff --git a/pkg/tui/views/dashboard/operations.go b/pkg/tui/views/dashboard/operations.go index b2d6e81..a5c4da4 100644 --- a/pkg/tui/views/dashboard/operations.go +++ b/pkg/tui/views/dashboard/operations.go @@ -41,17 +41,17 @@ func (m *Model) refreshIssueListsAndSelectIssue(issueID string) tea.Cmd { } } - if m.submitChan != nil { - select { - case m.submitChan <- struct{}{}: - m.logAction("tui submitted validation") - default: - } - } - return tea.Sequence(setItemsCmd, func() tea.Msg { return msgs.SelectIssueMsg{IssueID: issueID} }) } +// refreshAndSubmit refreshes the issue lists and submits validation. +// This is a wrapper that should be used after any successful user action. +func (m *Model) refreshAndSubmit(issueID string) tea.Cmd { + refreshCmd := m.refreshIssueListsAndSelectIssue(issueID) + m.submitValidation() + return refreshCmd +} + func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case msgs.TitleUpdatedMsg: @@ -63,7 +63,7 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, nil } m.logAction("tui updated issue title") - return m, m.refreshIssueListsAndSelectIssue(msg.IssueID) + return m, m.refreshAndSubmit(msg.IssueID) case msgs.DescriptionUpdatedMsg: m.editingDescription = false @@ -74,7 +74,7 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, nil } m.logAction("tui updated issue description") - return m, m.refreshIssueListsAndSelectIssue(msg.IssueID) + return m, m.refreshAndSubmit(msg.IssueID) case msgs.StatusUpdatedMsg: m.choosingStatus = false @@ -84,7 +84,7 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, nil } m.logAction("tui updated issue status") - return m, m.refreshIssueListsAndSelectIssue(msg.IssueID) + return m, m.refreshAndSubmit(msg.IssueID) case msgs.PriorityUpdatedMsg: m.choosingPriority = false @@ -94,7 +94,7 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, nil } m.logAction("tui updated issue priority") - return m, m.refreshIssueListsAndSelectIssue(msg.IssueID) + return m, m.refreshAndSubmit(msg.IssueID) case msgs.TypeUpdatedMsg: m.choosingType = false @@ -104,7 +104,7 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, nil } m.logAction("tui updated issue type") - return m, m.refreshIssueListsAndSelectIssue(msg.IssueID) + return m, m.refreshAndSubmit(msg.IssueID) case msgs.AssigneeUpdatedMsg: m.editingAssignee = false @@ -115,7 +115,7 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, nil } m.logAction("tui updated issue assignee") - return m, m.refreshIssueListsAndSelectIssue(msg.IssueID) + return m, m.refreshAndSubmit(msg.IssueID) case msgs.SelectIssueMsg: m.issueList.SelectIssueID(msg.IssueID) @@ -150,6 +150,7 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.setDetailIssueWithComments(*selectedIssue) m.logAction("tui created issue") + m.submitValidation() return m, tea.Sequence(setItemsCmd, func() tea.Msg { return msgs.SelectIssueMsg{IssueID: selectedIssue.ID} }) case msgs.IssueCommentAddedMsg: m.addingComment = false @@ -159,6 +160,7 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { if msg.Err != nil { return m, nil } + m.submitValidation() return m, m.refreshIssueListsAndSelectIssue(msg.IssueID) case msgs.DeletedMsg: m.confirmingDelete = false @@ -168,6 +170,7 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, nil } m.logAction("tui deleted issue") + m.submitValidation() return m, m.refreshIssueListsAndSelectIssue(msg.IssueID) case tea.KeyPressMsg: diff --git a/pkg/tui/views/kanban/model.go b/pkg/tui/views/kanban/model.go index ad9d68c..d1afc1d 100644 --- a/pkg/tui/views/kanban/model.go +++ b/pkg/tui/views/kanban/model.go @@ -178,6 +178,17 @@ func (m *Model) logAction(action string) { } } +// submitValidation sends a validation request to the submit channel. +func (m *Model) submitValidation() { + if m.submitChan != nil { + select { + case m.submitChan <- struct{}{}: + m.logAction("tui submitted validation") + default: + } + } +} + func (m *Model) Init() tea.Cmd { if m.submitChan != nil { m.submitChan <- struct{}{} diff --git a/pkg/tui/views/kanban/operations.go b/pkg/tui/views/kanban/operations.go index b19ac84..dd4d73c 100644 --- a/pkg/tui/views/kanban/operations.go +++ b/pkg/tui/views/kanban/operations.go @@ -54,17 +54,17 @@ func (m *Model) refreshIssueListsAndSelectIssue(issueID string) tea.Cmd { m.blockedList.SelectIssueID(issueID) m.doneList.SelectIssueID(issueID) - if m.submitChan != nil { - select { - case m.submitChan <- struct{}{}: - m.logAction("tui submitted validation") - default: - } - } - return tea.Sequence(todoCmd, inProgCmd, blockedCmd, doneCmd) } +// refreshAndSubmit refreshes the issue lists and submits validation. +// This is a wrapper that should be used after any successful user action. +func (m *Model) refreshAndSubmit(issueID string) tea.Cmd { + refreshCmd := m.refreshIssueListsAndSelectIssue(issueID) + m.submitValidation() + return refreshCmd +} + func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case msgs.TitleUpdatedMsg: @@ -74,7 +74,7 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { if msg.Err != nil { return m, nil } - return m, m.refreshIssueListsAndSelectIssue(msg.IssueID) + return m, m.refreshAndSubmit(msg.IssueID) case msgs.DescriptionUpdatedMsg: m.editingDescription = false @@ -83,7 +83,7 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { if msg.Err != nil { return m, nil } - return m, m.refreshIssueListsAndSelectIssue(msg.IssueID) + return m, m.refreshAndSubmit(msg.IssueID) case msgs.StatusUpdatedMsg: m.choosingStatus = false @@ -91,7 +91,7 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { if msg.Err != nil { return m, nil } - return m, m.refreshIssueListsAndSelectIssue(msg.IssueID) + return m, m.refreshAndSubmit(msg.IssueID) case msgs.PriorityUpdatedMsg: m.choosingPriority = false @@ -99,7 +99,7 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { if msg.Err != nil { return m, nil } - return m, m.refreshIssueListsAndSelectIssue(msg.IssueID) + return m, m.refreshAndSubmit(msg.IssueID) case msgs.TypeUpdatedMsg: m.choosingType = false @@ -107,7 +107,7 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { if msg.Err != nil { return m, nil } - return m, m.refreshIssueListsAndSelectIssue(msg.IssueID) + return m, m.refreshAndSubmit(msg.IssueID) case msgs.AssigneeUpdatedMsg: m.editingAssignee = false @@ -116,7 +116,7 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { if msg.Err != nil { return m, nil } - return m, m.refreshIssueListsAndSelectIssue(msg.IssueID) + return m, m.refreshAndSubmit(msg.IssueID) case msgs.SelectIssueMsg: m.todoList.SelectIssueID(msg.IssueID) @@ -160,6 +160,7 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } m.issueDetail.SetIssue(*selectedIssue) + m.submitValidation() return m, tea.Sequence(todoCmd, inProgCmd, blockedCmd, doneCmd, func() tea.Msg { return msgs.SelectIssueMsg{IssueID: selectedIssue.ID} }) case msgs.DeletedMsg: m.confirmingDelete = false @@ -185,6 +186,7 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // If there are no msgs at all, clear the detail view and return. if len(todoIssues) == 0 && len(inProgIssues) == 0 && len(blockedIssues) == 0 && len(doneIssues) == 0 { m.issueDetail.SetIssue(models.Issue{}) + m.submitValidation() return m, tea.Sequence(todoCmd, inProgCmd, blockedCmd, doneCmd) } @@ -252,6 +254,7 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // Safety: if targetIssues is still empty here, just clear detail and return. if len(targetIssues) == 0 { m.issueDetail.SetIssue(models.Issue{}) + m.submitValidation() return m, tea.Sequence(todoCmd, inProgCmd, blockedCmd, doneCmd) } @@ -261,6 +264,7 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } selectedIssue := targetIssues[newIndex] m.issueDetail.SetIssue(*selectedIssue) + m.submitValidation() return m, tea.Sequence(todoCmd, inProgCmd, blockedCmd, doneCmd, func() tea.Msg { return msgs.SelectIssueMsg{IssueID: selectedIssue.ID} })