Modules
Admin screens
An admin screen is HTML in a sandboxed frame styled like the admin. Forms post back to the same screen (req.method == "POST", req.form); links starting ? load the screen with that query; other links open in a new tab. A screen may answer ctx.response({ html, toast: "Saved" }) to choose the message the admin shows after a post (toast: false shows none). Screens appear under "From modules" in the admin's navigation for everyone who may open them: by default editors (edit_pages) and module managers; with { capability: "publish_pages" } whoever has that capability.
ctx.admin.card(title, fn) adds a card to the dashboard; the card may answer { html, screen: "Forms" } to give it an Open button.
ctx.ui builds the usual pieces, escaping every value:
ctx.ui.tabs([["?view=forms", "Forms"], ["?view=entries", "Submissions"]], "?view=forms")
ctx.ui.notice("Saved.", "success") // info, success, warning, error
ctx.ui.table({ columns: [
{ key: "name", label: "Name", link: "?view=edit&id={id}" }, // {field} is filled from the row
{ key: "created_ts", label: "Sent", format: "datetime" }, // date, datetime, bool
{ key: "actions", label: "", html: true }, // cells the module built with ctx.ui
], rows: rows, empty: "Nothing yet." })
ctx.ui.form({ action: "save", values: row, submit: "Save", fields: [
{ name: "title", label: "Title", required: true, help: "Shown at the top." },
{ name: "kind", label: "Kind", type: "select", options: [["a", "A"], ["b", "B"]] },
{ name: "id", type: "hidden" },
] }) // types: text, textarea, number, email, url, password, date, datetime-local, time, color, select, checkbox, hidden, file
ctx.ui.pager(ctx.db.page(...)?, { view: "entries" }) // previous / next, keeping the other query values
ctx.ui.stats([{ label: "This week", value: 12, hint: "3 unread" }])
ctx.ui.button("Delete", { action: "delete", id: row.id }, { confirm: "Delete this?", style: "danger" })
Modules → a module → Log shows what the module printed and the errors its routes, widgets, screens, hooks, jobs and queued work hit since the site started.