From 14e64f73f2f2c03e06633b4d743e0a608e22d3df Mon Sep 17 00:00:00 2001 From: Robin Olsen Date: Fri, 20 Mar 2026 17:11:51 +0100 Subject: [PATCH] fix close modal --- pkg/tui/components/helpbar.go | 4 ++++ pkg/tui/components/keymap.go | 2 +- pkg/tui/modal/confirm.go | 26 +++++++++++++------------- pkg/tui/modal/manager.go | 9 +++++++++ pkg/tui/modal/modal.go | 1 + pkg/tui/views/dashboard/keys.go | 9 ++------- pkg/tui/views/dashboard/operations.go | 17 ++++++++++++++++- pkg/tui/views/kanban/keys.go | 3 ++- pkg/tui/views/kanban/operations.go | 17 ++++++++++++++++- 9 files changed, 64 insertions(+), 24 deletions(-) diff --git a/pkg/tui/components/helpbar.go b/pkg/tui/components/helpbar.go index 27ec2a7..004b237 100644 --- a/pkg/tui/components/helpbar.go +++ b/pkg/tui/components/helpbar.go @@ -177,6 +177,7 @@ func helpBarConfig(view ViewKind) HelpBarConfig { {Key: "v", Desc: "kanban"}, {Key: "↑/k", Desc: "up"}, {Key: "↓/j", Desc: "down"}, + {Key: "/", Desc: "search"}, {Key: "a", Desc: "add"}, {Key: "c", Desc: "comment"}, {Key: "e/d/s/p/t/A", Desc: "edit"}, @@ -188,6 +189,7 @@ func helpBarConfig(view ViewKind) HelpBarConfig { {Key: "v", Desc: "kanban"}, {Key: "↑/k", Desc: "up"}, {Key: "↓/j", Desc: "down"}, + {Key: "/", Desc: "search"}, {Key: "a", Desc: "add issue"}, {Key: "c", Desc: "add comment"}, {Key: "x", Desc: "delete issue"}, @@ -208,6 +210,7 @@ func helpBarConfig(view ViewKind) HelpBarConfig { {Key: "v", Desc: "list view"}, {Key: "↑/k", Desc: "up"}, {Key: "↓/j", Desc: "down"}, + {Key: "/", Desc: "search"}, {Key: "pgup/pgdn", Desc: "page"}, {Key: "h/l", Desc: "column"}, {Key: "←/→", Desc: "move"}, @@ -223,6 +226,7 @@ func helpBarConfig(view ViewKind) HelpBarConfig { {Key: "←/→", Desc: "move issue"}, {Key: "↑/k", Desc: "up"}, {Key: "↓/j", Desc: "down"}, + {Key: "/", Desc: "search"}, {Key: "pgup", Desc: "page up"}, {Key: "pgdn", Desc: "page down"}, {Key: "a", Desc: "add issue"}, diff --git a/pkg/tui/components/keymap.go b/pkg/tui/components/keymap.go index c5bc96e..d5baf34 100644 --- a/pkg/tui/components/keymap.go +++ b/pkg/tui/components/keymap.go @@ -27,7 +27,7 @@ func DefaultCommonKeyMap() CommonKeyMap { key.WithHelp("?", "help"), ), Quit: key.NewBinding( - key.WithKeys("q", "ctrl+c"), + key.WithKeys("q"), key.WithHelp("q", "quit"), ), ScrollUp: key.NewBinding( diff --git a/pkg/tui/modal/confirm.go b/pkg/tui/modal/confirm.go index 20e9a8b..c9e2843 100644 --- a/pkg/tui/modal/confirm.go +++ b/pkg/tui/modal/confirm.go @@ -93,22 +93,22 @@ func (c *ConfirmModal) Update(msg tea.Msg) (tea.Cmd, bool) { // Check yes keys if slices.Contains(c.yesKeys, s) { - c.Deactivate() - return func() tea.Msg { - return ModalCompletedMsg{ - ModalID: c.ID(), - Value: ConfirmResult{Confirmed: true}, - } - }, true - } + c.Deactivate() + return func() tea.Msg { + return ModalCompletedMsg{ + ModalID: c.ID(), + Value: ConfirmResult{Confirmed: true}, + } + }, true + } // Check no/cancel keys if slices.Contains(c.noKeys, s) { - c.Deactivate() - return func() tea.Msg { - return ModalCancelledMsg{ModalID: c.ID()} - }, true - } + c.Deactivate() + return func() tea.Msg { + return ModalCancelledMsg{ModalID: c.ID()} + }, true + } } return nil, true diff --git a/pkg/tui/modal/manager.go b/pkg/tui/modal/manager.go index 3250677..f166d10 100644 --- a/pkg/tui/modal/manager.go +++ b/pkg/tui/modal/manager.go @@ -163,6 +163,15 @@ func (m *Manager) RenderWithMainView(mainView string) string { // RegisterCommonModals registers the standard set of modals used across views. // This helper reduces duplication between dashboard and kanban views. func RegisterCommonModals(m *Manager) { + + // Exit Confirm Modal + m.RegisterModal(NewConfirmModal(ConfirmConfig{ + ID: ModalConfirmExit, + Message: "Close the task and interface?", + YesKeys: []string{"y", "Y"}, + NoKeys: []string{"n", "N", "esc"}, + })) + // Edit Title Modal m.RegisterModal(NewTextInputModal(TextInputConfig{ ID: ModalEditTitle, diff --git a/pkg/tui/modal/modal.go b/pkg/tui/modal/modal.go index 0e3e3d6..151fc85 100644 --- a/pkg/tui/modal/modal.go +++ b/pkg/tui/modal/modal.go @@ -50,6 +50,7 @@ type ModalCancelledMsg struct { // Modal IDs used across the application const ( + ModalConfirmExit = "confirm-exit" ModalEditTitle = "edit-title" ModalCreateIssue = "create-issue" ModalEditAssignee = "edit-assignee" diff --git a/pkg/tui/views/dashboard/keys.go b/pkg/tui/views/dashboard/keys.go index 8cce7cc..34187f4 100644 --- a/pkg/tui/views/dashboard/keys.go +++ b/pkg/tui/views/dashboard/keys.go @@ -10,11 +10,6 @@ import ( type KeyMap struct { components.CommonKeyMap SwitchToKanbanBoard key.Binding - Quit key.Binding - SelectIssue key.Binding - BackToList key.Binding - ScrollUp key.Binding - ScrollDown key.Binding EditTitle key.Binding EditDescription key.Binding ChangeStatus key.Binding @@ -78,8 +73,8 @@ func (m *Model) handleKeyPressMsg(msg tea.KeyPressMsg) tea.Cmd { m.logAction("tui toggled help") case m.notInModalMsgWithKey(msg, m.keyMap.Quit): - m.logAction("tui quit requested") - return tea.Quit + m.logAction("tui opened exit confirmation") + return m.startConfirmExit() case m.notInModalMsgWithKey(msg, m.keyMap.SwitchToKanbanBoard): return func() tea.Msg { return msgs.SwitchToKanbanBoardMsg{} } diff --git a/pkg/tui/views/dashboard/operations.go b/pkg/tui/views/dashboard/operations.go index b27d26d..8b72da6 100644 --- a/pkg/tui/views/dashboard/operations.go +++ b/pkg/tui/views/dashboard/operations.go @@ -34,6 +34,10 @@ func (m *Model) refreshAndSubmit(issueID string) tea.Cmd { return refreshCmd } +func (m *Model) startConfirmExit() tea.Cmd { + return m.modalManager.ShowModal(modal.ModalConfirmExit) +} + func (m *Model) startEditTitle(selected ListIssue) tea.Cmd { m.currentIssueID = selected.ID titleModal := m.modalManager.GetTextInputModal(modal.ModalEditTitle) @@ -113,6 +117,11 @@ func (m *Model) startAddComment(selected ListIssue) tea.Cmd { // handleModalCompleted handles all modal completion messages func (m *Model) handleModalCompleted(msg modal.ModalCompletedMsg) tea.Cmd { switch msg.ModalID { + case modal.ModalConfirmExit: + if r, ok := msg.Value.(modal.ConfirmResult); ok && r.Confirmed { + m.logAction("tui confirmed exit") + return tea.Quit + } case modal.ModalEditTitle: if r, ok := msg.Value.(modal.TextInputResult); ok { m.logAction("tui submitted issue title edit") @@ -196,6 +205,8 @@ func (m *Model) handleModalCompleted(msg modal.ModalCompletedMsg) tea.Cmd { // handleModalCancelled handles all modal cancellation messages func (m *Model) handleModalCancelled(msg modal.ModalCancelledMsg) { switch msg.ModalID { + case modal.ModalConfirmExit: + m.logAction("tui canceled exit") case modal.ModalEditTitle: m.currentIssueID = "" m.logAction("tui canceled issue title edit") @@ -354,6 +365,10 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, m.refreshIssueListsAndSelectIssue(msg.IssueID) case tea.KeyPressMsg: + if msg.String() == "ctrl+c" { + return m, tea.Quit + } + if m.issueList.FilterState() == list.Filtering { cmd, _ := m.issueList.Update(msg) return m, cmd @@ -364,7 +379,7 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } cmd := m.handleKeyPressMsg(msg) - if cmd != nil { + if cmd != nil || m.IsInModal() { return m, cmd } diff --git a/pkg/tui/views/kanban/keys.go b/pkg/tui/views/kanban/keys.go index 85f8be8..4017711 100644 --- a/pkg/tui/views/kanban/keys.go +++ b/pkg/tui/views/kanban/keys.go @@ -54,7 +54,8 @@ func (m *Model) handleKeyPressMsg(msg tea.KeyPressMsg) tea.Cmd { m.helpBar.ToggleHelp() case m.notInModalMsgWithKey(msg, m.keyMap.Quit): - return tea.Quit + m.logAction("tui opened exit confirmation") + return m.startConfirmExit() case m.notInModalMsgWithKey(msg, m.keyMap.SwitchToDashboard): return func() tea.Msg { return msgs.SwitchToDashboardMsg{} } diff --git a/pkg/tui/views/kanban/operations.go b/pkg/tui/views/kanban/operations.go index 7884f7f..5e767bb 100644 --- a/pkg/tui/views/kanban/operations.go +++ b/pkg/tui/views/kanban/operations.go @@ -62,6 +62,10 @@ func (m *Model) refreshAndSubmit(issueID string) tea.Cmd { // Modal action handlers +func (m *Model) startConfirmExit() tea.Cmd { + return m.modalManager.ShowModal(modal.ModalConfirmExit) +} + func (m *Model) startEditTitle(selected ListIssue) tea.Cmd { m.currentIssueID = selected.ID titleModal := m.modalManager.GetTextInputModal(modal.ModalEditTitle) @@ -141,6 +145,11 @@ func (m *Model) startAddComment(selected ListIssue) tea.Cmd { // handleModalCompleted handles all modal completion messages func (m *Model) handleModalCompleted(msg modal.ModalCompletedMsg) tea.Cmd { switch msg.ModalID { + case modal.ModalConfirmExit: + if r, ok := msg.Value.(modal.ConfirmResult); ok && r.Confirmed { + m.logAction("tui confirmed exit") + return tea.Quit + } case modal.ModalEditTitle: if r, ok := msg.Value.(modal.TextInputResult); ok { cmd := msgs.UpdateIssueTitleCmd(m.app, m.currentIssueID, r.Value) @@ -218,6 +227,8 @@ func (m *Model) handleModalCompleted(msg modal.ModalCompletedMsg) tea.Cmd { // handleModalCancelled handles all modal cancellation messages func (m *Model) handleModalCancelled(msg modal.ModalCancelledMsg) { switch msg.ModalID { + case modal.ModalConfirmExit: + m.logAction("tui canceled exit") case modal.ModalEditTitle: m.currentIssueID = "" case modal.ModalCreateIssue: @@ -458,6 +469,10 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { }) case tea.KeyPressMsg: + if msg.String() == "ctrl+c" { + return m, tea.Quit + } + fl := m.FocusedIssueList() if fl.FilterState() == list.Filtering { cmd, _ := fl.Update(msg) @@ -469,7 +484,7 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } cmd := m.handleKeyPressMsg(msg) - if cmd != nil { + if cmd != nil || m.IsInModal() { return m, cmd }