Skip to content
docsv0.34.0

AdminSection

One section of the admin panel, as a plugin declares it. A section IS a Milpa Component — or a whole VIEW of them. It either names a component the panel already knows (the dashboard primitives — `metric-card`, `data-table`, `dashboard-grid`… — rendered with `$props`), or it brings its own: a `$definition` plus the `$renderer` that paints it, which the panel registers under `$component` before composing; or it brings a `$view` ({@see DeclaredView}) — a tree of components with their definitions, renderers, props and signal seeds, which the panel registers and compiles the same way (greenhouse decisions/0211). Either way the panel never learns the plugin's name — it learns the section's, and that is enough to list it, route it, render it and attribute it: the header of every section says «declared by <Plugin>», read from the catalogue, never from the section. What the panel hands the component: the `ComponentContext` it mounts with carries the section's component id (`milpa-admin-section-<id>`), the `principal` the gate authenticated (the actor's id, or null when nobody is signed in — the same fact the topbar shows), the `locale` the page answers in, the panel's `route` (its mount point) and, in `meta`, the host facts a guest may need without widening any contract: the gate in effect, the active section's id and the request's query ({@see \Milpa\Admin\View\AdminShell::META_GATE}, `META_SECTION`, `META_QUERY`). For the narrow shape the props are `$props` plus the request's query under `query`; a view's props are its own, per component. One prop name is RESERVED: `query`. The shell hands every active section the request's query params under `props['query']` (greenhouse decisions/0205), so a section that declared its own `query` would see it silently replaced on every request — the constructor refuses it instead. The sidebar lists sections by `$group` — one heading per distinct value, `admin` (the panel's own) first, then `app` (the default), then `agent`, then any other name in alphabetical order — and, within a group, by `$order` (lower first; ties break by `$id`, alphabetically). The panel OPENS on the first section in that same (`order`, `id`) order across every group, which is why the convention matters: the panel's own sections take 10..40 (Plugins 10, Routes 20, Settings 25, Stack 30, Dev tools 40), and a guest picks an order AFTER those — greenhouse decisions/0210 names 60 for the Desktop's Agent section — unless it means to be the page the panel opens on. A guest at order 10 named `agent` would tie with Plugins, win the tie by id, and become the front page. What a section may not do: bring its own `$definition` under a name the panel registers itself (a dashboard primitive, `admin-sidebar`, `admin-section-header`) — naming one is fine, redefining one would repaint every section that names it, so the panel refuses the section and says so.

AdminSection::__construct()

public function __construct(string $id, string $title, string $component = '', array $props = [], int $order = 0, string $group = self::GROUP_APP, ?Milpa\Live\Contracts\Component\ComponentDefinitionInterface $definition = null, ?Milpa\Live\Contracts\Rendering\ComponentRendererInterface $renderer = null, string $icon = '', ?Milpa\Admin\Section\DeclaredView $view = null, string $parent = ''):

Parameters

Parameters of __construct()
NameTypeDescription
$idstringthe section's identity and URL segment (`^[a-z][a-z0-9-]{0,40}$`)
$titlestringa catalog key the panel knows, or the literal title
$componentstringthe Milpa component name that renders the section — empty, and only empty, when the section brings a `$view` instead
$propsarray<string, mixed>the props the component mounts with — never `query`, which is reserved: the shell fills it with the request's query params. Empty with a `$view`, whose props are per component
$orderintsidebar position within the group, and the panel's front page across groups (lower first; ties break by id). The panel's own are 10..40 — a guest picks an order after those
$groupstringthe sidebar group: {@see self::GROUP_ADMIN} (the panel's own), {@see self::GROUP_APP} (default), {@see self::GROUP_AGENT}, or any other name — one heading per distinct value, admin → app → agent → others alphabetically; the heading comes from the catalog when it knows the group, else the raw value uppercased
$definition(ComponentDefinitionInterface | null)the component, when the section brings its own
$renderer(ComponentRendererInterface | null)the renderer for that component (required with it)
$iconstringa glyph for the sidebar item, optional — painted before the label
$view(DeclaredView | null)the whole tree the section declares instead of one component (greenhouse decisions/0211); with it, `$component`, `$props`, `$definition` and `$renderer` stay empty — the view carries them
$parentstringthe id of the section this one belongs UNDER, optional. A child stays out of the main navigation and is reached through its parent's gear; it routes at `{route}/s/{id}` like any other, keeps the same middleware, and can never be the panel's front page. One level only: a child of a child is refused, because a gear that opens a gear is a menu nobody asked for. A parent id nobody declared leaves the section a ROOT rather than hiding it — uninstalling one plugin must not make another's section unreachable (greenhouse decisions/0268)

AdminSection::ofView()

public static function ofView(string $id, string $title, Milpa\Admin\Section\DeclaredView $view, int $order = 0, string $group = self::GROUP_APP, string $icon = '', string $parent = ''): self

A section that declares a whole {@see DeclaredView} — the shape a plugin brings its own UI in (greenhouse decisions/0211). The same as the constructor with `view:`, said in one line.

Parameters

Parameters of ofView()
NameTypeDescription
$idstring
$titlestringa catalog key the panel knows, or the literal title
$viewMilpa\Admin\Section\DeclaredView
$orderintsidebar position within the group; the panel's own take 10..40
$groupstring{@see self::GROUP_ADMIN}, {@see self::GROUP_APP}, {@see self::GROUP_AGENT}, or any name
$iconstringa glyph for the sidebar item, optional
$parentstringthe id of the section this one belongs under — out of the main navigation, behind that section's gear, same URL and same gate. A factory that could not say this would make nesting a privilege of the constructor, and every guest that brings a view uses the factory (greenhouse decisions/0268)

AdminSection::isCustom()

public function isCustom(): bool

True when the section brings its own component instead of naming a registered one.

AdminSection::hasView()

public function hasView(): bool

True when the section declares a whole view instead of one component.