The GitHub Actions job "Required Checks" on texera.git/main has succeeded. Run started by GitHub user github-merge-queue[bot] (triggered by github-merge-queue[bot]).
Head commit for run: 51d7564309bf74ad75b4f28844ba2516e6bad9a6 / Prateek Ganigi <[email protected]> feat(frontend): restore the heat-map after a page refresh (#8552) ### What changes were proposed in this PR? Third sub-task of the heat-map umbrella #5772. Today the heat-map is session-only: a refresh drops the Layers > Performance toggle and the statistics that color the canvas, so the workflow has to be re-run just to look at it again. **Before this PR:** https://github.com/user-attachments/assets/3a29a5b1-5e7f-4d7a-9e62-05efdb47d6f1 **After this PR:** https://github.com/user-attachments/assets/a2506966-dbd5-4c93-8304-cb950d9a2771 ``` Before: refresh -> session state cleared -> overlay off, canvas blank After: refresh -> toggle + view restored -> last run's stats re-fetched -> canvas repainted ``` Two halves, both frontend-only. **1. Overlay state.** `heatmap-overlay-persistence.ts` keeps `{ view: HeatmapView | null }` in localStorage via the existing `localSetObject` / `localGetObject`. `MenuComponent` saves on toggle and on view change, and restores in `ngOnInit`. Only the Performance layer persists: Grid / Regions / Workers / Status stay session-only. A corrupted or foreign value reads as off. **2. Statistics.** `HeatmapStatsRestoreService` composes existing client APIs: ``` wid -> retrieveWorkflowExecutions -> latest completed run -> retrieveWorkflowRuntimeStatistics -> latest snapshot per operator -> WorkflowStatusService.setExternalStatus ``` `runtime-statistics-mapper.ts` does the shape conversion, including status code -> `OperatorState`; Failed and Killed have no `OperatorState` member, so they fall back to `Uninitialized` rather than a wrong state. Port-level metrics are not persisted, so the mapper omits the port maps entirely rather than emitting empty ones: `{}` already means "every port measured zero" (what `resetStatus` emits), so `changeOperatorStatistics` skips the port loops when the maps are absent and the port labels keep their display names. Two changes land outside the heat-map feature. `inputPortMetrics` / `outputPortMetrics` become optional on `OperatorStatistics`, the shared websocket-mirror type. Jackson already omits absent fields, so the mirror is not weakened. Separately, `changeOperatorStatistics` gains a branch for the absent case. `WorkflowStatusService` gains `setExternalStatus`. The websocket handler's body moves into a private `ingestRuntimeStatus` that both paths share, so live and restored updates emit identically. `performanceMetricsSubject` is already a `BehaviorSubject`, so the restore fetch cannot race the overlay's own init. Restoring is best-effort and entirely gated inside the service: | Skips when | Why | | --- | --- | | Overlay not persisted on | A localStorage read, so non-users issue no request at all | | No `wid` (unsaved workflow) | Nothing to fetch | | Execution in progress | The live stream wins | | No executions, or no statistics | Nothing to restore | | HTTP error | Must never block workspace entry | | Another producer writes statistics first | A new run resets the canvas; `isExecuting()` cannot see it until the backend replies | ### Any related issues, documentation, discussions? Closes #5775. Part of umbrella #5772. RFC #5216. Reviewer note: #5775 refers to `setExternalStatus` as already existing from #5773. It is not on `main` and this PR adds it. ### How was this PR tested? Manual, Chrome: run a workflow to completion, Layers > Performance on, pick **I/O imbalance**, reload: toggle, view and colors all come back with no re-run. Switch to **Time / row** and reload: the ranking inverts and survives. Uncheck and reload: stays off. `localStorage.clear()` and reload: back to default. ``` cd frontend && ng test --watch=false \ --include "**/heatmap-overlay-persistence.spec.ts" \ --include "**/runtime-statistics-mapper.spec.ts" \ --include "**/heatmap-stats-restore.service.spec.ts" \ --include "**/workflow-status.service.spec.ts" \ --include "**/joint-ui.service.spec.ts" \ --include "**/menu.component.spec.ts" \ --include "**/workspace.component.spec.ts" ``` | Spec | Tests | New | | --- | --- | --- | | `heatmap-overlay-persistence.spec.ts` | 4 | 4 | | `runtime-statistics-mapper.spec.ts` | 8 | 8 | | `heatmap-stats-restore.service.spec.ts` | 16 | 16 | | `workflow-status.service.spec.ts` | 14 | 3 | | `joint-ui.service.spec.ts` | 71 | 2 | | `menu.component.spec.ts` | 128 | 6 | | `workspace.component.spec.ts` | 28 | 0 | 39 new tests, 269 passing, covering the negative paths: corrupted stored value, unsaved workflow, live execution, a run started while the fetches are in flight, zero executions, a run that never completed, an empty payload, and an HTTP error from either fetch. `tsc --noEmit` (strict), `eslint ./src` and Prettier are clean. ### Was this PR authored or co-authored using generative AI tooling? This PR was co-authored by Claude, in compliance with ASF. Report URL: https://github.com/apache/texera/actions/runs/35551297317 With regards, GitHub Actions via GitBox
