pub struct AdminPlugin { /* private fields */ }Implementations§
Source§impl AdminPlugin
impl AdminPlugin
Sourcepub fn register(self, model: AdminModel) -> Self
pub fn register(self, model: AdminModel) -> Self
Register an AdminModel for one model. Chainable.
If two configs are registered for the same table the last one wins (a duplicate registration overwrites the earlier one).
The plugin name defaults to "admin" for models registered before
the plugin is installed into the app. From M7+ plugins will pass
their own name via Plugin::admin_register on the registry.
Sourcepub fn register_many(self, models: impl IntoIterator<Item = AdminModel>) -> Self
pub fn register_many(self, models: impl IntoIterator<Item = AdminModel>) -> Self
Register many AdminModels at once — the batch form of
register. Lets each plugin export a
Vec<AdminModel> (its admin surface, declared next to its models)
and the app register them in one call instead of a .register(...)
per model in main.rs.
// plugins/blog/src/lib.rs
pub fn admin_models() -> Vec<umbral_admin::AdminModel> {
vec![post_admin(), comment_admin(), tag_admin()]
}
// main.rs
AdminPlugin::default().register_many(blog::admin_models())Sourcepub fn register_for(self, plugin_name: &str, model: AdminModel) -> Self
pub fn register_for(self, plugin_name: &str, model: AdminModel) -> Self
Register an AdminModel for a specific plugin name.
This is the method the Plugin::routes / on_ready pathway uses
when a plugin contributes its own admin registrations. The sidebar
groups models by the plugin_name supplied here.
Sourcepub fn register_for_many(
self,
plugin_name: &str,
models: impl IntoIterator<Item = AdminModel>,
) -> Self
pub fn register_for_many( self, plugin_name: &str, models: impl IntoIterator<Item = AdminModel>, ) -> Self
Batch form of register_for — register many
models under one plugin name (the Plugin-pathway batch entry).
Sourcepub fn register_widget(self, widget: Widget) -> Self
pub fn register_widget(self, widget: Widget) -> Self
Register a dashboard widget. Chainable.
§Example
use umbral_admin::{AdminPlugin, Widget, WidgetKind, WidgetDataFn, WidgetPayload, KpiPayload, Span};
AdminPlugin::default()
.register_widget(Widget {
key: "total_posts",
title: "Total Posts".to_string(),
kind: WidgetKind::Kpi,
default_span: Span { cols: 3, rows: 1 },
permission: None,
data: WidgetDataFn::new(|_user| async move {
WidgetPayload::Kpi(KpiPayload {
value: "0".to_string(),
unit: None, delta: None, sparkline: None,
})
}),
});Sourcepub fn site_title(self, title: impl Into<String>) -> Self
pub fn site_title(self, title: impl Into<String>) -> Self
Override the admin site title — shown in the browser tab, the sidebar header, and the login page.
AdminPlugin::default().site_title("Acme Backoffice")Sourcepub fn site_description(self, description: impl Into<String>) -> Self
pub fn site_description(self, description: impl Into<String>) -> Self
One-line description shown on the dashboard / login page underneath the site title.
pub fn show_version(self, show: bool) -> Self
Sourcepub fn version(self, label: impl Into<String>) -> Self
pub fn version(self, label: impl Into<String>) -> Self
Show YOUR version instead of umbral’s (gaps3 #67).
AdminPlugin::default().version(concat!("MyShop v", env!("CARGO_PKG_VERSION")))The default advertises the framework — which is what the operator of a shop
almost certainly does NOT want on their staff login page. Whose version an admin
shows is a product decision, so it is yours to make. Implies show_version(true).
Prefer env!("CARGO_PKG_VERSION") over a literal: a hardcoded version is a lie
waiting for the next release, which is exactly how the admin came to claim
v0.0.1 five releases after it stopped being true.
Sourcepub fn brand_color(self, color: impl Into<String>) -> Self
pub fn brand_color(self, color: impl Into<String>) -> Self
Override the brand primary color. Accepts any valid CSS color
(#5b5bd6, rgb(91 91 214), hsl(240 60% 60%)). The wrapper
template emits a <style> that re-assigns --primary and
--primary-container so every “primary”-tinted element across
the admin picks it up automatically.
Sourcepub fn at(self, path: impl Into<String>) -> Self
pub fn at(self, path: impl Into<String>) -> Self
Gap 107: mount the admin at a path other than the default
/admin. Useful when a single domain hosts multiple umbral
admins, or when the operations team enforces a different
vanity URL. Accepts "/myadmin", "myadmin", or
"/myadmin/" — all normalise to "/myadmin".
AdminPlugin::default().at("/backoffice")
// → routes mount at /backoffice/login, /backoffice/{table}/, ...Templates read the configured base via the admin_base
Jinja global, so cross-page links resolve to the new path
automatically. Handler-side redirects and sanitise_next
also use the configured base.
Sourcepub fn base_path(&self) -> &str
pub fn base_path(&self) -> &str
The normalised admin base path. Public so plugin authors and the OpenAPI plugin can reference it.
Hide the dashboard’s “Models” cards section entirely. Use when the operator’s primary view is widget-driven and a long model grid would be noise (200-model enterprise installs, single-purpose admins, etc.).
AdminPlugin::default().dashboard_models_hidden()Sourcepub fn dashboard_models_only<S: Into<String> + Clone>(
self,
tables: &[S],
) -> Self
pub fn dashboard_models_only<S: Into<String> + Clone>( self, tables: &[S], ) -> Self
Show only a curated subset of models on the dashboard, in the given order. Unknown table names are dropped silently (typo-safe — if one plugin is unregistered the rest still render).
AdminPlugin::default().dashboard_models_only(&[
"product", "order", "customer",
])Type-safe alternative coming in a follow-up: a
models![Product, Order, Customer] macro that resolves
each type to its Model::TABLE so a rename in the
struct doesn’t require updating string references here.
Sourcepub fn dashboard_models_all(self) -> Self
pub fn dashboard_models_all(self) -> Self
Explicit reset to the default — show every registered model. Useful when a wrapper builder has previously configured a subset / hidden and you want the full grid back.
Sourcepub fn dashboard_section(self, section: WidgetSection) -> Self
pub fn dashboard_section(self, section: WidgetSection) -> Self
Append a named widget section to the dashboard. Sections render in registration order, each with its own heading
- (optional) subtitle + widget grid:
AdminPlugin::default()
.dashboard_section(
WidgetSection::new("Sales overview")
.subtitle("Daily KPIs across the storefront")
.widget(shop_total_sales_widget())
.widget(shop_orders_widget()))
.dashboard_section(
WidgetSection::new("Engagement")
.widget(umbral_admin::builtin_recent_users_widget()))Widgets registered via the legacy register_widget(...)
land in an implicit final section titled “Widgets” so
pre-existing apps keep working without refactor.
Sourcepub fn dashboard_section_at(self, index: usize, section: WidgetSection) -> Self
pub fn dashboard_section_at(self, index: usize, section: WidgetSection) -> Self
Insert a section at a specific position in the dashboard.
Useful when a wrapper builder appended sections earlier
and you want a new one above them. index is clamped at
the current section count, so usize::MAX is equivalent
to Self::dashboard_section.
AdminPlugin::default()
.dashboard_section(sales_section)
.dashboard_section(system_section)
// Slot a new section between the two:
.dashboard_section_at(1, alerts_section)Sourcepub fn dashboard_models_title(self, title: impl Into<String>) -> Self
pub fn dashboard_models_title(self, title: impl Into<String>) -> Self
Override the heading shown above the model-cards section.
Default “Models”. Pair with dashboard_models_subtitle
for a one-line explainer.
Sourcepub fn dashboard_models_subtitle(self, subtitle: impl Into<String>) -> Self
pub fn dashboard_models_subtitle(self, subtitle: impl Into<String>) -> Self
Optional one-line caption under the model-cards heading.
Sourcepub fn restore_last_path(self, enabled: bool) -> Self
pub fn restore_last_path(self, enabled: bool) -> Self
Control whether the admin “restore where I left off” feature is
active (default: true — on by default, opt out to disable).
When enabled (true, the default):
/admin/302-redirects to the last-visited changelist URL stored inadmin_user_pref.preferences.last_path.- The changelist handler writes
last_pathon every page visit. - The “Home” breadcrumb carries
?dashboard=1so the dashboard is reachable in one click (the escape hatch becomes a UI affordance).
When disabled (false):
/admin/always renders the dashboard directly.- The changelist handler skips the
last_pathwrite — no dead data accumulates inadmin_user_pref.preferences.
AdminPlugin::default().restore_last_path(false)Sourcepub fn view(self, view: AdminView) -> Self
pub fn view(self, view: AdminView) -> Self
Register a custom admin view — a widget page mounted at
{admin_base}/{view.path}. Chainable.
AdminPlugin::default().view(
AdminView::new("reports/sales", "Sales report")
.with_icon("bar-chart")
.section(WidgetSection::new("This month").widget(revenue_kpi())),
)Sourcepub fn views(self, views: impl IntoIterator<Item = AdminView>) -> Self
pub fn views(self, views: impl IntoIterator<Item = AdminView>) -> Self
Batch form of view.
Trait Implementations§
Source§impl Clone for AdminPlugin
impl Clone for AdminPlugin
Source§fn clone(&self) -> AdminPlugin
fn clone(&self) -> AdminPlugin
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for AdminPlugin
impl Debug for AdminPlugin
Source§impl Default for AdminPlugin
impl Default for AdminPlugin
Source§impl Plugin for AdminPlugin
impl Plugin for AdminPlugin
Source§fn name(&self) -> &'static str
fn name(&self) -> &'static str
migrations/. Plugin names live in the same namespace as
migrate::APP_PLUGIN_NAME ("app"), so user crates must not
pick the name "app".Source§fn dependencies(&self) -> &'static [&'static str]
fn dependencies(&self) -> &'static [&'static str]
App::builder() topological sort uses this; cycles surface as
BuildError::PluginCycle. The default is no dependencies.Source§fn static_files(&self) -> Vec<StaticFile>
fn static_files(&self) -> Vec<StaticFile>
Source§fn static_dirs(&self) -> Vec<StaticDir>
fn static_dirs(&self) -> Vec<StaticDir>
Source§fn models(&self) -> Vec<ModelMeta>
fn models(&self) -> Vec<ModelMeta>
makemigrations. Read moreSource§fn routes(&self) -> Router
fn routes(&self) -> Router
AppBuilder::routes(). Plugins
choose their own path prefixes (spec 02 §“What a plugin can
contribute”: routes are flat, not auto-prefixed).Source§fn route_paths(&self) -> Vec<RouteSpec>
fn route_paths(&self) -> Vec<RouteSpec>
routes used for surfacing route lists outside the request
flow (currently: the dev-mode default 404 page). axum doesn’t
expose its internal route table, so plugins report what they
declare here; the framework treats this as informational only
— not a source of truth for routing. Read moreSource§fn on_ready(&self, _ctx: &AppContext) -> Result<(), PluginError>
fn on_ready(&self, _ctx: &AppContext) -> Result<(), PluginError>
ctx.runtime() when the runtime handle lands.Source§fn openapi_paths(&self) -> Vec<(String, Value)>
fn openapi_paths(&self) -> Vec<(String, Value)>
Vec<(path, value)> where path is the URL template
(/api/auth/login, /api/foo/{id}) and value is the
matching OpenAPI 3.0 Path Item Object serialised as
a serde_json::Value. Read moreSource§fn system_checks(&self) -> Vec<SystemCheck>
fn system_checks(&self) -> Vec<SystemCheck>
App::build() alongside the framework’s built-in checks.
Severity::Error blocks boot; Severity::Warning logs and
continues.Source§fn provides_storage(&self) -> bool
fn provides_storage(&self) -> bool
true if this plugin registers a Storage
backend (e.g. StoragePlugin, which calls
crate::storage::set_storage in Plugin::on_ready). Read moreSource§fn database(&self) -> Option<&'static str>
fn database(&self) -> Option<&'static str>
None to use the
"default" pool (the same one umbral::db::pool() returns). Read moreSource§fn templates_dirs(&self) -> Vec<PathBuf>
fn templates_dirs(&self) -> Vec<PathBuf>
Source§fn template_registrars(
&self,
) -> Vec<Box<dyn Fn(&mut Environment<'static>) + Sync + Send>>
fn template_registrars( &self, ) -> Vec<Box<dyn Fn(&mut Environment<'static>) + Sync + Send>>
Source§fn wrap_router(&self, router: Router) -> Router
fn wrap_router(&self, router: Router) -> Router
Source§fn middleware(&self) -> Vec<Arc<dyn Middleware>>
fn middleware(&self) -> Vec<Arc<dyn Middleware>>
Source§fn static_root_dirs(&self) -> Vec<PathBuf>
fn static_root_dirs(&self) -> Vec<PathBuf>
static_url — with
no namespace segment. Read moreSource§fn commands(&self) -> Vec<Box<dyn PluginCommand>>
fn commands(&self) -> Vec<Box<dyn PluginCommand>>
Source§fn api_endpoints(&self) -> Vec<ApiEndpoint>
fn api_endpoints(&self) -> Vec<ApiEndpoint>
Auto Trait Implementations§
impl !RefUnwindSafe for AdminPlugin
impl !UnwindSafe for AdminPlugin
impl Freeze for AdminPlugin
impl Send for AdminPlugin
impl Sync for AdminPlugin
impl Unpin for AdminPlugin
impl UnsafeUnpin for AdminPlugin
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<A, B, T> HttpServerConnExec<A, B> for Twhere
B: Body,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> Paint for Twhere
T: ?Sized,
impl<T> Paint for Twhere
T: ?Sized,
Source§fn fg(&self, value: Color) -> Painted<&T>
fn fg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self with the foreground set to
value.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like red() and
green(), which have the same functionality but are
pithier.
§Example
Set foreground color to white using fg():
use yansi::{Paint, Color};
painted.fg(Color::White);Set foreground color to white using white().
use yansi::Paint;
painted.white();Source§fn bright_black(&self) -> Painted<&T>
fn bright_black(&self) -> Painted<&T>
Source§fn bright_red(&self) -> Painted<&T>
fn bright_red(&self) -> Painted<&T>
Source§fn bright_green(&self) -> Painted<&T>
fn bright_green(&self) -> Painted<&T>
Source§fn bright_yellow(&self) -> Painted<&T>
fn bright_yellow(&self) -> Painted<&T>
Source§fn bright_blue(&self) -> Painted<&T>
fn bright_blue(&self) -> Painted<&T>
Source§fn bright_magenta(&self) -> Painted<&T>
fn bright_magenta(&self) -> Painted<&T>
Source§fn bright_cyan(&self) -> Painted<&T>
fn bright_cyan(&self) -> Painted<&T>
Source§fn bright_white(&self) -> Painted<&T>
fn bright_white(&self) -> Painted<&T>
Source§fn bg(&self, value: Color) -> Painted<&T>
fn bg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self with the background set to
value.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like on_red() and
on_green(), which have the same functionality but
are pithier.
§Example
Set background color to red using fg():
use yansi::{Paint, Color};
painted.bg(Color::Red);Set background color to red using on_red().
use yansi::Paint;
painted.on_red();Source§fn on_primary(&self) -> Painted<&T>
fn on_primary(&self) -> Painted<&T>
Source§fn on_magenta(&self) -> Painted<&T>
fn on_magenta(&self) -> Painted<&T>
Source§fn on_bright_black(&self) -> Painted<&T>
fn on_bright_black(&self) -> Painted<&T>
Source§fn on_bright_red(&self) -> Painted<&T>
fn on_bright_red(&self) -> Painted<&T>
Source§fn on_bright_green(&self) -> Painted<&T>
fn on_bright_green(&self) -> Painted<&T>
Source§fn on_bright_yellow(&self) -> Painted<&T>
fn on_bright_yellow(&self) -> Painted<&T>
Source§fn on_bright_blue(&self) -> Painted<&T>
fn on_bright_blue(&self) -> Painted<&T>
Source§fn on_bright_magenta(&self) -> Painted<&T>
fn on_bright_magenta(&self) -> Painted<&T>
Source§fn on_bright_cyan(&self) -> Painted<&T>
fn on_bright_cyan(&self) -> Painted<&T>
Source§fn on_bright_white(&self) -> Painted<&T>
fn on_bright_white(&self) -> Painted<&T>
Source§fn attr(&self, value: Attribute) -> Painted<&T>
fn attr(&self, value: Attribute) -> Painted<&T>
Enables the styling Attribute value.
This method should be used rarely. Instead, prefer to use
attribute-specific builder methods like bold() and
underline(), which have the same functionality
but are pithier.
§Example
Make text bold using attr():
use yansi::{Paint, Attribute};
painted.attr(Attribute::Bold);Make text bold using using bold().
use yansi::Paint;
painted.bold();Source§fn rapid_blink(&self) -> Painted<&T>
fn rapid_blink(&self) -> Painted<&T>
Source§fn quirk(&self, value: Quirk) -> Painted<&T>
fn quirk(&self, value: Quirk) -> Painted<&T>
Enables the yansi Quirk value.
This method should be used rarely. Instead, prefer to use quirk-specific
builder methods like mask() and
wrap(), which have the same functionality but are
pithier.
§Example
Enable wrapping using .quirk():
use yansi::{Paint, Quirk};
painted.quirk(Quirk::Wrap);Enable wrapping using wrap().
use yansi::Paint;
painted.wrap();Source§fn clear(&self) -> Painted<&T>
👎Deprecated since 1.0.1: renamed to resetting() due to conflicts with Vec::clear().
The clear() method will be removed in a future release.
fn clear(&self) -> Painted<&T>
renamed to resetting() due to conflicts with Vec::clear().
The clear() method will be removed in a future release.
Source§fn whenever(&self, value: Condition) -> Painted<&T>
fn whenever(&self, value: Condition) -> Painted<&T>
Conditionally enable styling based on whether the Condition value
applies. Replaces any previous condition.
See the crate level docs for more details.
§Example
Enable styling painted only when both stdout and stderr are TTYs:
use yansi::{Paint, Condition};
painted.red().on_yellow().whenever(Condition::STDOUTERR_ARE_TTY);