Skip to content

feat: pinned threads and manual arrangement - #663

Merged
Tryanks merged 6 commits into
mainfrom
feat/pinned-threads
Oct 9, 2026
Merged

Tryanks merged 6 commits into
mainfrom
feat/pinned-threads

Conversation

@Tryanks

@Tryanks Tryanks commented Oct 8, 2026

Copy link
Copy Markdown
Owner

Summary

core      SessionMeta { pinned_at, pin_order, active_order }      (serde defaults)
          thread_sort: Pinned → Active → Settled sections
            pinned: keyed by key, then keyless newest-created
            active: keyless by max(created, unsettled) desc, then keyed by key
          order_key_between / spread_order_keys / plan_reorder    (base-26, no trailing `a`,
            None on corrupt or reversed bounds → caller spreads, hidden rows keep their keys)
          settlement: pinned_at blocks automatic settlement (inactivity and PR routes)
protocol  PinSession{session_id, order_key?} · UnpinSession · ReorderPinned{order_key} · ReorderActive{order_key}
runtime   pin: promotes Settled → Active (no unsettled_at), keeps an existing pin's key
          unpin: clears pin + key, stays Active      settle: also clears pin, pin key, active order
          refusals: archived · empty key · ReorderPinned on unpinned · ReorderActive on pinned/settled
ui        sidebar (Flat, Grouped, phone)  pinned rows first, pin glyph, hover Unpin (gpui-base Button)
          desktop drag (sidebar/arrange.rs) within/between sections, Pin/Unpin/Settle/Un-settle badge,
            labels only while dragging, empty-section targets, Escape cancels, edge auto-scroll
          phone: PINNED / ACTIVE captions; Destination::ArrangeThreads page with grip handles
          menu: Pin thread / Unpin thread · Move up / Move down · Arrange threads… (phone)
          undo: unpin → PinSession{former key}; settle → UnsettleSession + PinSession{former key}

Closes #528

Evidence

  • Before: no pinned state; the sidebar had Active and the Settled shelf only.
    After (desktop, light): pinned rows lead, each with its pin glyph
    desktop
    After (phone, light): Arrange threads
    phone

Checks (after rebasing on 4ed9683):

  • cargo fmt --all --check: clean
  • cargo clippy --workspace --all-targets --locked -- -D warnings: clean
  • cargo nextest run --workspace --locked: 1048 tests run: 1048 passed, 13 skipped
  • cargo machete: no unused dependencies

Tests:

  • new runtime::app::tests::pinning_promotes_and_exempts_until_a_settle_unpins: drives the pipe. A pin promotes a settled thread without stamping unsettled_at. An aged pinned thread survives the inactivity sweep while an unpinned one settles and loses its active order. Unpin keeps Active. Settle unpins. Covers both reorder refusals. Fails without the pinned blocker (checked).
  • new core::thread_sort::tests::{keys_fit_between_any_neighbours_and_refuse_corrupt_bounds, spread_keys_stay_ordered_and_insertable, a_move_writes_one_key_unless_a_neighbour_has_none}
  • new ui::sidebar::tests::pinned_rows_lead_and_a_drag_or_undo_writes_their_keys: checks the rendered order on desktop Flat and the phone list. A real mouse drag of an active row between two pins sends one PinSession with a key between theirs. Escape cancels a drag. Settle and undo send UnsettleSession + PinSession{"t"}.
  • extended core::settlement tests: pinned joins the blocker table, and a pinned thread with a merged PR does not settle.
  • No test deleted or rewritten.

Live checks:

  • Desktop app on a synthetic TCODE_DATA_DIR profile: a real mouse drag pinned an active row between two pins. The phone shot shows the result ("Dark mode contrast pass" in Pinned).
  • Phone example (--local, same profile) for the Arrange page. The page was reached through a temporary local edit that rendered it in place of the thread list (not committed). The truncated title comes from the desktop phone example's traffic-light inset.

Platform gaps:

  • Mid-drag screenshot not captured.
  • Handle drag on real iOS/Android touch not exercised.
  • Mobile and Web builds run in CI.

Merge Danger

Door: two-way
Blast Radius: sidebar
New optional metadata fields and four new commands; old indexes decode unchanged. Row ordering, the hover verbs and the settle undo change for every sidebar layout.

@Tryanks
Tryanks marked this pull request as ready for review October 9, 2026 01:20
@Tryanks
Tryanks merged commit 835afd5 into main Oct 9, 2026
7 checks passed
@Tryanks
Tryanks deleted the feat/pinned-threads branch October 9, 2026 01:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Thread lifecycle: pinned threads and manual arrangement (B2)

1 participant