Skip to content

Let a plugin offer a sort mode for the built-in sidebar thread list #4450

Description

@merllinsbeard

The workflow

I run a plugin that computes a status for every thread: it needs me, it errored, it is working, it is waiting, it is set aside, or it is done. I want the built-in Thread list to sort by that status, so that inside each project and section the threads that need me come first. I do not want to replace the whole list to get this.

What happens today

The built-in list sorts only by updated time, created time, or title. The only way for a plugin to change the order is experimental_threadList, an exclusive replacement slot. A plugin that takes it has to rebuild rows, grouping, pinning, drag and drop, shortcuts, and windowing, and it falls behind bb as those change.

#2135 asked for the general version: regions, regrouping, and a custom order. It was closed as no longer planned, with "reopen if a concrete host-owned composition need returns". This is one such need, limited to order. experimental_threadList stays the surface for fully custom lists.

What you would expect

A narrow, experimental surface where a plugin supplies only sort keys:

  • app.experimental_sidebarThreadSorts.register({ id, title, description? }) returns a controller. setKeys({ [threadId]: { rank, at } | null }) replaces every key of that sort: rank ascending, then at descending.
  • experimental_useSidebarThreadSorts() lets any list read the registered sorts: <pluginId>:<id>, title, and keys. A plugin's sorts and keys go away when it is disabled or its frontend fails to load. After a reload it starts with no keys.
  • The Thread list shows plugin sorts under Sort by, after the built-ins. It stores the choice in a synced pluginSort preference, also settable with bb thread-list prefs set pluginSort <pluginId>:<id>.
  • Within every existing group, nested children included, threads are ordered by the plugin's keys, then by the saved built-in sort. Threads without a key follow keyed ones. A worktree group moves as one block, placed by its best-keyed thread.
  • Grouping, section and project order, collapsed state, and Pinned stay as they are. Without the providing plugin, the list silently uses the built-in sort.
  • During a drag, a pointer press, keyboard focus in the sidebar, or a rename, the list keeps the plugin keys it had and applies newer keys when that ends. Unkeyed threads and exact ties still follow the live built-in sort.
  • When new keys reorder rows, the rows the reader sees stay in place.

A prototype is on my fork, based on 4354b88: main...merllinsbeard:bb:feat/plugin-thread-sort (4 commits, head merllinsbeard/bb@7a20062). Main pieces:

Context and alternatives

The thread-list test suite passes on the prototype's code (472 tests), and typecheck, lint, and oxfmt are clean for the package.

I also ran a dev build with my own status plugin, which is private. In it I checked:

  • switching sorts;
  • Pinned order;
  • collapsed sections and collapsed children;
  • children staying nested under their parents;
  • moving threads between sections;
  • live reorders on a new question, a thread I stopped, and a status change of the selected thread;
  • the phone sidebar;
  • fallback when the plugin is disabled.

That run found one bug, now fixed in the prototype. When a thread moved to the top of its group, React moved nearly every row node, the browser lost its scroll anchor, and the visible rows jumped by one row height. The list now snapshots the visible rows before the update and restores their positions after it.

Alternatives I ruled out:

  • A full experimental_threadList replacement: too much duplicated behavior.
  • Manual ordering (Allow manual ordering of unpinned threads within each project #4425): it does not follow live status.
  • A built-in "By status" sort over bb's own row indicator: it covers error, waiting, and working, but not states a plugin defines, such as set aside or done. Each workflow also ranks states differently.

This came out of a local bb thread that is not publicly reachable. The commit messages on the branch record the design and the checks.

Before a PR, I would like your call on three points. The full list is in the api_to_audit.md entry linked above.

  1. Is { rank, at } enough, or would you prefer string keys or a comparator?
  2. Should holding the order during interactions and keeping visible rows in place move to the host, so every list behaves the same? Or should they stay in the Thread list?
  3. When the providing plugin is missing, should the list keep the saved choice and fall back silently, as the prototype does? Or should Sort by show the sort as unavailable?

I will open a PR once the shape is agreed.

Checks

  • I searched open and closed issues for the same request.
  • If an agent wrote this, the body ends with > AGENT GENERATED.

AGENT GENERATED

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    pluginsPlugin SDK, runtime, marketplaceuiApp shell, sidebar, composer, rendering

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions