Fix: Interactive restore now shows dynamic status updates during operation

Issue: Interactive cluster restore showed 'Status: Initializing...' throughout
the entire restore process, making it appear stuck even though restore was working.

Root cause:
- Status and phase were set once in NewRestoreExecution()
- Never updated during the restore process
- Only changed to 'Completed' or 'Failed' at the end
- No visual feedback about what stage of restore was running

Solution: Time-based status progression
Added logic in Update() tick handler to change status based on elapsed time:
- 0-2 sec: 'Initializing restore...' / Phase: Starting
- 2-5 sec: Context-aware status:
  - If cleanup: 'Cleaning N existing database(s)...' / Phase: Cleanup
  - If cluster: 'Extracting cluster archive...' / Phase: Extraction
  - If single: 'Preparing restore...' / Phase: Preparation
- 5-10 sec:
  - If cluster: 'Restoring global objects...' / Phase: Globals
  - If single: 'Restoring database...' / Phase: Restore
- 10+ sec: 'Restoring [cluster] databases...' / Phase: Restore

Benefits:
- User sees the restore is progressing through stages
- Different status messages for cluster vs single database restore
- Shows cleanup phase when enabled
- Spinner + changing status = clear visual feedback
- Better user experience during long-running restores

Note: These are estimated phases since the restore engine runs in silent mode
(no stdout interference with TUI). Actual operation may be faster or slower
than time estimates, but provides much better UX than static 'Initializing'.
This commit is contained in:
2025-11-12 09:17:39 +00:00
parent eb3e5c0135
commit 23a87625dc

View File

@@ -175,6 +175,43 @@ func (m RestoreExecutionModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
if !m.done { if !m.done {
m.spinnerFrame = (m.spinnerFrame + 1) % len(m.spinnerFrames) m.spinnerFrame = (m.spinnerFrame + 1) % len(m.spinnerFrames)
m.elapsed = time.Since(m.startTime) m.elapsed = time.Since(m.startTime)
// Update status based on elapsed time to show progress
// This provides visual feedback even though we don't have real-time progress
elapsedSec := int(m.elapsed.Seconds())
if elapsedSec < 2 {
m.status = "Initializing restore..."
m.phase = "Starting"
} else if elapsedSec < 5 {
if m.cleanClusterFirst && len(m.existingDBs) > 0 {
m.status = fmt.Sprintf("Cleaning %d existing database(s)...", len(m.existingDBs))
m.phase = "Cleanup"
} else if m.restoreType == "restore-cluster" {
m.status = "Extracting cluster archive..."
m.phase = "Extraction"
} else {
m.status = "Preparing restore..."
m.phase = "Preparation"
}
} else if elapsedSec < 10 {
if m.restoreType == "restore-cluster" {
m.status = "Restoring global objects..."
m.phase = "Globals"
} else {
m.status = fmt.Sprintf("Restoring database '%s'...", m.targetDB)
m.phase = "Restore"
}
} else {
if m.restoreType == "restore-cluster" {
m.status = "Restoring cluster databases..."
m.phase = "Restore"
} else {
m.status = fmt.Sprintf("Restoring database '%s'...", m.targetDB)
m.phase = "Restore"
}
}
return m, restoreTickCmd() return m, restoreTickCmd()
} }
return m, nil return m, nil
@@ -199,7 +236,7 @@ func (m RestoreExecutionModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.elapsed = msg.elapsed m.elapsed = msg.elapsed
if m.err == nil { if m.err == nil {
m.status = "Completed" m.status = "Restore completed successfully"
m.phase = "Done" m.phase = "Done"
m.progress = 100 m.progress = 100
} else { } else {