Interface IBowireRailContribution
- Namespace
- Kuestenlogik.Bowire.Plugins
- Assembly
- Kuestenlogik.Bowire.dll
Descriptor contributed by a package that wants to add a rail (a left-strip activity-bar icon + its associated sidebar / main-pane view) to the Bowire workbench.
public interface IBowireRailContribution
Remarks
Rails are the top-level navigation primitives in the workbench shell: Discover, Workspaces, Recordings, Mocks, Flows, Proxy, Benchmarks, Security, &c. Each rail used to be hardcoded into the JS bundle. With #294 every rail goes through this descriptor so embedded hosts can pick the rails they ship — drop the Security NuGet, the Security rail disappears from the strip; drop AI, the Assistant module unwires itself.
The descriptor is intentionally narrow. It carries enough metadata for the JS renderer (id, label, icon, sort, group, default-enabled) to draw the rail icon + register the route, but the actual sidebar / main-pane DOM stays inside the existing per-feature JS module the rail bundles with — the descriptor only opts the rail into the strip + Settings → Rail modes.
Implementations are auto-discovered by Discover(ILogger?)
when the host invokes AddBowire(IServiceCollection);
hosts can also register a descriptor explicitly via
services.AddBowireRail<TRail>().
Properties
AlwaysOn
Whether the rail is part of the locked always-on set. Differs
from DefaultEnabled: an always-on rail also can't
be disabled at all. Defaults to false; only the four core
rails (Home, Discover, Compose, Workspaces) ship as always-on.
bool AlwaysOn { get; }
Property Value
DefaultEnabled
Whether the rail is part of the always-on minimum set. Always-on
rails cannot be disabled via Settings → Rail modes (the checkbox
renders greyed with a "Built-in" badge). Set false for
every rail the operator might reasonably want to switch off.
bool DefaultEnabled { get; }
Property Value
DisplayName
Human-readable label shown in the rail tooltip + Settings.
string DisplayName { get; }
Property Value
Group
Visual group the rail belongs to. Adjacent rails with different
group values get a divider between them. Built-in groups:
"work", "scenarios", "quality",
"hardening". New groups land at the bottom of the rail
by default.
string Group { get; }
Property Value
HideFromRail
When true, the rail is in the catalogue (so routing still
works when another rail's tree dispatches into it — e.g.
Collections / Environments dispatched from a workspace) but no
dedicated rail-strip icon renders. Defaults to false.
bool HideFromRail { get; }
Property Value
IconKey
Icon key from the workbench's SVG-icon catalogue (e.g.
"house", "discover", "shield"). Resolved
JS-side via svgIcon(key). Unknown keys fall back to a
generic square placeholder.
string IconKey { get; }
Property Value
Id
Stable identifier (e.g. "discover", "recordings",
"security"). Must match the rail-mode id the JS bundle
uses for routing — operators' localStorage.bowire_rail_mode
values + deep links key off this. Case-sensitive (snake-lower).
string Id { get; }
Property Value
MainPaneRendererKey
Identifier of a JS-side function the rail package's JS fragment
registers on window.__bowireRailRenderers at load time.
The core renderMain dispatcher looks up the renderer by
id and invokes it instead of hard-coding the per-rail branch.
Empty / null means "no rail-owned renderer; fall back to
the core dispatcher arm".
string? MainPaneRendererKey { get; }
Property Value
Remarks
Convention: railId + 'Main' (e.g. "recordingsMain",
"benchmarksMain"). The hosted JS fragment writes
window.__bowireRailRenderers["recordingsMain"] = function () { ... };
inside the shared IIFE. The renderer takes no arguments and
returns the DOM root for the main pane.
RequiresWorkspace
When true, the rail's view only makes sense inside an active
workspace (Recordings / Mocks / Collections / Flows / Benchmarks /
Compose — anything that persists artefacts to a workspace folder).
The rail button stays clickable (so tour spotlighting + the rail
strip's tab semantics keep working) but a click without an active
workspace redirects the operator to the Home rail, where the
"Create your first workspace" CTA lives, and fires an explanatory
toast. Defaults to false — rails that work standalone
(Home, Discover, Traffic, Workspaces, Security, Settings) stay
reachable at all times.
bool RequiresWorkspace { get; }
Property Value
SidebarKind
Sidebar template the rail renders. Recognised values: "none",
"services", "collections", "environments",
"recordings", "mocks", "workspaces",
"sources", "benchmarks", "flows",
"proxy", "security", "library". Adding a
new value requires a matching arm in render-sidebar.js's
dispatcher — see the sidebar.kind comment block in that
file.
string SidebarKind { get; }
Property Value
SidebarRendererKey
Identifier of a JS-side function the rail package's JS fragment
registers on window.__bowireRailRenderers at load time.
The core renderSidebar dispatcher looks up the renderer by
id and invokes it instead of hard-coding the per-rail branch.
Empty / null means "no rail-owned renderer; fall back to
the core dispatcher arm" — so the slice can be moved
incrementally rail-by-rail without breaking the bundle.
string? SidebarRendererKey { get; }
Property Value
Remarks
Convention: railId + 'Sidebar' (e.g. "recordingsSidebar",
"proxySidebar"). The hosted JS fragment writes
window.__bowireRailRenderers["recordingsSidebar"] = function () { ... };
inside the shared IIFE. The renderer takes no arguments and
returns the DOM root to mount as the sidebar — same contract as
the legacy renderRecordingsSidebar() &c. arms.
SortIndex
Sort priority. Lower values appear higher in the rail strip. The built-in catalogue uses 100-step intervals so third-party rails can wedge between two built-ins without re-numbering everything.
int SortIndex { get; }