Problem/Motivation

Edit Mode sidebars were assembled imperatively in Edit::buildSideBars() and the client tracked a single active sidebar at a time. This had several limits:

  • Only one panel could be open across the whole UI, so a left-rail tool palette and a right-rail panel could not be shown together.
  • Panels were effectively tied to Edit Mode; an always-on panel (for example an AI chat available on every page, including anonymous and non-edit routes) had nowhere to live.
  • Tools contributed panels through buildLeftSideBar() / buildRightSideBar(), which the mode hard-wrapped, so panels were not independently discoverable or reusable.

Proposed resolution

Introduce a discoverable #[Sidebar] plugin type, move panel assembly to NavigationPlusUi, and make the client SidebarManager track one active panel per side.

  • Add the Sidebar attribute, SidebarInterface, SidebarPluginBase and SidebarPluginManager. Two axes govern a panel: applies() decides DOM presence, while the mode/tool binding plus the {id}_sidebar open/close cookie decide visibility.
  • Move sidebar building from Edit::buildSideBars() into NavigationPlusUi::buildSidebars(), buildSidebarPanel() and isSidebarVisible(). buildSidebarPanel() is public so dynamic, per-request panels (e.g. edit_plus per-entity Change forms) can be rendered for AJAX replacement into the stable navigation-plus-{side}-sidebar wrapper.
  • Port the built-in Settings and Notifications panels to #[Sidebar] plugins. Their toggle buttons are pulled from the plugins into the mode top bar; an always-on (mode-independent) panel instead gets a fixed-position floating launcher.
  • Extract ModeState, a lightweight request-derived mode lookup, so the cookie-auth-critical messenger decorator no longer depends on the now heavier NavigationPlusUi (which pulls in the plugin managers), avoiding a container circular reference.
  • Dispatch LoadEditablePageEvent when the editable page AJAX response is built so modules can attach their own commands.
  • Client: SidebarManager exposes openSidebar(id) / closeSidebar(id) / closeSide() / closeAll() / closeEphemeral() as the single open/close path; type and side are read from the panel element. A shared CLOSE_BLOCKED sentinel and a [data-sidebar-close] behavior let a panel own its close control. Persistent panels survive leaving Edit Mode.

User interface changes

  • Left- and right-rail panels can now be open simultaneously (one active panel per side, mutually exclusive within a side).
  • Always-on panels render a floating launcher button outside Edit Mode.

API changes

  • BC break: ToolInterface::buildLeftSideBar() and buildRightSideBar() are removed. Tools that need a panel now ship a #[Sidebar] plugin.
  • New plugin type #[Sidebar] (Plugin/Sidebar/), with manager service plugin.manager.navigation_plus_sidebars and hook_navigation_plus_sidebar_info_alter().
  • New navigation_plus.mode_state service (ModeState); EditModeMessenger now depends on it instead of NavigationPlusUi.
  • NavigationPlusUi gains public buildSidebarPanel(), isSidebarVisible(), getActiveTool() and getToolPlugins().
  • New LoadEditablePageEvent.
  • Shared sidebar JS moved to the navigation_plus/sidebar library; the SidebarManager API changed from a single active sidebar to per-side tracking.

Comments

tim bozeman created an issue. See original summary.

  • tim bozeman committed 4c4676b5 on 2.3.x
    task: #3594959 Replace hardcoded Edit Mode sidebars with a #[Sidebar]...
tim bozeman’s picture

Status: Reviewed & tested by the community » Fixed

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

tim bozeman’s picture

tim bozeman’s picture