Skip to content

Expose panel collapse on the request/provide bus - #322

Open
sandesh-sp wants to merge 4 commits into
developmentfrom
feat/panel-collapse-bus-api
Open

Expose panel collapse on the request/provide bus#322
sandesh-sp wants to merge 4 commits into
developmentfrom
feat/panel-collapse-bus-api

Conversation

@sandesh-sp

@sandesh-sp sandesh-sp commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

Why

Panels can only be driven from inside core. PanelManager_ is reachable by direct import, which a plugin cannot do across a sandbox boundary, so a plugin that wants to draw its own collapse control — a rail with a chevron for the panel beside it, say — has no way to read panel state or act on it.

What

Three handlers on the request/provide bus plugins already use for everything else:

  • panels:getAll — lists each panel with what it takes to target one: id, position, current state, collapsible (whether its constraints permit both collapsing and restoring), and toolIds, which is how a plugin recognizes the panel it lives in.
  • panels:show / panels:hide — wrap the existing showPanel/hidePanel methods, pairing on the bus the way the core: command events already do. Each names the state it wants rather than flipping whatever it finds, so a control that read the layout before the user clicked still lands on the state the click asked for, and a failed request is safe to retry. Both report false rather than throwing: an unknown panel, a panel whose constraints forbid the requested state, or a malformed payload is a caller mistake, not a layout failure.

Matching typed helpers (mmgisGetPanels, mmgisShowPanel, mmgisHidePanel) land in the plugin adapter at src/essence/Tools/_shared/adapters/mmgisAPI.ts. They have no caller until #323.

Panel changes already broadcast on mmgis-panel-layout-changed, so callers follow state by re-requesting the listing rather than polling. No new event.

The handlers register at module scope so they exist from import.

Scope

Additive, with one exception: PanelManager_.addToolToPanel now calls notifyLayoutChanged(), so a panel gaining a tool broadcasts just as losing one already did. Both call sites are in ToolControllerModern_.assignToolsToPanels, which modern.js runs before UserInterfaceModern_.init() subscribes its listener — so today the extra broadcast has no observer and is defensive only. No other PanelManager_ method changes.

Testing

tests/unit/panelBusHandlers.spec.js covers registration, the listing's shape (including collapsible and toolIds), the collapse/restore round trip and its idempotence, and the failure modes (unknown panel, constraints forbid it, malformed payload).

Panel suites at this branch tip: 87 tests passing across tests/unit/panelBusHandlers.spec.js and tests/unit/panelManager/, tsc --noEmit clean.

Related

The first consumer is the LayerFilterThemes rail's collapse chevron, in #323. That branch is independent and merges on its own; its chevron hides itself while these handlers are absent, and appears once this lands.

Panels can only be driven from inside core: PanelManager_ is reachable by
direct import, which a plugin cannot do across a sandbox boundary. A plugin
that wants to draw its own collapse control -- a rail with a chevron for the
panel beside it, say -- has no way to read panel state or act on it.

Register two handlers on the bus that plugins already use for everything
else. `panels:getAll` lists each panel with what it takes to target one:
its position, current state, whether its constraints permit collapsing, and
the ids of the tools it hosts, which is how a plugin recognizes the panel it
lives in. `panels:toggleCollapsed` wraps togglePanelCollapsed and reports
failure rather than throwing, since an unknown panel or one that forbids
collapsing is a caller mistake and not a layout failure. Changes continue to
broadcast on mmgis-panel-layout-changed, so callers follow state by
re-requesting the listing rather than polling.

The handlers register at module scope so they exist from import, which the
mmgisAPI test stub has to account for -- fill it out with the
provide/request/hasHandler bus it was missing.
The handlers registered from PanelManager_, which made a layout primitive
import the API boundary and drag the whole mmgisAPI graph in behind it.
Register them alongside the existing showPanel/hidePanel/togglePanel
methods instead, reading through the _panelManager reference that
UserInterfaceModern_ already injects, so the dependency runs one way and
the handlers inherit the "modern layout not active" guard.

Replace panels:toggleCollapsed with panels:show and panels:hide, mirroring
the core:showPanel/core:hidePanel commands. A sandboxed plugin reads panel
state asynchronously, so a toggle sent on a click lands on the opposite
state if anything moved the panel since the listing was read, and a failed
request cannot be retried. Both commands are idempotent and delegate to the
existing implementations, so neither needs a new direct method.

panels:getAll resolves null under the legacy layout rather than an empty
array, letting a caller tell "no panels here" from "none registered yet",
and reports collapsible only for a panel that can be both collapsed and
restored — one that permits collapsing with no visible state to return to
is stuck once collapsed.

Broadcast the layout change when a tool joins a panel. addToolToPanel was
the only mutator that did not, leaving toolIds — the field a plugin uses to
recognize the panel it lives in — silently stale.

Document the providers and the mmgis-panel-layout-changed event, whose
payload carries core's internal panel objects rather than the listing
shape, and add typed wrappers to the shared adapter that holds the bus
name strings.
The rationale for naming a state rather than toggling was written four
times over — the docs page, both adapter docstrings, the block above the
provide calls, and a test. Keep it in the docs and leave each code site
with its contract.

Correct the listing's documented empty-array case while here: the modern
layout registers its panels before mmgisAPI holds the manager, so a
non-null result is always populated.
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.

1 participant