feat(WorktreeRow): add loading state and safety guards to worktree deletion - #128
Open
gedeagas wants to merge 1 commit into
Open
feat(WorktreeRow): add loading state and safety guards to worktree deletion#128gedeagas wants to merge 1 commit into
gedeagas wants to merge 1 commit into
Conversation
…letion - Prevent duplicate deletion requests via in-flight ref and early returns - Show spinner during deletion; disable interactions (drag, click, context menu) - Persist "don't ask again" only on successful deletion, not on failure - Replace raw buttons with Button component for consistent loading indicator
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
There was a problem hiding this comment.
Pull request overview
Adds a safer UX for worktree deletion in the sidebar by introducing an in-progress (“deleting”) state that disables interactions and shows a spinner, plus tests for the delete flow.
Changes:
- Add
isDeletingUI state +deleteInFlightRefguard to prevent concurrent deletes and disable row interactions during deletion. - Update delete confirmation dialog to use the shared
<Button>component and disable controls while deleting. - Add a new Vitest test suite for the deletion flow (confirmation dialog behavior, loading state, and failure handling).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| src/renderer/components/Sidebar/WorktreeRow.tsx | Adds deletion in-flight UI state/guards, disables interactions, and updates confirmation dialog controls. |
| src/renderer/components/Sidebar/tests/WorktreeRow.test.tsx | Adds new tests for delete confirmation + loading state + error behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+136
to
140
| await removeWorktree(worktree.projectId, worktree.id) | ||
| if (skipFutureConfirmations) setSkipDeleteConfirm(true) | ||
| rowDispatch({ type: 'HIDE_DELETE_CONFIRM' }) | ||
| } catch (err) { | ||
| console.error('[WorktreeRow] removeWorktree failed:', err) |
Comment on lines
+157
to
+173
| it('shows a row-level spinner when confirmation is skipped', async () => { | ||
| const removal = deferred<void>() | ||
| mocks.removeWorktree.mockReturnValue(removal.promise) | ||
| mocks.skipDeleteWorktreeConfirm = true | ||
| renderRow() | ||
|
|
||
| const row = screen.getByRole('option') | ||
| fireEvent.keyDown(row, { key: 'Delete' }) | ||
|
|
||
| await waitFor(() => expect(row.getAttribute('aria-busy')).toBe('true')) | ||
| expect(within(row).getByRole('status')).toBeTruthy() | ||
| expect(row.getAttribute('draggable')).toBe('false') | ||
|
|
||
| await act(async () => removal.resolve()) | ||
|
|
||
| await waitFor(() => expect(row.getAttribute('aria-busy')).toBe('false')) | ||
| }) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
deleteInFlightRefguard and disabled UI controlsLayers touched
src/renderer/) — components, stores, libChanges
Sidebar / Center / Right panel:
WorktreeRow.tsx: AddedisDeletingstate to reducer,deleteInFlightRefto prevent concurrent deletes,aria-busyattribute during deletion, disabled click/drag/context-menu interactions while deleting, replaced raw<button>with<Button>component in the confirmation dialog, show<Spinner>in place of PR icon and pin button while deleting__tests__/WorktreeRow.test.tsx: New test suite covering delete-confirmation dialog flow, spinner/aria-busypresence during async deletion, double-click guard, error flash on failure, and "don't ask again" persistenceHow to test
yarn devyarn test WorktreeRow- all new tests passChecklist
yarn devyarn typecheck