doManualRefresh is the internal implementation of a full refresh. Caller must have already acquired the refresh guard (token != 0).
(token uint64)
| 52 | // doManualRefresh is the internal implementation of a full refresh. |
| 53 | // Caller must have already acquired the refresh guard (token != 0). |
| 54 | func (a *App) doManualRefresh(token uint64) { |
| 55 | // Check if there are any pending operations |
| 56 | if models.GlobalState.HasPendingOperations() { |
| 57 | a.endRefresh(token) |
| 58 | a.showMessageSafe("Cannot refresh data while there are pending operations in progress") |
| 59 | return |
| 60 | } |
| 61 | |
| 62 | // Show loading indicator |
| 63 | a.header.ShowLoading("Refreshing data...") |
| 64 | a.footer.SetLoading(true) |
| 65 | |
| 66 | // NOTE: UI state reads (selections, search) are intentionally NOT captured here. |
| 67 | // For the group mode path, they are captured inside QueueUpdateDraw (on the UI |
| 68 | // goroutine) before calling enrichGroupNodesParallel. For the single-profile path, |
| 69 | // doEnrichNodes captures them inside its own QueueUpdateDraw callback. This ensures |
| 70 | // all tview reads happen on the UI goroutine and are race-free. |
| 71 | |
| 72 | // Run data refresh in goroutine to avoid blocking UI |
| 73 | go func() { |
| 74 | // Snapshot connection state under lock so reads are race-free. |
| 75 | conn := a.snapConn() |
| 76 | |
| 77 | if conn.isGroupMode { |
| 78 | // Group mode logic |
| 79 | ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) |
| 80 | defer cancel() |
| 81 | |
| 82 | nodes, vms, err := conn.groupManager.GetGroupClusterResources(ctx, true) |
| 83 | if err != nil { |
| 84 | a.endRefresh(token) |
| 85 | a.QueueUpdateDraw(func() { |
| 86 | a.header.ShowError(fmt.Sprintf("Refresh failed: %v", err)) |
| 87 | a.footer.SetLoading(false) |
| 88 | }) |
| 89 | |
| 90 | return |
| 91 | } |
| 92 | |
| 93 | a.QueueUpdateDraw(func() { |
| 94 | // Capture selections on the UI goroutine before starting background enrichment. |
| 95 | snap := a.captureSelections() |
| 96 | |
| 97 | // Update GlobalState nodes/VMs; UI lists will be updated after enrichment to reduce flicker. |
| 98 | models.GlobalState.OriginalNodes = nodes |
| 99 | models.GlobalState.OriginalVMs = vms |
| 100 | |
| 101 | // Apply node filter if active |
| 102 | nodeSearchState := models.GlobalState.GetSearchState(api.PageNodes) |
| 103 | if nodeSearchState != nil && nodeSearchState.Filter != "" { |
| 104 | models.FilterNodes(nodeSearchState.Filter) |
| 105 | } else { |
| 106 | models.GlobalState.FilteredNodes = make([]*api.Node, len(nodes)) |
| 107 | copy(models.GlobalState.FilteredNodes, nodes) |
| 108 | } |
| 109 | |
| 110 | // Apply VM filter if active |
| 111 | vmSearchState := models.GlobalState.GetSearchState(api.PageGuests) |
no test coverage detected