Expand description
Tablo: a server-rendered admin toolkit on Topcoat and Toasty.
A Panel serves one Resource per Toasty model. A resource names the model, whose
ModelColumns give its default table and detail page, and the record
form its create and edit submissions parse into, which ModelForm derives
from the model or RecordForm from a struct of its own. It declares the
rest as one ResourceDef value: its Policy, which denies by default, and any Table,
Schema or Detail that replaces or extends the defaults.
The app mounts the panel on its own Topcoat router with RouterBuilderPanelExt::panel, which
builds each def once and checks it against the database schema first; one router mounts any
number of panels at distinct prefixes.
#[derive(Debug, Clone, toasty::Model, tablo_core::ModelColumns, tablo_core::ModelForm)]
pub struct Book {
#[key]
#[auto]
pub id: uuid::Uuid,
pub title: String,
}
pub struct BookResource;
impl Resource for BookResource {
type Model = Book;
type Form = BookForm;
fn declare() -> ResourceDef<Self> {
ResourceDef::new().policy(Allow)
}
}
let router = Router::builder()
.discover()
.app_context(db)
.panel(Panel::new("admin").resource::<BookResource>())?
.build();The user guide walks through a complete panel and each
part of it. ResourceDef lists everything a resource declares, Resource the hooks it
overrides, and Panel every builder call.
Modules§
- auth
- Authenticates panel users and gates panel routes.
- csrf
- CSRF protection via double-submit cookie.
- db
- The
Dbglue: how Tablo code reaches the pooled Toasty database, and the transaction a panel write runs its record fns and hooks in. - extend
- The traits that add a new kind of building block to a declaration: a
Columna table lists and a detail page shows, aFiltera table offers, aControlaField::customfield renders, anOptionSourcea relationship choice loads its options from, aTypedValuea text field parses, aFilterDateaDateFiltermatches by day, and aFilterKeyaSelectFiltermatches.Includes,FilterInput,FilterValue,ControlFutureandControlInputare what their methods take and return. - notification
- Messages for a panel user: the toast a write flashes, and the
StoredNotificationsNotificationssends to the bell of a panel withPanel::notifications. - rich_
text - Rich text (ADR-0032): the
Tools a toolbar offers, the HTML each produces, and the cleaning that keeps a value to the elements its tools produce. A rich text field cleans what it reads andRichTextColumnwhat it renders; a page of the app’s own renders a stored value throughclean. - url
- URLs into the request’s panel, so app code never spells a prefix.
Macros§
- lens
- Build a
Lensfrom a model and a field, or a chain of embedded fields. - models
toasty::models!with the models Tablo ships appended, so a panel’sDbholds every table auth reads.- relation
- Build a
RelationLensfrom a model and one of its relation fields. - t
- A message spelled in the request’s locale:
t!(cx, "id", name = value, ..)istext!("id", name = value, ..).localize(cx), for what takes aString, such as aNotification’s title. - text
- A
Textmessage with its arguments:text!("id", name = value, ..)isText::message("id").arg("name", value)...
Structs§
- Abilities
- A policy that answers each
Abilityfrom the check declared for it, and denies every ability it declares none for. - Allow
- Allows every ability.
- And
- The policy
andreturns: allows what both sides allow. - Auth
- The panel’s authentication configuration (ADR-0013).
- Auth
Mail - Where a panel’s auth mail comes from and where its links point, installed with
Auth::mail: the sender, and the absolute URL every link starts with. - Boolean
Column - A column of a
boolfield rendered as an icon. - Brand
- Branding for the panel’s shell: the sidebar header, the login card, and the
topbar below
md, where the sidebar folds into a sheet. - Choice
Field - A choice field:
Field::choice, or a record form’s choice control (Fis the form). - Color
Column - A column of a
Stringfield holding a CSS color, rendered as a swatch beside the value. - Computed
Column - A display-only column rendering any text from the row, with no query predicate.
- Count
Column - A column counting the records of a
Deferredhas_manyfield that a sourceSshows, which declares the field’s include so every page that renders it loads the records. - Currency
- How a money column spells its amounts: the symbol, where it goes, the decimals, and whether the field stores minor units.
- Custom
Field - A field an app’s
Controlrenders:Field::customandField::toggle, or a record form’s toggle (Fis the form). - Date
Column - A column of a date field, rendered as a calendar day.
- Date
Filter - Date filter matching a date or time field by calendar day, or by a range of days; see
FilterDatefor the types. - Declaration
Error - One declaration mistake: who declares it, where, and what is wrong.
- Deny
- Allows nothing: the default policy.
- Detail
- The declaration of a detail page:
Columns, the same ones aTablelists, arranged inSection,Group,GridandTabsblocks. - DirUploader
- Writes each upload into one directory as
{uuid}-{basename}and stores its URL underurl_prefix;Panel::uploads_dirinstalls it and serves the directory there. - Email
Verification - A panel’s email verification, installed with
Auth::email_verification: theEmailVerifier, and how many links one account may ask for. The links go out through the panel’sAuthMail. - Embedded
Column - A column of an
EmbeddedFormvalue. - Field
- One form field binding a lens to the control editing it, offering only that control’s modifiers so a modifier on the wrong control does not compile.
- Field
Access - Who may view one field of a model’s records, and who may change it, which
ResourceDef::field_accessdeclares: every resource the panel mounts over the model obeys the rule. - Field
Error - One key a submission was refused under: a form key, or a record form’s
field enum in
Resource::validate_record. - Field
Errors - A refused submission.
- File
Column - A column of a
Stringfield holding an uploaded file’s path, rendered as a link to the file. - File
Field - A file field:
Field::file, or a record form’s file control (Fis the form). - Filter
Value - What a request carries for one filter: the values its
f.<name>parameter repeats, in the order the request carries them, and the parts itsf.<name>.<part>parameters name. - Form
Field - One record-form field and the form keys it binds.
- Form
Values - What a form holds, one
FormValueper key: a submission its schema read, or a stored record as its record form spells it. - Global
Search - How a resource’s records show in its panel’s global search, as
ResourceDef::global_searchdeclares it: the details listed under each result’s title. - Grid
- A block of
colscolumns, clamped to 1..12, laying out a form’s fields or a detail page’s columns. - Group
- An unlabelled block grouping a form’s fields or a detail page’s columns.
- Header
Actions - The
HeaderActions a page or a resource declares, in button order. - Image
Column - A column of a
Stringfield holding an uploaded image’s path, rendered as a thumbnail. - Lens
- A model field’s typed path, which queries filter and sort on, paired with the function that reads the field off a loaded record.
- Login
Throttle - How many sign-in attempts one login may make from one client address in a window, as
Auth::throttlesets it. - Membership
- One tenant a user may act for: its id, and the name the tenant switcher
shows. A
PanelUserlists its memberships intenants. - Mount
Error - Why
RouterBuilderPanelExt::panelrefused a panel: every declaration mistake it found. - Navigation
Item - A sidebar entry: a resource’s, from its
ResourceDef, or aPage’s. - NoForm
- The record form of a resource with no create or edit page.
- Notification
- A message for a panel user: flashed as a toast after a write, or stored for the bell with
Notifications::send. - Notification
Action - A link a
Notificationoffers under its text, such as “Download” or “View order”. - Notifications
- Sends
StoredNotifications to one panel’s users, and wakes their open bells. Cloning it is cheap. - Or
- The policy
orreturns: allows what either side allows. - Outcome
- What an
Actionor aHeaderActionasks of the response once its write commits: which notification it flashes and where it lands. - PageDef
- What a
Pagedeclares: its slug, sidebar entry, access and header actions. - Page
Position - Where a page numbered by
?page=sits in its result set. - Panel
- An admin panel: resources and pages under one prefix, framed by one shell
and gated by one
Auth. - Panel
Handle - A panel’s mounted resources and its database, which a background job or a test keeps to build
a context per run without declaring the panel again. A router’s mounted panel gives it through
panel_handle, a panel no router mounts throughPanel::handle. Cloning it is cheap. - Password
Auth - Shipped default authenticator: Argon2id verification against
AdminUser. - Password
Reset - A panel’s password reset, installed with
Auth::password_reset: thePasswordResetter, and how many links one address may ask for. The links go out through the panel’sAuthMail. - Password
Sign Up - Registers an
AdminUserfrom aSignUp, refusing a passwordnew_password_errorsrefuses and an email another account holds. Install it withAuth::registration. - Places
- Where an
Action’s button renders:Action::PLACES. - Posted
- An edit submission: the parsed form, and the fields the submission named.
- Profile
- The profile form
PasswordAuthedits anAdminUserthrough, and a customProfileEditorcan take as its input: a name, an email address, an optional new password typed twice, and the current password. - Public
Link - A record’s public page, linked from its detail and edit pages.
- Query
Filter - A filter offering named predicates, such as an embedded-enum variant or any query the app
names. Several values match a record any of their predicates selects, which
multiplelets the control choose. - Read
Only - Allows listing and viewing, and no write: no create, update, delete or custom action.
- Reads
- The fields of
MaColumnor aFilterreads, by the root field each path starts at: whatfield_accesshides it by. - Relation
- One relation of a parent resource’s records.
- Relation
Column - A column showing the record of a
Deferredbelongs_toorhas_onefield as text, or the records of ahas_manyone (list), which declares the field’s include so every page that renders it loads them. - Relation
Lens - A relation field’s include, which loads it, paired with the function that reads the loaded relation off a record.
- Repeater
Column - A column of a list of
FormInputitems. - Repeater
Field - A repeater:
Field::repeater, or a record form’s#[form(repeat)]control (Fis the form). - Resource
Def - What a
Resourcedeclares: its names, navigation, policy, tenancy, table, form, detail page, relations and actions. - Rich
Text Column - A column of a
Stringfield holding a rich text field’s HTML. A detail page shows the formatted HTML; a table cell shows its text, cut toexcerptcharacters; an export holds the text. - Rich
Text Field - A rich text field:
Field::rich_text, or a record form’s text control made one withTextField::rich_text(Fis the form). - Schema
- Composes fields and layout blocks and resolves every field once into one list.
- Section
- A titled block holding a form’s fields (
schema) or a detail page’s columns (columns, whichdetaildeclares). - Select
Filter - Select filter matching a field exactly: a
String, anyFormScalarsuch as anOptionsenum, or a foreign key to arelationship’s rows. Several values match a record holding any of them, whichmultiplelets the control choose. - SignUp
- The sign-up form
PasswordSignUpregisters from, and a customRegistrarcan take as its input: a name, an email address, and a new password typed twice. - Sort
- A column and a direction to sort a table by: parsed from
?sort=<column>&dir=asc|desc, or declared as the table’s default. - Source
- Holds the values and errors a schema’s controls render with.
- Switch
- Renders a
boolfield as a switch, a checkbox with theswitchrole drawn as an on/off track, preceded by a hiddenfalse: whatCustomField::switchrenders. - Tab
- One tab of a
Tabsblock: a titled trigger and the fields or columns it shows. - Table
- Table description of a
Resource’s list view declaring columns and how they map to queries. - Table
Page - One executed page of rows for
WiredTable::render. - Table
State - Request-scoped table state, parsed from the list’s URL query.
- Tabs
- A block showing one
Tabat a time, each holding a form’s fields (Tab::schema) or a detail page’s columns (Tab::columns). - Tenancy
- How a resource’s rows belong to a tenant.
- Tenant
- Request-scoped tenant identifier.
- Tenant
Id - One tenant’s id, and the field type of a resource’s tenant column.
- Tenant
Registration - A panel’s tenant registration page, installed with
Auth::tenant_registration: theTenantRegistrarthat creates tenants, and whether a user who acts for none must create one first. - Ternary
Filter - Ternary filter matching a
boolfield. - Text
- A word a panel renders: plain text, or a message the request’s
Localespells. - Text
Column - A column of one field, rendered as text and bound through a
Lensfor sorting and search. - Text
Field - A text field:
Field::text, or a record form’s text control (Fis the form). - Toggle
- Renders a
boolfield as a checkbox preceded by a hiddenfalse. - TwoFactor
- A panel’s two-factor sign-in, installed with
Auth::two_factor: each signed-in user may add an authenticator app, or codes by email when the panel mails them, at{prefix}/two-factor, and an account that has one signs in with a code from it after its password. - When
- The policy
whenreturns. - Wired
Table - A declared
Tablewith one request’s actions and policy wired on: what the list page renders.
Enums§
- Ability
- One thing a policy is asked to allow; record abilities are asked once per loaded row, and a record that cannot be viewed cannot be written by guessing its key.
- Action
Input Fault - Why an action’s input cannot be served:
DeclarationErrorKind::ActionInput. - Action
Layout - Where a table puts a row’s actions: its custom actions, View, Edit and Delete.
- Alignment
- Where a column’s header and cells align their content.
- Auth
Mail Fault - Why a panel’s auth mail cannot be sent:
DeclarationErrorKind::AuthMail. - Change
- What one write of a resource changed: the mutation and the rows it wrote.
- Color
- A semantic color for a badge, a status dot or a cell’s text.
- Column
Toggle - Whether each reader may hide a
Columnfrom their list, and whether it starts shown. - Column
Width - How a
Columntakes the table’s width. - Cursor
- A pagination cursor: the page after, or the page before, an encoded row.
- Declaration
Error Kind - What is wrong with a declaration.
- Field
Access Fault - Why a
field_accesscannot hide its field everywhere the panel shows it:DeclarationErrorKind::FieldAccess. - Field
Error Kind - Why a key was refused.
- Field
Rule Fault - Why a field’s declared rules cannot work:
DeclarationErrorKind::FieldRule. - Form
Value - One key’s value in
FormValues, in the shape its control posts. - Locale
Fault - Why a panel’s
localesortranslationscannot be served. - Many
ToMany Fault - Why a many-to-many field or relation cannot link records:
DeclarationErrorKind::ManyToMany. - NavTarget
- Where a sidebar entry points.
- Notification
Status - The kind of notification (status).
- Number
- A number as a cell reads it: an integer stays exact, a float is rounded when spelled.
- Pagination
- How a table pages through its rows.
- Profile
Fault - Why a panel’s profile page cannot be served:
DeclarationErrorKind::Profile. - Profile
Update - What a
ProfileEditor::savechanged, which decides what happens to the user’s sessions. - Reset
Fault - Why a panel’s password reset cannot be served:
DeclarationErrorKind::PasswordReset. - Segment
Fault - Why a path segment cannot be a literal URL segment.
- Sign
UpFault - Why a panel’s sign-up page cannot be served:
DeclarationErrorKind::SignUp. - Site
- The part of a declaration a
DeclarationErroris in. - Tenancy
Fault - Why a resource’s tenancy cannot scope its rows:
DeclarationErrorKind::Tenancy. - Tenant
Profile Fault - Why a panel’s tenant settings page cannot be served:
DeclarationErrorKind::TenantProfile. - Tenant
Registration Fault - Why a panel’s tenant registration page cannot be served:
DeclarationErrorKind::TenantRegistration. - Tool
- One button of a rich text field’s toolbar. A tool is also a grant: the field keeps only the elements and attributes its tools produce, so a tool left off the toolbar cannot be typed, is dropped from a paste, and is removed from a forged post.
- Trashed
- Which records a query over a soft-deleting resource admits: the live ones, the trashed ones, or both.
- TwoFactor
Fault - Why the panel’s two-factor sign-in cannot be served:
DeclarationErrorKind::TwoFactor. - Verification
Fault - Why a panel’s email verification cannot be served:
DeclarationErrorKind::EmailVerification. - Write
Error - Why a record fn or an action’s run wrote nothing: a refusal the form renders, or a failure.
Constants§
- DEFAULT_
PAGE_ SIZE - The page size of a table that declares none with
Table::paginate. - DEFAULT_
PER_ PAGE_ OPTIONS - The page sizes a table offers a reader by default, beside its own
Table::paginatesize. - MAX_
IMPORT_ ROWS - The most rows one CSV import creates: every row writes in the request’s one transaction, so a longer file is refused whole.
- MAX_
RELATIONSHIP_ OPTIONS - Caps the options a relationship choice field loads instead of scanning a large table per select.
- MAX_
REPEATER_ ROWS - The most rows one repeater takes: each renders in full when the form comes back refused, so an unbounded list would let a small submission render a page of any size.
Traits§
- Action
- A mutation beyond create, update and delete: “publish”, “archive”, “resend the invite”.
- Authenticator
- How a panel loads its users (ADR-0013).
- Date
Value - The field types a
DateColumnspells as a calendar day:jiff::civil::Date,jiff::civil::DateTime,jiff::Timestamp(read in the request’stime_zone, as aDateFilterreads it) and anOptionof any of them. - Embedded
Form - Reads an embedded value from and writes it to
FormValues, one key per leaf; derive it to generate the value’s schema. - Foreign
Key - A foreign-key column type referencing a primary key of type
K:Kitself, orOption<K>for an optional reference. Sealed: these are the only two. - Form
Input - A typed value a form posts under its own keys, which no column binds: what an
Actionasks for before it runs, what a sign-up reads, one item of a repeater. - Form
Scalar - A type one form key reads and writes:
String, everyTypedValuetype, every enum derivingOptions, and anOptionof any of them. - Header
Action - A mutation that acts on no record, run from a button in a page’s header: “import posts”, “clear the cache”, “recompute the totals”.
- Into
Columns - Convert a single built-in column, a tuple of any
Columns, aVecor slice of boxed columns, or()for none yet, into a table’s column list. - Into
Detail - Converts a column, a layout block of columns, a tuple of either, or a
Detailinto aDetail. - Into
Filters - Convert a single built-in filter, or a tuple of any
Filters, into a table’s filter list. - Into
Form Value - A value a field’s
defaulttakes: anyFormScalaror a&stror&Stringin the form spelling, or an array orVecof them for a multiple choice. - Into
Options - A choice’s static options as
(value, label)pairs, in display order. A value listed alone is its own label; a label is aText, so a message translates it. - Into
Schema - Converts a field, a layout block, a tuple of either, or a schema into a
Schema. - Model
Columns - The table and detail page a model reads as when its resource declares none: what a
ResourceDefwithout atablelists and without adetailshows. - Numeric
- A field a
TextColumncan spell as a number or an amount of money: every integer and float type, and anOptionof one, which reads as the table’s dash whenNone. - Options
- A closed set of values, each with its label.
- Page
- A panel page that is not a resource, mounted at
{prefix}/{slug}with a sidebar entry; the panel owns the route and entry while the page owns its markup. - Panel
User - A signed-in user, as the panel knows it (ADR-0013).
- Policy
- Decides which
Abilitys the current user has over a resource’s records. - Profile
Editor - How a panel lets the signed-in user edit their own account on its profile page, installed
with
Auth::profile. - Record
Form - The typed value a resource’s form submission parses into.
- Registrar
- How a panel creates accounts from its sign-up page, installed with
Auth::registration. - Resource
- Maps one Toasty
Modelto its admin UI. - Router
Builder Panel Ext - Mounts a
Panelon a router the app owns. - Tenant
Column - A field type a tenancy names:
TenantId, orOption<TenantId>for a nullable column. - ToOne
Relation - A to-one relation field to
TaRelationColumnreads:Deferred<T>, orDeferred<Option<T>>for a nullable relation. - Uploader
- Stores one uploaded file and names the value a record stores; installed once
per panel with
Panel::uploads. - Watched
- A field a condition can watch: a text, choice or custom field of the form
F, passed tovisible_whenby reference.
Functions§
- can
- Whether
R’s policy, as the context’s panel mounted it, allowsability;falsewhen the panel does not mountR. Does not check sign-in or tenant scope. - can_
list - Whether the current request may open
R’s list: the request’s panel mountsR, and sign-in, tenant scope, andAbility::ViewAnyallow it. - can_
open - Whether the current request may open the page
P: the request’s panel mountsP, and sign-in andPageDef::accessallow it, the checks the page’sGETmakes. - contains_
expr - Escaped substring predicate for
lensmatchingterm. - header_
action_ buttons - The header buttons of the page
Pthe request may run, for itspage_actions: - navigation_
item R’s sidebar entry in the context’s panel, with its label, URL and icon;Nonewhen the panel does not registerR.- parse_
items - The items the repeater
keyholds in a submission read through its schema, none when it posts nothing: what a record form’s parse reads the repeater with, and what a hand-written one or an action input reads. - parse_
list - Read the values a multiple choice posted, none when it posted nothing: what a record form’s parse reads a many-to-many field with.
- parse_
password - Read a password from a completed submission: required as
parse_scalarreads aString, but kept as typed, with its outer spaces, since a login compares the password untrimmed. - parse_
scalar - Read one scalar from a completed submission.
- register_
models - Register every model Tablo ships in
models:AdminUser,AuthSession,ColumnPreference,AuthToken,AuthFactorandStoredNotification. - require_
tenant - Requires a tenant, returning an error if missing (for tenant-owned resources).
- sanitize_
filename - Strips a client filename to a safe basename capped at 255 bytes, without control or
bidirectional-override characters, rejecting
.,.., and Windows reserved names to empty: what a file field’sUploaderreceives, for a page that parses its own multipart body. - scoped_
query - The tenant-scoped base query.
- scoped_
query_ in scoped_queryadmitting the recordstrashednames, as a restore or a trash list loads them, under the same tenant filter.- tenant_
id - The tenant the request acts for, if any.
- time_
zone - The time zone the request reads and shows wall-clock times in: the signed-in user’s
time_zone, else the request panel’stime_zone, else UTC. - when
- Allows every ability while
predicateholds for the request. - wired_
table - Returns the panel’s list table for
R, with the request’s row actions wired on, for a page that owns its table; render it over the page’s own query withWiredTable::render. - write_
create - The derived create: the form’s builder, the request tenant stamped on the
resource’s
Tenancy::column, executed throughex, then a join row linking the record to each record its many-to-many fields hold. - write_
items - The repeater’s value holding
items: what a record form hydrates the repeater with, and what a hand-written one writes. - write_
list - The values a multiple choice holds, as its one form key carries them: what a record form hydrates a many-to-many field with, and what a hand-written one writes.
- write_
update - The derived update: assign every named field and execute through
ex, then link the record to the records each named many-to-many field holds, and unlink it from the others.
Derive Macros§
- Embedded
Form - Derives
EmbeddedFormfor an embedded struct or enum. - Form
Input - Derives
FormInputfor a typed value a form posts under its own keys: what anActionasks for before it runs, what a sign-up reads, or one item of a repeater. - Model
Columns - Derive a model’s
ModelColumns: the table a resource lists it in and the detail page it shows it on, when the resource declares neither. - Model
Form - Derive a model’s
RecordFormstruct from the model: the fields a person fills, named and typed as the model declares them. - Options
- Derive
Optionsfor a unit-variant enum: the(value, label)list a choice field, a select filter and a column share, and theFormScalarthat posts a variant as its value and reads it as its label. - Record
Form - Derive
RecordFormfor the typed value a resource’s form writes.