feat(gui-app): show task status on the mobile nav drawer's recent-task rows (#1747)
## Problem
The mobile nav drawer's "Recent tasks" rows show no task status: three
agents can be mid-turn and nothing in the drawer says so. The history
page and the desktop list both carry the status indicator (running dots,
unread result, attention states) on every row; the drawer is the one
task list without it.
The gap is a side effect of a deliberate density decision. The drawer
dropped the leading glyph because every row in that list is a task, so a
repeated Layers icon carried no information and cost the title ~28px.
That reasoning holds for the *default* glyph. It does not hold for
status: an agent working, or a result waiting to be read, is information
about *this* row, and it was thrown out with the decoration.
## Change
- `epics-list-shared.tsx`: the hook wiring behind
`HistoryRowLeadingIcon` (`useEpicActivityStatus` for epics only,
`useSurfaceNotificationIndicatorState`, `NotificationIndicatorIcon`) is
lifted into `HistoryRowStatusIcon`, which takes the surface's
`testIdPrefix`, `className` and `defaultIcon`. `HistoryRowLeadingIcon`
is now that with the Layers default; the history page and desktop list
are unchanged.
- `mobile-nav-drawer.tsx`: each task row mounts `HistoryRowStatusIcon`
with `defaultIcon={null}`, so the indicator takes the leading slot only
when it carries information (running activity, or any indicator state)
and an idle row keeps its full title width. Pinned rows keep the pin
glyph; pinned + running shows pin then dots. Row height and the
timestamp column are unchanged. Phases behave as on the history page: no
activity lookup.
- The shell mounts the drawer outside the
`NotificationIndicatorsProvider`s the tab strip and the list panel put
around their own rows, so `DrawerTaskList` asks
`useNotificationIndicators` for the epics on screen (epic rows' ids only
— a phase row's `epicId` is a phase id — against the app-wide active
host, as the tab strip does) and provides the answer to its rows —
otherwise unread and pending-attention states would have reached the
rows as an empty map.
This is a mount, not an invention: the desktop list and the phone's
history already show exactly this status through the same component.
## Testing
`mobile-nav-drawer` (27), `mobile-history-list` + `epics-list-panel`
(85) suites; gui-app `tsgo -b`, `oxlint`, `eslint`, root write-mode
`oxfmt`.
- idle row: no svg, no `role="status"` (the density decision still
holds).
- running epic: `role="status"` with the "Task activity in progress"
label and the `mobile-nav-task-activity-<id>` dots; the idle sibling row
shows nothing.
- pinned + running: pin and dots both present, pin first in document
order.
- unread result (no live activity): the drawer asks the notifications
source for exactly the on-screen epic ids, the indicator renders for the
unread epic and not for its idle sibling — through the real context
path; with the drawer's provider removed this test fails.
- phase row marked busy: no status (the activity source is asked with
`null`), and the notification query is asked about the epic beside it
only.
---------
Signed-off-by: Pranshu Gupta <76090263+pranshugupta54@users.noreply.github.com> P
Pranshu Gupta committed
bb28debc77a32fc27cd22cfcb63f2154a7b0eaea
Parent: 60cf9f6
Committed by GitHub <noreply@github.com>
on 9/7/2026, 3:56:50 PM