Skip to content

Add confirmation popup for removing downloads#539

Open
junaid2005p wants to merge 1 commit into
mainfrom
popup-cancel-paused-or-active
Open

Add confirmation popup for removing downloads#539
junaid2005p wants to merge 1 commit into
mainfrom
popup-cancel-paused-or-active

Conversation

@junaid2005p

@junaid2005p junaid2005p commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator

Greptile Summary

This PR adds confirmation before removing unfinished downloads. The main changes are:

  • A new removal-confirmation state and modal.
  • Shared deletion and reconciliation logic.
  • Tests for active, paused, cancelled, confirmed, and auto-shutdown flows.

Confidence Score: 4/5

Errored downloads can still be removed without confirmation, and incoming requests can interrupt the new modal state.

Target IDs remain stable across list updates. Confirmation and cancellation clear their pending state. Failed downloads are misclassified as completed for removal. External requests can replace the removal modal before a decision.

internal/tui/update_dashboard.go and internal/tui/view.go

T-Rex T-Rex Logs

What T-Rex did

  • Reproduced an erred-download flow in T-Rex where a done download with a non-nil error bypassed RemoveConfirmState and triggered Service.Delete with failed-partial-id; the download count dropped from one to zero.
  • In a focused in-process T-Rex test, an incoming DownloadEvent replaced state 22 with extension-confirmation state 7 and left removeTargetID populated; pressing Escape canceled the replacement and returned to the dashboard while the removal target remained pending.
  • State-transition coverage showed that Escape and n cancel a pending deletion returning to DashboardState, while y and Left+Enter trigger deletion, and a completed-download x is deleted directly without confirmation; both focused tests and the full go test ./internal/tui -count=1 exited 0.

View all artifacts

T-Rex Ran code and verified through T-Rex

Important Files Changed

Filename Overview
internal/tui/update_dashboard.go Routes unfinished downloads through confirmation, but errored downloads bypass it and incoming requests can interrupt the new state.
internal/tui/update_modals.go Adds confirm and cancel handling while centralizing deletion, list refresh, and auto-shutdown reconciliation.
internal/tui/view.go Renders the removal modal, but filename truncation can split multibyte UTF-8 characters.
internal/tui/model.go Adds the removal-confirmation state and target download ID.
internal/tui/update.go Dispatches key input to the new modal handler.
internal/tui/delete_resilience_test.go Covers active, paused, confirm, cancel, success, and delete-error behavior, but not errored downloads or incoming requests during confirmation.
internal/tui/power_test.go Updates auto-shutdown coverage for the added confirmation step.
Prompt To Fix All With AI
Fix the following 3 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 3
internal/tui/update_dashboard.go:146-151
**Errored Downloads Bypass Confirmation**

`done` is also set for failed downloads, including downloads with partial progress. Pressing remove on such an entry skips the new confirmation and immediately deletes its resumable state, even though it has the same progress-loss risk as an active or paused download.

```suggestion
			if !d.done || d.err != nil {
				m.removeTargetID = d.ID
				m.quitConfirmFocused = 1 // default focus on "Cancel"
				m.state = RemoveConfirmState
				return m, nil
			}
```

### Issue 2 of 3
internal/tui/view.go:952-953
**Byte Slice Corrupts UTF-8**

When a filename contains multibyte characters, byte 27 can fall inside a UTF-8 sequence. The confirmation modal then displays malformed text or replacement characters instead of the target filename.

### Issue 3 of 3
internal/tui/update_dashboard.go:149
**Incoming Requests Replace Modal State**

`RemoveConfirmState` is not included in the busy states that queue incoming download requests. If an extension or API request triggers another confirmation while this modal is open, that state replaces the removal modal and leaves `removeTargetID` pending, so the original confirmation cannot be completed or cancelled normally.

Reviews (1): Last reviewed commit: "feat(tui): added a popup before removing..." | Re-trigger Greptile

Greptile also left 3 inline comments on this PR.

Comment on lines +146 to 151
if !d.done {
m.removeTargetID = d.ID
m.quitConfirmFocused = 1 // default focus on "Cancel"
m.state = RemoveConfirmState
return m, nil
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Errored Downloads Bypass Confirmation

done is also set for failed downloads, including downloads with partial progress. Pressing remove on such an entry skips the new confirmation and immediately deletes its resumable state, even though it has the same progress-loss risk as an active or paused download.

Suggested change
if !d.done {
m.removeTargetID = d.ID
m.quitConfirmFocused = 1 // default focus on "Cancel"
m.state = RemoveConfirmState
return m, nil
}
if !d.done || d.err != nil {
m.removeTargetID = d.ID
m.quitConfirmFocused = 1 // default focus on "Cancel"
m.state = RemoveConfirmState
return m, nil
}

Rule Used: What: All code changes must include tests for edge... (source)

Artifacts

Repro: focused Go test exercising the real TUI delete state transition

  • Contains supporting evidence from the run (text/x-go; charset=utf-8).

Repro: verbose failing test output showing immediate deletion without confirmation

  • Keeps the command output available without making the summary code-heavy.

View artifacts

T-Rex Ran code and verified through T-Rex

Prompt To Fix With AI
This is a comment left during a code review.
Path: internal/tui/update_dashboard.go
Line: 146-151

Comment:
**Errored Downloads Bypass Confirmation**

`done` is also set for failed downloads, including downloads with partial progress. Pressing remove on such an entry skips the new confirmation and immediately deletes its resumable state, even though it has the same progress-loss risk as an active or paused download.

```suggestion
			if !d.done || d.err != nil {
				m.removeTargetID = d.ID
				m.quitConfirmFocused = 1 // default focus on "Cancel"
				m.state = RemoveConfirmState
				return m, nil
			}
```

**Rule Used:** What: All code changes must include tests for edge... ([source](https://app.greptile.com/surge-org-3/-/custom-context?memory=2b22782d-3452-4d55-b059-e631b2540ce8))

How can I resolve this? If you propose a fix, please make it concise.

Comment thread internal/tui/view.go
Comment on lines +952 to +953
} else if len(filename) > 30 {
filename = filename[:27] + "..."

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Byte Slice Corrupts UTF-8

When a filename contains multibyte characters, byte 27 can fall inside a UTF-8 sequence. The confirmation modal then displays malformed text or replacement characters instead of the target filename.

Rule Used: What: All code changes must include tests for edge... (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: internal/tui/view.go
Line: 952-953

Comment:
**Byte Slice Corrupts UTF-8**

When a filename contains multibyte characters, byte 27 can fall inside a UTF-8 sequence. The confirmation modal then displays malformed text or replacement characters instead of the target filename.

**Rule Used:** What: All code changes must include tests for edge... ([source](https://app.greptile.com/surge-org-3/-/custom-context?memory=2b22782d-3452-4d55-b059-e631b2540ce8))

How can I resolve this? If you propose a fix, please make it concise.

if !d.done {
m.removeTargetID = d.ID
m.quitConfirmFocused = 1 // default focus on "Cancel"
m.state = RemoveConfirmState

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Incoming Requests Replace Modal State

RemoveConfirmState is not included in the busy states that queue incoming download requests. If an extension or API request triggers another confirmation while this modal is open, that state replaces the removal modal and leaves removeTargetID pending, so the original confirmation cannot be completed or cancelled normally.

Rule Used: What: All code changes must include tests for edge... (source)

Artifacts

Repro: focused in-process TUI state-machine test

  • Contains supporting evidence from the run (text/x-go; charset=utf-8).

Repro: verbose failing test output showing modal replacement and orphaned removal target

  • Keeps the command output available without making the summary code-heavy.

View artifacts

T-Rex Ran code and verified through T-Rex

Prompt To Fix With AI
This is a comment left during a code review.
Path: internal/tui/update_dashboard.go
Line: 149

Comment:
**Incoming Requests Replace Modal State**

`RemoveConfirmState` is not included in the busy states that queue incoming download requests. If an extension or API request triggers another confirmation while this modal is open, that state replaces the removal modal and leaves `removeTargetID` pending, so the original confirmation cannot be completed or cancelled normally.

**Rule Used:** What: All code changes must include tests for edge... ([source](https://app.greptile.com/surge-org-3/-/custom-context?memory=2b22782d-3452-4d55-b059-e631b2540ce8))

How can I resolve this? If you propose a fix, please make it concise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant