fix: view-queue link + agent inbox shows unread messages only

fix(dashboard): update 'view queue' link to /builds.html

The build queue moved to its own /builds.html page. The queue-summary
'view queue →' link in tabs.js still pointed at /core.html, so clicking
it landed on the wrong page.

fix(broker): filter agent inbox to unread (acked_at IS NULL)

recent_for was returning all messages regardless of ack state, so the
agent inbox showed everything even after 'mark all read'. Now filters
to acked_at IS NULL — mirroring exactly what mark_all_read drains —
so the inbox empties on reload after the operator drains it.
This commit is contained in:
iris 2026-07-01 18:31:32 +02:00 committed by mara
commit 5264828091
3 changed files with 8 additions and 9 deletions

View file

@ -1133,11 +1133,9 @@ window.marked = marked;
return wrap;
}
// "mark all read" header row drains the host broker's pending +
// delivered-unacked rows for this agent. Visible rows here are
// the most-recent-N regardless of ack state, so the list itself
// doesn't visually empty on click — the status pill confirms
// the drain count, and the next turn_start's "unread" badge
// will read zero.
// delivered-unacked rows for this agent. The inbox shows only
// unread (acked_at IS NULL) rows, so after the drain + refreshState()
// the list empties (matching the operator's expectation).
wrap.append(buildInboxMarkAllRow(currentLabel, () => {
// Refresh state so any UI surface that DOES depend on
// delivery state (eg future per-status filters) picks up

View file

@ -826,7 +826,7 @@ window.marked = marked;
el('span', { class: 'glyph spinner' }, '◐'), ' ',
el('strong', {}, 'build queue'), ' — ',
parts.join(' · '), ' ',
el('a', { class: 'queue-summary-link', href: '/core.html' }, 'view queue →'),
el('a', { class: 'queue-summary-link', href: '/builds.html' }, 'view queue →'),
));
}

View file

@ -339,9 +339,9 @@ impl Broker {
Ok(batch)
}
/// Latest `limit` messages addressed to `recipient`, newest-first.
/// Includes delivered + undelivered alike — used for the operator
/// inbox view on the dashboard. Caller decides what to show.
/// Unread (unacked) messages addressed to `recipient`, newest-first.
/// Filters to `acked_at IS NULL` so the agent inbox view clears after
/// "mark all read" — mirroring exactly what `mark_all_read` will drain.
pub fn recent_for(&self, recipient: &str, limit: u64) -> Result<Vec<InboxRow>> {
let conn = self.conn.lock().unwrap();
let limit_i = i64::try_from(limit.min(i64::MAX as u64)).unwrap_or(i64::MAX);
@ -349,6 +349,7 @@ impl Broker {
"SELECT id, sender, body, sent_at, in_reply_to
FROM messages
WHERE recipient = ?1
AND acked_at IS NULL
ORDER BY id DESC
LIMIT ?2",
)?;