desktop: channel-feature registry (settings sections + channel classification) - #6865
Open
jmreijnen-parkbee wants to merge 5 commits into
Open
Conversation
added 5 commits
August 26, 2026 13:26
SettingsSection union, SETTINGS_SECTION_VALUES/isSettingsSection, the settingsSections descriptor, the renderSettingsSection switch, and SettingsView's settingsNavGroups were five parallel structures a new settings section had to touch. settingsSections is now the single source: each descriptor carries value/label/icon/featureGate as before, plus group, order, and a render(props) closure lifted from the old switch case. SettingsView derives nav grouping and panel rendering directly from the registry. Behavior, data-testids, and section order/grouping are unchanged (including the pre-existing "moderation" section, which isn't wired into any nav group both before and after this change). Part of the desktop channel-feature-registry seam proposed in block#3280. Signed-off-by: Joost Reijnen <jreijnen@parkbee.com>
…spatch
Introduces shared/channel-features: a ChannelFeaturePlugin registry
modeled on the existing shared/features/ flag manifest ("typed
definition list + resolver hook + gate"), per
block#3280.
A plugin classifies a channel (parseBinding) into a typed binding and
declares the glyph shown for channels it matches. Four built-in plugins
(dm, private-channel, forum, stream — registered in priority order in
builtins.ts) now back two call sites that used to independently
re-derive "what kind of channel is this":
- ChatHeader's ChannelIcon dm/private/forum/hash cascade is now a
channelGlyph() lookup against the registry instead of an inline
if-chain.
- ChannelScreen's forum-vs-chat content dispatch (and three related
layout checks: single-panel view, transparent chrome, the
timeline-loading gate, and the "manage" action's forum branch) now
read one classifyChannel(activeChannel)?.pluginId === "forum" result
instead of four independent activeChannel.channelType === "forum"
checks.
This is intentionally the minimal, behavior-preserving slice of the
RFC's proposed surface that current upstream has a second real
consumer for. The RFC's fuller plugin surface (tabs, settingsPanel,
sidebar group/create-actions, headerAction) is not ported here — see
PR_DESCRIPTION.md's Follow-ups for why and what it would take.
registry.test.mjs exercises the built-in plugin priority/precedence
cascade and registerChannelFeature's dedup/sort behavior.
Signed-off-by: Joost Reijnen <jreijnen@parkbee.com>
Covers problem/how/testing/follow-ups per CONTRIBUTING.md's PR checklist, states this implements block#3280, notes the complementary relationship to block#3275, and records today's duplicate-issue/PR search. Signed-off-by: Joost Reijnen <jreijnen@parkbee.com>
Signed-off-by: Joost Reijnen <jreijnen@parkbee.com>
Signed-off-by: Joost Reijnen <jreijnen@parkbee.com>
jmreijnen-parkbee
force-pushed
the
upstream-pr/channel-feature-registry-seam-b
branch
from
August 26, 2026 11:27
45889cb to
b3f0788
Compare
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.
Implements #3280.
Problem
Adding a channel-scoped feature to the desktop client means editing several
centrally-owned files at once. Two concrete cases of this exist in current
upstream
maintoday:SettingsPanels.tsx/SettingsView.tsx):a
SettingsSectionunion type, aSETTINGS_SECTION_VALUESarray,isSettingsSection, asettingsSectionsdescriptor array, arenderSettingsSectionswitch with aneverexhaustiveness gate, andSettingsView's separatesettingsNavGroupsmap. Five parallelstructures a new settings section has to touch.
ChatHeader'sChannelIconre-derives "what kind of channel is this" (dm, private, forum, hash) as
an inline if-chain, and
ChannelScreenseparately re-checksactiveChannel.channelType === "forum"in four different places todecide what to render.
This PR is the client-side companion the RFC describes, ported fresh onto
current upstream. Our original implementation lived in a fork whose git
history isn't connected to this repo (a content-snapshot import, not a real
fork), so it couldn't be cherry-picked. See "Provenance" below.
How
Commit 1, settings-section registry.
settingsSectionsis now thesingle source of truth: each descriptor carries
value/label/icon/featureGateas before, plusgroup,order, and arender(props)closure lifted from the old switch case.
SettingsViewderives navgrouping and panel rendering directly from the registry. Behavior,
data-testids, and section order/grouping are unchanged, including thepre-existing
"moderation"section, which isn't wired into any nav groupeither before or after this change.
Commit 2,
shared/channel-featuresregistry. AChannelFeaturePluginregistry modeled on the existing
shared/features/flag manifest (typeddefinition list, resolver hook, gate):
Four built-in plugins (
dm,private-channel,forum,stream,registered in priority order in
builtins.ts) reproduceChatHeader'sexisting dm, private, forum, hash cascade exactly, and now back two call
sites that used to derive it independently:
ChatHeader'sChannelIconcallschannelGlyph({channelType, visibility})instead of the inline if-chain.
ChannelScreencomputesisActiveChannelForumonce, viaclassifyChannel(activeChannel)?.pluginId === "forum", and reuses it forthe forum/chat content dispatch, the single-panel-view check, the
transparent-chrome check, the timeline-loading gate, and the "manage
channel" action's forum branch. Five sites that used to check
channelType === "forum"on their own.Registration happens at module scope in
shared/channel-features/index.ts,the same way
shared/features/manifestloads at import time, so any callsite that imports from the barrel gets the built-ins for free.
Not in this PR
The RFC's fuller proposed surface,
tabs,settingsPanel,sidebargroup/create-actions,
headerAction, is not in this PR. Our originalimplementation had those because our fork added new channel types
(product/repo/board-hierarchy) that needed their own tab bars, sidebar
groups, and settings panels. Current upstream
mainhas no secondconsumer yet: the only two dispatch points that exist today (
ChatHeader'sglyph,
ChannelScreen's forum/chat split) are a binary classification, nota multi-tab surface. Adding the tab/sidebar-group machinery now would be
speculative for zero real callers. See Follow-ups below for what would
justify porting the rest.
Relationship to #3275
#3275 ("host MCP Apps as channel tabs") is the motivating case for the RFC:
it extends
ChannelScreen's shared shells directly to add a new tab type.This PR doesn't touch #3275's code, and its content dispatch (forum vs.
chat) is orthogonal to MCP-App tabs, which install within a channel that's
already classified as a normal chat channel. There's no merge conflict or
ordering dependency between the two.
The natural follow-up once both land: an MCP-App-tabs plugin would extend
ChannelFeaturePluginwith atabsfield, as the RFC describes, andregister its tab bar for channels with an installed app. This PR doesn't
ship that field pre-emptively, since there's no real second tab-contributing
plugin in this repo yet to shape it against. It answers the same question
by proving the
parseBinding/glyph/priority-cascade mechanics on two realcall sites, so that field has something real to build on.
Review focus
channel classifier, no
tabs/sidebar/headerActionsurface) theright size for a first PR, or should more of the RFC's surface be
included speculatively even without a second consumer?
review question about the same relationship ("does the current typed
channel-surface seam compose cleanly with the behavior-preserving
registry proposed in RFC: desktop channel-feature registry to replace the per-feature tab/settings/sidebar wiring (behavior-preserving; complements #3275) #3280")? This PR doesn't answer that by adding a
tabsfield, it answers it by proving the underlying mechanics: doesthat stand on its own, or do you want the
tabsfield sketched heretoo even without a plugin to use it yet?
channelGlyph's stream-vs-Hash styling special case inChatHeader.tsxis the one place the port kept a pre-existing wart rather than
generalizing it. Worth fixing here, or fine as a named follow-up?
Testing
At commit
31861518d(the last code commit on this branch; later commitsonly touch this description):
pnpm typecheck: clean.pnpm lint(biome check): clean on all touched/added files (twopre-existing warnings and two pre-existing infos elsewhere in the repo,
unrelated and unchanged).
pnpm test(unit,node --test): 5463 passed, 0 failed, including thenew
desktop/src/shared/channel-features/registry.test.mjs(11 tests:built-in plugin registration order, idempotent re-registration, the
dm/private/forum/stream classification cascade and its precedence, and
registerChannelFeature's sort/dedup behavior).pnpm build:e2e: clean build.pnpm exec playwright test --project=smoke --grep "forum|Forum|settings|Settings|sidebar|Sidebar":112 passed, 1 skipped, 0 failed (covers
settings-section-layout.spec.ts,sidebar.spec.ts,sidebar-offcanvas-rail.spec.ts,sidebar-relay-card.spec.ts,sidebar-snapshot.spec.ts,sidebar-more-unread-overlap.spec.ts,hosted-communities-settings-screenshots.spec.ts,invites-settings-screenshots.spec.ts,profile-backup-settings.spec.ts,voice-settings.spec.ts, and the forum-touching cases in the broaderchannel specs).
just ci). ThisPR has no Rust changes and no diff outside
desktop/src, and the fullJS/TS suite plus the targeted grep above already cover every spec that
touches channel tabs, sidebar hierarchy, and settings. A reviewer with
more time may want the full suite for extra confidence.
Screenshots
Captured locally against a dev build and the mock bridge:
(Personal/Communities/App) and unchanged panel content.
#generalchannel, showing thestreamplugin's Hash glyph in thechannel header, the same icon the old inline cascade produced for a
plain open stream channel.
These weren't posted through
scripts/post-screenshots.sh, since thatscript needs an open PR and none was opened for this branch. Whoever opens
the PR from
upstream-pr/channel-feature-registry-seam-bshould recaptureand post screenshots through that script at PR-creation time.
Follow-ups
tabs/ChannelFeatureShellsurface once a second realtab-contributing plugin exists (an MCP-App-tabs plugin building on
feat(desktop): host MCP Apps as channel tabs #3275, or a future Sequence/board/docs-style channel type). A second
concrete caller is the right trigger, shaping it against one hypothetical
consumer risks guessing wrong.
ChannelFeatureSidebar), samereasoning. Upstream has no repo/product-style sidebar hierarchy today to
drive the design.
headerAction, same reasoning. No plugin needs to contribute a headeraction yet (our fork needed this for a "New idea" dialog action that
doesn't exist upstream).
channelGlyph's stream-vs-Hash styling special case inChatHeader.tsxis worth generalizing into a per-plugin style hook, orleft as the one acknowledged wart of an otherwise uniform glyph lookup.
Duplicate check
gh api search/issues -f q='repo:block/buzz channel feature registry ChannelFeaturePlugin'returns exactly two results: issue #3280 (this RFC) and PR #3275 (the MCP
Apps host, discussed above). No other open or closed issue or PR implements
a channel-feature or settings-section registry for the desktop client.
Provenance
The design was originally implemented and reviewed in a fork whose git
history isn't connected to this upstream repo (a content-snapshot import,
not a real fork), so it couldn't be cherry-picked or rebased. This PR is a
fresh port of the mechanism onto current
upstream/main, adapted to whatupstream's
ChannelScreen/ChatHeader/settings code actually look liketoday, which has drifted from our fork's snapshot: the settings-section
descriptor shape, the channel dispatch's actual branch points, and the
absence of any custom channel-type/tab surface all differ from what the
original diff assumed. See "Not in this PR" above for the scope that drift
and the behavior-preserving constraint together produced.