CPLAT-11489: daily Produced pane reads as a timeline, tabbed by kind - #157
Merged
Merged
Conversation
The day pane grouped every output into kind sections, so a day read as four
stacked lists instead of as the day it was — and on a real day (570 outputs)
the later sections sat hundreds of lines below the fold, reachable only by
scrolling past everything else.
Rows now come out in the order the outputs first appeared, each stamped with
that time. Kinds became TABS: All plus one per kind the scope produced, each
carrying its count so the bar doubles as the day's rollup. tab/shift+tab
switches — the keys that rotate preview modes on a session row, which a day
row has none of (rowSupportsPreviewModes already said so). As a bonus, tab
on a day row no longer silently rotates sessPreviewMode.
Chronological is NOT the natural insertion order: a session's Refs are
sorted first-seen DESCENDING, so the timeline only exists because of the
explicit sort. Outputs with no recorded entry (plan slugs; refs extracted
before FirstSeen existed) fall back to the producing session's time rather
than a zero that would sink them to the bottom and read as "produced last" —
those stamps are marked `~` so the row does not assert a minute it does not
know. A first mention on another date spells the date out.
Three traps this had to get right:
- a.dayOutputRows holds the FILTERED slice, because that is what
dayOutputsCursor indexes — rendering a filter while indexing the full
list would make enter/o/y/x act on a different row than the highlighted
one. The cursor resets on a tab switch for the same reason.
- the preview cache key carries the tab; without it the next
updateSessionPreview() sees a matching key and the pane reverts.
- the active tab stays in the bar even on a day that produced none of it,
so walking dates under one kind filter keeps comparing like with like.
Kairo-Kim
approved these changes
Aug 14, 2026
|
| Commit | Scanned at | New | Resolved | Net |
|---|---|---|---|---|
2afa7ae < |
2026-08-14 07:50 UTC | 0 | 0 | 0 |
Last scanned: 2afa7ae · 2026-08-14 07:50 UTC
|
| Commit | Scanned at | New | Resolved | Net |
|---|---|---|---|---|
2afa7ae |
2026-08-14 07:50 UTC | — | — | — |
2afa7ae < |
2026-08-14 07:50 UTC | 0 | 0 | 0 |
Last scanned: 2afa7ae · 2026-08-14 07:50 UTC
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
JIRA: https://sendbird.atlassian.net/browse/CPLAT-11489
Follow-up to #156. The daily view's "Produced" pane grouped every output into kind sections — Pull Requests, then Jira Issues, then Artifacts, then Plans. Two things are wrong with that on a real day.
1. Sections are not how a day happened
The pane answers "what came out of this day", but grouping destroys the one ordering a day actually has. "What happened after that PR went up" is unanswerable from four stacked lists.
Rows now come out in the order the outputs first appeared, each stamped with that time, kinds interleaved:
Chronological is not the natural insertion order. A session's
Refsare sorted first-seen descending (session.SortRefs), so without an explicit sort the pane reads backwards inside every session — dropping the kind sort alone would not have produced a timeline.Outputs with no recorded entry — plan slugs, which have no transcript entry at all, and refs extracted before
FirstSeenexisted — fall back to the producing session's time. A zero timestamp would sink them to the bottom of the day and read as "produced last", which is a claim the row cannot support. Those stamps are marked~so the row does not assert a minute it does not know. A first mention landing on another date (a long-lived session carrying a ref in) spells the date out rather than showing a bare time that belongs to the wrong day.2. The later sections were unreachable
Measured on a real day: 570 outputs — 424 PRs, 393 Jira, 7 artifacts, 7 plans. With kinds stacked as sections, Plans sits ~500 lines below the fold, reachable only by scrolling past everything else. Sections are the wrong container at that scale.
Kinds are now tabs:
Allplus one per kind the scope produced, each carrying its count so the bar doubles as the day's rollup — you can see there were 424 PRs without opening that tab.tab/shift+tabswitches. Those are the keys that already rotate preview modes on a session row, and a day row has none to rotate —rowSupportsPreviewModes()already said so, which is why the number keys are suppressed there too. As a side effect,tabon a day row no longer silently rotatessessPreviewMode; that was invisible state corruption that only surfaced after moving back to a session row.Every tab keeps the one chronology, and the selected tab is sticky as you walk between dates, so "what PRs did each day produce" stays one keypress per day. A day with none of that kind says so rather than silently falling back to
All— a silent fallback would break exactly the comparison the stickiness exists for.Three traps this had to get right
a.dayOutputRowsholds the filtered slice, because that is whatdayOutputsCursorindexes. Rendering a filter while indexing the full list would leaveenter/o/y/xacting on a different output than the highlighted one. The cursor resets on a tab switch for the same reason.cycleDayOutputTabclearsCacheKeyand renders, but the nextupdateSessionPreview()— any navigation, any refresh tick — recomputes it. Without the tab in the key that call sees a match, returns early, and the pane silently reverts to the previous tab's content.dayOutputTabsForotherwise drops it and the index lookup falls back toAll.Testing
gofmtandgo vetclean; full suite green on a clean rebase ontomaster.Every fix was verified by disabling it individually and confirming the corresponding test fails:
selectedOwnsDayPane()branch inkm.Session.Previewtab after one press = "", want the PR tab+sessPreviewMode = 1, want it untouchedtimeline order = [middle late early], want [early middle late]cursor = 2, want 0cache key is unchanged across a tab switch — the pane will not repaintAllTwo notes on the test work itself:
TestDayPreviewTabKeySwitchesKinddrivesapp.Update(tea.KeyTab), nothandleDayPreviewKeysdirectly.tabis consumed bykm.Session.Previewlong before the focused-preview handlers run, so a handler-level test would pass while the actual keypress does nothing. The existingTestDayPreviewKeysIgnoreUnrelatedKeysasserts the day pane does not handletab, which is what forced the switch into the right place.