From: Christian Brauner <brauner@kernel.org>
To: "Kernel.org Tools" <tools@kernel.org>
Cc: Konstantin Ryabitsev <konstantin@linuxfoundation.org>,
"Christian Brauner (Amutable)" <brauner@kernel.org>
Subject: [PATCH RFC v2 22/25] review-tui: extract the Msgs column renderer from TrackedSeriesItem
Date: Wed, 12 Aug 2026 23:47:03 +0200 [thread overview]
Message-ID: <20260812-work-b4-multiver-rows-v2-22-305d53cd723a@kernel.org> (raw)
In-Reply-To: <20260812-work-b4-multiver-rows-v2-0-305d53cd723a@kernel.org>
The tracker list computes the Msgs column, a thread total plus an unseen
badge, inline in TrackedSeriesItem.compose(). Per-version child rows
need the same column, so pull the computation out into _msgs_fields() and
the styled append into _append_msgs().
No functional change.
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
src/b4/review_tui/_tracking_app.py | 107 +++++++++++++++++++++++--------------
1 file changed, 66 insertions(+), 41 deletions(-)
diff --git a/src/b4/review_tui/_tracking_app.py b/src/b4/review_tui/_tracking_app.py
index 999513ca..53466498 100644
--- a/src/b4/review_tui/_tracking_app.py
+++ b/src/b4/review_tui/_tracking_app.py
@@ -726,6 +726,66 @@ def _format_attestation(att: str, app: Any = None) -> Optional[RichText]:
return text
+def _unseen_delta(
+ message_count: Optional[int], seen_message_count: Optional[int]
+) -> int:
+ """Unseen messages in a thread, for every renderer of that number.
+
+ An absent seen count means nothing is known to have been read yet --
+ but the counts are written in pairs, so in practice that only happens
+ on rows migrated in from a database predating them. Treat it as
+ "nothing unseen" rather than "everything unseen": two renderers
+ disagreeing about a missing value is worse than either answer.
+ """
+ if message_count is None or seen_message_count is None:
+ return 0
+ return max(0, message_count - seen_message_count)
+
+
+def _msgs_fields(
+ message_count: Optional[int], seen_message_count: Optional[int]
+) -> Tuple[str, str, bool]:
+ """Render the Msgs column for a (total, seen) message count pair.
+
+ Returns (base, badge, base_accent): "1" (all seen), "6" accented (all
+ new), "6" + "(3)" (mixed). A never-fetched thread has no count and
+ renders as "-". The badge is accented whenever it is non-empty.
+ """
+ if message_count is None:
+ return '-', '', False
+ if message_count == 0:
+ return '0', '', False
+ delta = _unseen_delta(message_count, seen_message_count)
+ if delta == message_count:
+ # All follow-ups are new
+ return str(message_count), '', True
+ if delta > 0:
+ # Mixed: total + (unseen)
+ return str(message_count), f'({delta})', False
+ # All seen
+ return str(message_count), '', False
+
+
+def _append_msgs(
+ label: RichText,
+ app: Any,
+ message_count: Optional[int],
+ seen_message_count: Optional[int],
+) -> None:
+ """Append the Msgs column (total + unseen badge) to *label*."""
+ base, badge, base_accent = _msgs_fields(message_count, seen_message_count)
+ base_style = ''
+ badge_style = ''
+ if base_accent or badge:
+ accent = f'bold {resolve_styles(app)["warning"]}'
+ if base_accent:
+ base_style = accent
+ if badge:
+ badge_style = accent
+ label.append(f' {base.rjust(3)}', style=base_style)
+ label.append(f'{badge:<3s}', style=badge_style)
+
+
class TrackedSeriesItem(ListItem):
"""A single tracked series entry in the listing."""
@@ -770,36 +830,6 @@ class TrackedSeriesItem(ListItem):
art_str = f'{a}·{r}·{t}'
else:
art_str = '-'
- fc = self.series.get('message_count')
- sc = self.series.get('seen_message_count')
- if fc is not None:
- delta = (fc - sc) if (sc is not None and fc > sc) else 0
- else:
- delta = 0
- # Msgs display: "1" (all seen), "6" accent (all new), "6(3)" mixed
- if fc is None:
- fu_base = '-'
- fu_badge = ''
- base_accent = False
- elif fc == 0:
- fu_base = '0'
- fu_badge = ''
- base_accent = False
- elif delta == fc:
- # All follow-ups are new
- fu_base = str(fc)
- fu_badge = ''
- base_accent = True
- elif delta > 0:
- # Mixed: total + (unseen)
- fu_base = str(fc)
- fu_badge = f'({delta})'
- base_accent = False
- else:
- # All seen
- fu_base = str(fc)
- fu_badge = ''
- base_accent = False
# Build compact prefix using LoreSubject to extract subsystem/modifier tokens
ls = b4.LoreSubject(subject)
extras = ls.get_extra_prefixes(exclude=['patch'])
@@ -822,17 +852,12 @@ class TrackedSeriesItem(ListItem):
label.append(' ')
label.append(' ')
label.append(art_str.rjust(7))
- base_style = ''
- badge_style = ''
- if base_accent or fu_badge:
- ts = resolve_styles(self.app)
- accent = f'bold {ts["warning"]}'
- if base_accent:
- base_style = accent
- if fu_badge:
- badge_style = accent
- label.append(f' {fu_base.rjust(3)}', style=base_style)
- label.append(f'{fu_badge:<3s}', style=badge_style)
+ _append_msgs(
+ label,
+ self.app,
+ self.series.get('message_count'),
+ self.series.get('seen_message_count'),
+ )
label.append(f' {symbol}{flag} {subject_display}')
yield Label(label, markup=False)
--
2.53.0
next prev parent reply other threads:[~2026-08-12 21:47 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-12 21:46 [PATCH RFC v2 00/25] review: track and browse every version of a tracked series Christian Brauner
2026-08-12 21:46 ` [PATCH RFC v2 01/25] review-tui: fix rethreaded series thread viewing Christian Brauner
2026-08-12 21:46 ` [PATCH RFC v2 02/25] review: do not clear fields a re-adding caller does not know Christian Brauner
2026-08-12 21:46 ` [PATCH RFC v2 03/25] review-tui: keep the rethread flag on an upgraded series row Christian Brauner
2026-08-12 21:46 ` [PATCH RFC v2 04/25] review: guard the tracking-commit amend on the worktree, not the checkout Christian Brauner
2026-08-12 21:46 ` [PATCH RFC v2 05/25] review-tui: recompute an evicted A·R·T cache entry Christian Brauner
2026-08-12 21:46 ` [PATCH RFC v2 06/25] review: test the prerequisite fixes Christian Brauner
2026-08-12 21:46 ` [PATCH RFC v2 07/25] review: serialize schema migrations against a concurrent opener Christian Brauner
2026-08-12 21:46 ` [PATCH RFC v2 08/25] review: test the migration serialization Christian Brauner
2026-08-12 21:46 ` [PATCH RFC v2 09/25] review: track message counts for all revisions of a series Christian Brauner
2026-08-12 21:46 ` [PATCH RFC v2 10/25] review: give per-change_id state its own table Christian Brauner
2026-08-12 21:46 ` [PATCH RFC v2 11/25] review: test per-revision message tracking Christian Brauner
2026-08-12 21:46 ` [PATCH RFC v2 12/25] review-tui: poll every revision on u/U updates Christian Brauner
2026-08-12 21:46 ` [PATCH RFC v2 13/25] review: test the per-revision poll sweep Christian Brauner
2026-08-12 21:46 ` [PATCH RFC v2 14/25] review-tui: resolve the tracked revision in revision lists Christian Brauner
2026-08-12 21:46 ` [PATCH RFC v2 15/25] review-tui: fall back when a cached thread blob has no series Christian Brauner
2026-08-12 21:46 ` [PATCH RFC v2 16/25] review-tui: test revision resolution and the range-diff fallback Christian Brauner
2026-08-12 21:46 ` [PATCH RFC v2 17/25] review: skip the catalog mirror when nothing moved Christian Brauner
2026-08-12 21:46 ` [PATCH RFC v2 18/25] review: match a stray posting by message-id Christian Brauner
2026-08-12 21:47 ` [PATCH RFC v2 19/25] review: add backward discovery of older series revisions Christian Brauner
2026-08-12 21:47 ` [PATCH RFC v2 20/25] review-tui: add a "Find older revisions" action Christian Brauner
2026-08-12 21:47 ` [PATCH RFC v2 21/25] review: test the catalog mirror, stray matching and backward discovery Christian Brauner
2026-08-12 21:47 ` Christian Brauner [this message]
2026-08-12 21:47 ` [PATCH RFC v2 23/25] review-tui: give the unseen badge a column of its own Christian Brauner
2026-08-12 21:47 ` [PATCH RFC v2 24/25] review-tui: expand tracked series into per-version rows Christian Brauner
2026-08-12 21:47 ` [PATCH RFC v2 25/25] review-tui: test per-version tracker rows Christian Brauner
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260812-work-b4-multiver-rows-v2-22-305d53cd723a@kernel.org \
--to=brauner@kernel.org \
--cc=konstantin@linuxfoundation.org \
--cc=tools@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox