Skip to main content

tablo_core/
lib.rs

1//! Tablo: a server-rendered admin toolkit on [Topcoat](topcoat) and [Toasty](toasty).
2//!
3//! A [`Panel`] serves one [`Resource`] per Toasty model. A resource names the model, whose
4//! [`ModelColumns`](derive@ModelColumns) give its default table and detail page, and the record
5//! form its create and edit submissions parse into, which [`ModelForm`](derive@ModelForm) derives
6//! from the model or [`RecordForm`](derive@RecordForm) from a struct of its own. It declares the
7//! rest as one [`ResourceDef`] value: its [`Policy`], which denies by default, and any [`Table`],
8//! [`Schema`] or [`Detail`] that replaces or extends the defaults.
9//! The app mounts the panel on its own Topcoat router with [`RouterBuilderPanelExt::panel`], which
10//! builds each def once and checks it against the database schema first; one router mounts any
11//! number of panels at distinct prefixes.
12//!
13//! ```rust,no_run
14//! # use tablo_core::{Allow, Panel, Resource, ResourceDef, RouterBuilderPanelExt};
15//! # use toasty::Db;
16//! # use topcoat::router::{Router, RouterBuilderDiscoverExt};
17//! # fn main() -> topcoat::Result<()> {
18//! #[derive(Debug, Clone, toasty::Model, tablo_core::ModelColumns, tablo_core::ModelForm)]
19//! pub struct Book {
20//!     #[key]
21//!     #[auto]
22//!     pub id: uuid::Uuid,
23//!     pub title: String,
24//! }
25//!
26//! pub struct BookResource;
27//!
28//! impl Resource for BookResource {
29//!     type Model = Book;
30//!     type Form = BookForm;
31//!
32//!     fn declare() -> ResourceDef<Self> {
33//!         ResourceDef::new().policy(Allow)
34//!     }
35//! }
36//!
37//! # let db: Db = todo!();
38//! let router = Router::builder()
39//!     .discover()
40//!     .with(db)
41//!     .panel(Panel::new("admin").resource::<BookResource>())?
42//!     .build();
43//! # let _ = router;
44//! # Ok(())
45//! # }
46//! ```
47//!
48//! The [user guide](https://y-l.fr/tablo/nightly/guide/) walks through a complete panel and each
49//! part of it. [`ResourceDef`] lists everything a resource declares, [`Resource`] the hooks it
50//! overrides, and [`Panel`] every builder call.
51
52// The derives emit `tablo_core::` paths; this lets them expand inside this
53// crate's own tests too.
54extern crate self as tablo_core;
55
56#[doc(hidden)]
57pub mod __macro {
58    pub use toasty::{
59        Executor, Result as DbResult,
60        codegen_support::Version,
61        schema::{Embed, Model},
62        stmt,
63        stmt::{List, Path},
64    };
65    pub use topcoat::{context::Cx, icon::IconData};
66
67    pub use crate::{
68        Color, Lens, Text,
69        detail::Detail,
70        extend::{Includes, OptionSource},
71        form::{
72            FieldError, FormField, FormInput, FormScalar, FormValues, NullableScalar, RecordForm,
73            assert_form_scalar, links_include, links_key, parse_list, parse_password, parse_scalar,
74            required_input, write_links,
75        },
76        i18n::option_label,
77        schema::{
78            ChoiceField, CustomField, EmbeddedForm, Field, FileField, HoldsTabs, IntoSchema,
79            Options, RepeaterField, Schema, TextField,
80            embedded::{Embedded, EmbeddedBuilder, embedded_field, take_leaf, take_value},
81            form_key, parse_items,
82            tree::Retype,
83            write_items,
84        },
85        table::{
86            ModelColumns, Table,
87            model::{Reference, pick},
88        },
89        toasty_compat::VariantId,
90        values::write_list,
91    };
92}
93// Each public item has one path. Types live at the root; a public module is a namespace for
94// the functions and constants that read best qualified (`auth::user`, `csrf::verify`).
95mod audit;
96pub mod auth;
97mod bus;
98mod chart;
99mod column;
100mod cookie;
101pub mod csrf;
102pub mod db;
103mod declaration;
104mod derive;
105mod detail;
106mod display;
107#[doc(hidden)]
108pub mod dom;
109mod error;
110pub mod extend;
111mod flash;
112mod form;
113mod i18n;
114mod lens;
115mod limits;
116mod models;
117mod naming;
118mod navigation;
119pub mod notification;
120mod outcome;
121mod page;
122mod panel;
123mod policy;
124mod resource;
125#[cfg(feature = "rich-text")]
126pub mod rich_text;
127mod schema;
128mod table;
129mod tenancy;
130#[cfg(test)]
131mod test_support;
132mod toasty_compat;
133mod topcoat_compat;
134mod upload;
135mod values;
136mod widget;
137
138/// The future a type-erased, dyn-compatible method returns.
139pub(crate) type BoxFuture<'a, T> = std::pin::Pin<Box<dyn Future<Output = T> + Send + 'a>>;
140
141pub use audit::{AuditChange, AuditEntry, AuditEvent};
142pub use auth::{
143    config::Auth,
144    external::ExternalAuth,
145    impersonation::Impersonation,
146    mail::AuthMail,
147    panel_user::{Authenticator, PanelUser},
148    password::{PasswordAuth, PasswordSignUp},
149    password_reset::PasswordReset,
150    profile::{Profile, ProfileEditor, ProfileUpdate},
151    registration::{Registrar, SignUp},
152    tenant_registration::TenantRegistration,
153    throttle::LoginThrottle,
154    two_factor::TwoFactor,
155    verification::EmailVerification,
156};
157pub use chart::{Chart, Series, chart};
158#[cfg(feature = "rich-text")]
159pub use column::RichTextColumn;
160pub use column::{
161    BooleanColumn, ColorColumn, ColumnToggle, ColumnWidth, ComputedColumn, CountColumn, DateColumn,
162    DateValue, EmbeddedColumn, FileColumn, IconColumn, ImageColumn, IntoColumns, ListColumn,
163    RelationColumn, RelationLens, RepeaterColumn, SelectColumn, TextColumn, TextInputColumn,
164    ToOneRelation, ToggleColumn, contains_expr,
165};
166pub use declaration::{
167    ActionInputFault, AreaFault, AuthMailFault, DeclarationError, DeclarationErrorKind,
168    EditableColumnFault, FieldAccessFault, FieldRuleFault, LocaleFault, ManyToManyFault,
169    MountError, PolicyFault, ProfileFault, RelatedFormFault, ResetFault, SegmentFault, SignUpFault,
170    Site, TenancyFault, TenantProfileFault, TenantRegistrationFault, TwoFactorFault,
171    VerificationFault,
172};
173pub use derive::{EmbeddedForm, FormInput, ModelColumns, ModelForm, Options, RecordForm};
174pub use detail::{Detail, IntoDetail};
175pub use display::{Alignment, Color, Currency, FontWeight, Number, Numeric};
176pub use form::{NoForm, Posted, RecordForm};
177pub use i18n::Text;
178pub use lens::{Lens, Reads};
179pub use limits::Limits;
180pub use models::register_models;
181pub use navigation::{NavTarget, NavigationItem};
182pub use notification::stored::Notifications;
183pub use outcome::{Notification, NotificationAction, NotificationStatus, Outcome};
184pub use page::{Page, PageDef, PageFilter, PageFilters};
185pub use panel::{
186    Area, AreaGroup, AuditLog, Brand, ChangedField, ChangedRecord, CommitHook, Environment,
187    Impersonate, Panel, PanelChange, PanelHandle, Radius, RouterBuilderPanelExt, WiredTable,
188    can_list, can_open, can_view_field, list_query, navigation_item, page_filter_bar, page_filters,
189    pages::header_action_buttons, record_table, stats, url, widgets, wired_table,
190};
191pub use policy::{Abilities, Ability, Allow, And, Deny, Or, Policy, ReadOnly, When, when};
192pub use resource::{
193    Action, Change, FieldAccess, ForeignKey, GlobalSearch, HeaderAction, HeaderActions, Places,
194    PublicLink, RecordPage, RecordPageDef, Relation, Resource, ResourceDef, ResourcePage, Trashed,
195    WriteError, can, filter_keys, scoped_query, scoped_query_in, write_create, write_delete,
196    write_force_delete, write_restore, write_update,
197};
198#[cfg(feature = "rich-text")]
199pub use rich_text::tool::Tool;
200#[cfg(feature = "rich-text")]
201pub use schema::RichTextField;
202pub use schema::{
203    ChoiceField, CustomField, EmbeddedForm, Field, FileField, Grid, Group, IntoFormValue,
204    IntoOptions, IntoSchema, MAX_RELATIONSHIP_OPTIONS, MAX_REPEATER_ROWS, Options, RepeaterField,
205    Schema, Section, Source, Step, Switch, Tab, Tabs, TextField, Toggle, Watched, Wizard,
206    input::FormInput, parse_items, write_items,
207};
208pub use table::{
209    ActionLayout, Cursor, DEFAULT_PAGE_SIZE, DEFAULT_PER_PAGE_OPTIONS, DateFilter, FilterValue,
210    IntoFilters, ListTab, ModelColumns, NumberFilter, PagePosition, Pagination, PresenceFilter,
211    QueryFilter, RowLink, SelectFilter, Sort, Summary, Table, TablePage, TableState, TernaryFilter,
212    TextFilter, TextMatch,
213};
214pub use tenancy::{
215    ClaimedTenant, Membership, Tenancy, Tenant, TenantColumn, TenantId, require_tenant, tenant_id,
216};
217pub use upload::{DirUploader, Uploader, sanitize_filename};
218pub use values::{
219    FieldError, FieldErrorKind, FieldErrors, FormField, FormScalar, FormValue, FormValues,
220    parse_list, parse_password, parse_scalar, time_zone, write_list,
221};
222pub use widget::{
223    DEFAULT_RECORD_ROWS, MAX_RECORD_ROWS, RecordTable, Stat, Trend, Widget, WidgetDef,
224};