From 54427a384ed0633c285bdf2475b00b547305ce6d Mon Sep 17 00:00:00 2001 From: jcleira Date: Tue, 27 Jan 2026 09:25:41 +0100 Subject: [PATCH] Add Loading State During Workspace Deletion * Objective Keep the confirmation dialog open with a "Deleting..." message while the workspace deletion is in progress. * Why Previously, the dialog closed immediately after pressing 'y', leaving users without visual feedback during long deletions, such as when removing large `node_modules` directories. * How This commit adds a loading state to the confirmation dialog, showing a "Deleting..." message until the deletion completes. --- pkg/ui/dashboard/confirm.go | 49 +++++++++++++++++++++++++++++++++-- pkg/ui/dashboard/dashboard.go | 13 +++++++--- 2 files changed, 56 insertions(+), 6 deletions(-) diff --git a/pkg/ui/dashboard/confirm.go b/pkg/ui/dashboard/confirm.go index 06319ab..927e8a1 100644 --- a/pkg/ui/dashboard/confirm.go +++ b/pkg/ui/dashboard/confirm.go @@ -17,6 +17,7 @@ type ConfirmModel struct { keys KeyMap confirmed bool canceled bool + deleting bool } // NewConfirm creates a new confirmation dialog. @@ -46,9 +47,23 @@ func (m ConfirmModel) IsCanceled() bool { // IsDone returns true if the dialog is complete. func (m ConfirmModel) IsDone() bool { + if m.deleting { + return false + } return m.confirmed || m.canceled } +// SetDeleting sets the deleting state. +func (m ConfirmModel) SetDeleting(deleting bool) ConfirmModel { + m.deleting = deleting + return m +} + +// IsDeleting returns true if a deletion is in progress. +func (m ConfirmModel) IsDeleting() bool { + return m.deleting +} + // Init initializes the component. func (m ConfirmModel) Init() tea.Cmd { return nil @@ -56,6 +71,10 @@ func (m ConfirmModel) Init() tea.Cmd { // Update handles messages. func (m ConfirmModel) Update(msg tea.Msg) (ConfirmModel, tea.Cmd) { + if m.deleting { + return m, nil + } + if keyMsg, ok := msg.(tea.KeyMsg); ok { switch { case key.Matches(keyMsg, m.keys.Confirm): @@ -84,6 +103,32 @@ func (m ConfirmModel) View() string { Bold(true). Foreground(warningColor) + if m.deleting { + b.WriteString(titleStyle.Render("Deleting Workspace")) + b.WriteString("\n\n") + b.WriteString("Deleting workspace and cleaning up branches...") + b.WriteString("\n\n") + if m.action.Workspace != "" { + fmt.Fprintf(&b, "Workspace: %s\n", m.action.Workspace) + } + b.WriteString("\n") + b.WriteString("Please wait...") + + content := boxStyle.Render(b.String()) + + if m.width > 0 && m.height > 0 { + return lipgloss.Place( + m.width, + m.height, + lipgloss.Center, + lipgloss.Center, + content, + ) + } + + return content + } + descStyle := lipgloss.NewStyle(). Foreground(lipgloss.Color("252")). MarginTop(1). @@ -100,10 +145,10 @@ func (m ConfirmModel) View() string { b.WriteString("\n\n") if m.action.Workspace != "" { - b.WriteString(fmt.Sprintf("Workspace: %s\n", m.action.Workspace)) + fmt.Fprintf(&b, "Workspace: %s\n", m.action.Workspace) } if m.action.Repo != "" { - b.WriteString(fmt.Sprintf("Repository: %s\n", m.action.Repo)) + fmt.Fprintf(&b, "Repository: %s\n", m.action.Repo) } b.WriteString("\n") diff --git a/pkg/ui/dashboard/dashboard.go b/pkg/ui/dashboard/dashboard.go index 96d6eb6..4ccea51 100644 --- a/pkg/ui/dashboard/dashboard.go +++ b/pkg/ui/dashboard/dashboard.go @@ -157,10 +157,12 @@ func (m DashboardModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { if m.showConfirm { var cmd tea.Cmd m.confirmModel, cmd = m.confirmModel.Update(msg) - if m.confirmModel.IsDone() { - if m.confirmModel.IsConfirmed() { - cmd = m.executeConfirmedAction() - } + if m.confirmModel.IsConfirmed() && !m.confirmModel.IsDeleting() { + m.confirmModel = m.confirmModel.SetDeleting(true) + cmd = m.executeConfirmedAction() + return m, cmd + } + if m.confirmModel.IsCanceled() { m.showConfirm = false } return m, cmd @@ -261,6 +263,9 @@ func (m DashboardModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, nil case ActionCompleteMsg: + if msg.Action == ActionDelete { + m.showConfirm = false + } switch { case msg.Output != "": m.statusMessage = msg.Output