doRefreshVMData is the shared implementation for VM data refresh. When withTasks is true, it also refreshes the tasks list after the VM data is updated.
(vm *api.VM, withTasks bool)
| 21 | // doRefreshVMData is the shared implementation for VM data refresh. |
| 22 | // When withTasks is true, it also refreshes the tasks list after the VM data is updated. |
| 23 | func (a *App) doRefreshVMData(vm *api.VM, withTasks bool) { |
| 24 | // Check if VM has pending operations (skip for withTasks since the caller just queued the task) |
| 25 | if !withTasks { |
| 26 | if isPending, pendingOperation := models.GlobalState.IsVMPending(vm); isPending { |
| 27 | a.showMessageSafe(fmt.Sprintf("Cannot refresh VM while '%s' is in progress", pendingOperation)) |
| 28 | return |
| 29 | } |
| 30 | } |
| 31 | |
| 32 | // Show loading indicator |
| 33 | if withTasks { |
| 34 | a.header.ShowLoading(fmt.Sprintf("Refreshing VM %s and tasks", vm.Name)) |
| 35 | } else { |
| 36 | a.header.ShowLoading(fmt.Sprintf("Refreshing VM %s", vm.Name)) |
| 37 | } |
| 38 | |
| 39 | // Store VM identity for selection restoration |
| 40 | vmID := vm.ID |
| 41 | vmNode := vm.Node |
| 42 | |
| 43 | // Run refresh in goroutine to avoid blocking UI |
| 44 | go func() { |
| 45 | // Get the correct client for this VM (important for group mode) |
| 46 | client, err := a.getClientForVM(vm) |
| 47 | if err != nil { |
| 48 | a.QueueUpdateDraw(func() { |
| 49 | a.header.ShowError(fmt.Sprintf("Error refreshing VM: %v", err)) |
| 50 | }) |
| 51 | return |
| 52 | } |
| 53 | |
| 54 | // Fetch fresh VM data with callback for when enrichment completes |
| 55 | freshVM, err := client.RefreshVMData(vm, func(enrichedVM *api.VM) { |
| 56 | // This callback is called after guest agent data has been loaded |
| 57 | a.QueueUpdateDraw(func() { |
| 58 | // Update VM details if this VM is currently selected |
| 59 | if selectedVM := a.vmList.GetSelectedVM(); selectedVM != nil && selectedVM.ID == enrichedVM.ID && selectedVM.Node == enrichedVM.Node { |
| 60 | a.vmDetails.Update(enrichedVM) |
| 61 | } |
| 62 | }) |
| 63 | }) |
| 64 | if err != nil { |
| 65 | // If VM refresh fails (e.g., VM was migrated to a different node), |
| 66 | // fall back to a full refresh to find the VM on its new node. |
| 67 | // Note: manualRefresh must NOT be called inside QueueUpdateDraw to avoid |
| 68 | // nested QueueUpdateDraw deadlocks (manualRefresh queues its own updates). |
| 69 | a.QueueUpdateDraw(func() { |
| 70 | a.header.ShowLoading("VM may have been migrated, performing full refresh") |
| 71 | }) |
| 72 | a.manualRefresh() |
| 73 | |
| 74 | return |
| 75 | } |
| 76 | |
| 77 | // Update UI with fresh data on main thread |
| 78 | a.QueueUpdateDraw(func() { |
| 79 | // Get current search state |
| 80 | vmSearchState := models.GlobalState.GetSearchState(api.PageGuests) |
no test coverage detected