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

Reply via email to