pub struct PanelHandle { /* private fields */ }Expand description
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 through
Panel::handle. Cloning it is cheap.
let builder = Router::builder()
.discover()
.app_context(db)
.panel(Panel::new("admin").resource::<PostResource>())?;
let admin = builder.panel_handle("admin").expect("mounted above");
let router = builder.build();
// In the job, once per run:
let cx = admin.context().with(Tenant(tenant));
let posts = scoped_query::<PostResource>(&cx)?;Implementations§
Source§impl PanelHandle
impl PanelHandle
Sourcepub fn context(&self) -> Cx
pub fn context(&self) -> Cx
A context outside any request in which the panel’s resources answer as the panel mounted
them: what a job or a test passes to scoped_query,
can, write_create and the other entry points that
answer from a mounted def. It holds the database and the resources, and no request,
session or tenant. Add a tenant with cx.with(Tenant(id)). It carries no signed-in user,
so a policy that reads one answers as for a signed-out request.
The context is one unit of work, as a request is: loads it memoizes stay cached for its lifetime, so a job builds one per run. A context built with no panel at all knows no resource: every entry point that reads a mounted def answers as for a resource the panel does not mount.
Sourcepub fn enter(&self, cx: &Cx) -> Cx
pub fn enter(&self, cx: &Cx) -> Cx
cx answering as this panel, for a request outside every panel’s prefix, such as a
public page: scoped_query, can and the other
entry points that answer from a mounted def answer as this panel mounted its resources,
and, for a handle a router gives, the url helpers answer with its URLs.
A request outside every prefix answers as no panel until it enters one, however many
panels the router mounts. It runs no auth gate and signs no one in, so a public page’s
context knows no user. Enter only outside every prefix: under a panel’s prefix, a handle
Panel::handle gives leaves the request answering as its own panel.
async fn public_posts(cx: &Cx, admin: &PanelHandle) -> Result<Vec<Post>> {
let cx = admin.enter(cx);
Ok(scoped_query::<PostResource>(&cx)?
.exec(&mut tablo_core::db::db(&cx)?)
.await?)
}Sourcepub fn url(&self) -> Option<String>
pub fn url(&self) -> Option<String>
The panel’s prefix, e.g. /admin, for a public page’s link to it; None for
Panel::handle’s, which no router mounts.
Sourcepub fn notifications(&self) -> Notifications
pub fn notifications(&self) -> Notifications
Sends stored notifications to this panel’s users from outside a request, such as from a
job, for no tenant until Notifications::tenant names one. The bells they have open
update when the handle is a router’s.
admin
.notifications()
.tenant(tenant)
.send(owner_id, Notification::info("The nightly import finished"))
.await?;Sourcepub async fn document<'a>(
&'a self,
cx: &'a Cx,
title: impl Into<String>,
body: impl View + 'a,
) -> Result<BoxView<'a>>
pub async fn document<'a>( &'a self, cx: &'a Cx, title: impl Into<String>, body: impl View + 'a, ) -> Result<BoxView<'a>>
Renders a complete HTML document around a page outside every prefix with this panel’s
shell settings: its stylesheet, font, scripts, favicon and dark-mode default. A handle
Panel::handle gives renders the document without them.
/// The handle `panel_handle("admin")` returned, kept in the app context.
struct Admin(PanelHandle);
#[layout("/blog")]
async fn blog_layout(cx: &Cx, slot: Slot<'_>) -> Result<impl View> {
let Admin(admin) = app_context::<Admin>(cx);
admin.document(cx, "Blog", view! { <main>(slot)</main> }).await
}