Developer docs/Extension reference
UI schema
Declarative plugin UI: plugins describe pages and slot contributions as a JSON node tree that the frontend renders natively with shadcn components and the active theme. No plugin JavaScript ever runs in the app; embed (a sandboxed iframe) is a documented last resort behind the ui.embed capability.
#Node types
Every node type the renderer understands. Unknown types are rejected at manifest load so a plugin never renders half-broken.
stackrowgridcardsectionseparatortabstabaccordionaccordion_itemdialogheadingtextbadgealertstatkvcodeimageavatariconprogressskeletonemptytooltipmoneydatelinktablelisteachifchartbuttonforminputtextareaselectswitchcheckboxradiocollapsiblepopoversheetdropdownbreadcrumbpaginationscroll_arealabelkbdblockquotelist_itemframeembed
Limits: at most 2000 nodes and depth 32 per tree.
#Slots
Positions an addon can fill on every page. A slot name is <area>.<route>.<position>: area is admin or client, route is the page's route key (path segments without ids joined by -, e.g. /admin/invoices/42 → invoices, /admin/settings/tax → settings-tax) or * for every page. replace:<section> swaps out a named section.
| Kind | Values |
|---|---|
| Page positions | before, after, toolbar, row-actions, tabs, detail-panel |
| Layout positions | header, sidebar, footer, banner |
Slots a plugin can fill with a node tree. Context keys available as {{ctx.*}} are listed next to each slot.
| Slot | Context keys |
|---|---|
admin.dashboard | |
client.dashboard | |
admin.service.detail | ctx.service_id |
admin.customer.detail | ctx.customer_id |
admin.order.detail | ctx.order_id |
admin.invoice.detail | ctx.invoice_id |
client.home |
#UiPage
| Field | Type | Required | Description |
|---|---|---|---|
id | String | yes | [a-z0-9-], unique per plugin; route /admin/p/<plugin>/<id> or /p/<plugin>/<id>. |
area | String | yes | admin or client. |
title | String | yes | Translation key in plugin.<id>.*. |
icon | Option<String> | no | Phosphor icon name (PascalCase without Icon), e.g. HardDrives. |
nav | bool | no | Show in the sidebar. |
hub | Option<String> | no | Nav category whose hub lists the page (billing, addons, …). |
permission | Option<String> | no | |
data | BTreeMap<String, DataSource> | no | |
body | Value | no | Declarative node tree (or null when frame is set). |
frame | Option<Frame> | no |
Source: crates/pelty-extensions/src/ui_schema.rs (UiPage).
#UiSlotContribution
| Field | Type | Required | Description |
|---|---|---|---|
slot | String | yes | |
permission | Option<String> | no | |
data | BTreeMap<String, DataSource> | no | |
body | Value | no | |
frame | Option<Frame> | no | |
order | i32 | no | Order among contributions to the same slot (lower first). |
Source: crates/pelty-extensions/src/ui_schema.rs (UiSlotContribution).
#Frame
A sandboxed iframe served from the addon's own assets/ folder.
| Field | Type | Required | Description |
|---|---|---|---|
src | String | yes | Package path, e.g. assets/ui/index.html (served at /api/v1/addons/<id>/assets/ui/index.html). |
height | Option<u32> | no | Initial height in px (the frame auto-resizes via the bridge). |
Source: crates/pelty-extensions/src/ui_schema.rs (Frame).
#DataSource
| Field | Type | Required | Description |
|---|---|---|---|
get | String | yes | GET path under /api/v1/; may contain {{ctx.*}} / {{params.*}}. |
refresh_secs | Option<u32> | no | Auto-refresh interval (5..=3600 s). |
Source: crates/pelty-extensions/src/ui_schema.rs (DataSource).
#Example
See Addon UI.