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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.