feat(dashboard): highlight proposals pane + bell on new proposal #50
@@ -1352,6 +1352,10 @@ def _main_loop(stdscr: "curses._CursesWindow") -> None:
|
|||||||
if manifest_cache[0] is None:
|
if manifest_cache[0] is None:
|
||||||
manifest_cache[0] = Manifest.resolve(USER_CWD)
|
manifest_cache[0] = Manifest.resolve(USER_CWD)
|
||||||
return manifest_cache[0]
|
return manifest_cache[0]
|
||||||
|
# First-tick guard: a brand-new dashboard finds any
|
||||||
|
# pre-existing queue entries on its first poll; those
|
||||||
|
# shouldn't ring the bell as if they just arrived.
|
||||||
|
saw_first_tick = False
|
||||||
while True:
|
while True:
|
||||||
pending = discover_pending()
|
pending = discover_pending()
|
||||||
if selected >= len(pending):
|
if selected >= len(pending):
|
||||||
@@ -1363,10 +1367,21 @@ def _main_loop(stdscr: "curses._CursesWindow") -> None:
|
|||||||
|
|
||||||
now = time.monotonic()
|
now = time.monotonic()
|
||||||
live_ids = {qp.proposal.id for qp in pending}
|
live_ids = {qp.proposal.id for qp in pending}
|
||||||
|
# Detect proposals we've never seen before — used to ring
|
||||||
|
# the terminal bell (so tmux's monitor-bell or the
|
||||||
|
# terminal's own bell-on-activity surface a notice when
|
||||||
|
# the operator isn't looking at the dashboard pane).
|
||||||
|
newly_arrived = live_ids - first_seen.keys()
|
||||||
|
if saw_first_tick and newly_arrived:
|
||||||
|
try:
|
||||||
|
curses.beep()
|
||||||
|
except curses.error:
|
||||||
|
pass
|
||||||
for proposal_id in live_ids:
|
for proposal_id in live_ids:
|
||||||
first_seen.setdefault(proposal_id, now)
|
first_seen.setdefault(proposal_id, now)
|
||||||
for stale_id in list(first_seen.keys() - live_ids):
|
for stale_id in list(first_seen.keys() - live_ids):
|
||||||
del first_seen[stale_id]
|
del first_seen[stale_id]
|
||||||
|
saw_first_tick = True
|
||||||
|
|
||||||
_render(
|
_render(
|
||||||
stdscr, pending, selected, status_line,
|
stdscr, pending, selected, status_line,
|
||||||
@@ -1541,10 +1556,22 @@ def _render(
|
|||||||
|
|
||||||
# ----- proposals pane (top) -----
|
# ----- proposals pane (top) -----
|
||||||
row = 2
|
row = 2
|
||||||
|
# When any proposal is in the recent-arrival window (the
|
||||||
|
# individual rows are green-highlighted by the existing logic),
|
||||||
|
# also highlight the pane label so the alert is visible at a
|
||||||
|
# glance even when the operator is focused elsewhere.
|
||||||
|
proposals_have_recent = any(
|
||||||
|
_is_recent(qp.proposal.id, first_seen, now) for qp in pending
|
||||||
|
)
|
||||||
proposals_label = "proposals:"
|
proposals_label = "proposals:"
|
||||||
|
if proposals_have_recent:
|
||||||
|
proposals_label += " (new!)"
|
||||||
if proposals_focused:
|
if proposals_focused:
|
||||||
proposals_label += " (focused)"
|
proposals_label += " (focused)"
|
||||||
stdscr.addnstr(row, 0, proposals_label, w - 1, curses.A_DIM)
|
label_attr = curses.A_DIM
|
||||||
|
if proposals_have_recent:
|
||||||
|
label_attr = curses.A_BOLD | green_attr
|
||||||
|
stdscr.addnstr(row, 0, proposals_label, w - 1, label_attr)
|
||||||
row += 1
|
row += 1
|
||||||
if not pending:
|
if not pending:
|
||||||
stdscr.addnstr(
|
stdscr.addnstr(
|
||||||
|
|||||||
Reference in New Issue
Block a user