pub trait HeaderAction: 'static {
type Input: FormInput;
const NAME: &'static str;
const CONFIRM: bool = false;
// Required method
fn run(
cx: &Cx,
input: Self::Input,
ex: &mut dyn Executor,
) -> impl Future<Output = Result<Outcome, WriteError>> + Send;
// Provided methods
fn label(cx: &Cx) -> String { ... }
fn can_run(_cx: &Cx) -> bool { ... }
fn validate_input(_cx: &Cx, _input: &Self::Input) -> FieldErrors { ... }
fn success(cx: &Cx) -> String { ... }
}Expand description
A mutation that acts on no record, run from a button in a page’s header: “import posts”, “clear the cache”, “recompute the totals”.
A resource declares one with
ResourceDef::header_action, and its list page renders
the button; a Page declares one with
PageDef::header_action, and renders the buttons with
header_action_buttons:
struct RecountTags;
impl HeaderAction for RecountTags {
type Input = ();
const NAME: &'static str = "recount-tags";
async fn run(
_cx: &Cx,
_: (),
_ex: &mut dyn Executor,
) -> Result<tablo_core::Outcome, tablo_core::WriteError> {
// Recount through `ex`, the framework's transaction.
Ok(tablo_core::Outcome::done())
}
}The framework owns everything around run, as it does for a record’s
Action:
- the route,
{url}/-/actions/{NAME}under the list or page URL, and its CSRF check; - who may run it: on a resource, the policy’s
Ability::ViewAnyandAbility::RunHeaderwith the action’sNAME; on a page,PageDef::access; on either, thencan_run. A refusal answers 403 and renders no button; - the transaction:
runwrites through its executor, and an error rolls everything back; - on a resource, the hooks, with
Change::HeaderAction:Resource::before_commitin the transaction afterrun, thenResource::after_commitonce it commits; - the success notification, and the redirect back to the list as it was left, its search, sort and filters kept, or to the page.
No record is loaded, so nothing scopes run to the request’s tenant: an action
over a tenant’s records reads them through scoped_query.
An action that asks for an Input asks for it as a record’s action does, in a
dialog or a page titled with its label, and runs on its submit.
Required Associated Constants§
Sourceconst NAME: &'static str
const NAME: &'static str
The action’s URL segment, distinct among the actions of its resource or page.
A name that is not a single path segment does not compile, as for
Action::NAME.
Provided Associated Constants§
Required Associated Types§
Required Methods§
Sourcefn run(
cx: &Cx,
input: Self::Input,
ex: &mut dyn Executor,
) -> impl Future<Output = Result<Outcome, WriteError>> + Send
fn run( cx: &Cx, input: Self::Input, ex: &mut dyn Executor, ) -> impl Future<Output = Result<Outcome, WriteError>> + Send
Perform the action with the parsed input, through the framework’s transaction ex,
and say what the response does once it commits: Outcome::done
for the success notification, landing back on the list or page.
Refuses the input with WriteError::Refused, as
Action::run does.
Provided Methods§
Sourcefn label(cx: &Cx) -> String
fn label(cx: &Cx) -> String
The button text. Defaults to the message action-{NAME} of the panel’s catalogs, else
NAME in sentence case: "recount-tags" reads “Recount tags”.
Sourcefn can_run(_cx: &Cx) -> bool
fn can_run(_cx: &Cx) -> bool
Whether the request may run the action, beyond the policy or the page’s access: a
feature flag, a role the policy does not model. Defaults to true.
Sourcefn validate_input(_cx: &Cx, _input: &Self::Input) -> FieldErrors
fn validate_input(_cx: &Cx, _input: &Self::Input) -> FieldErrors
Refuse an input run should not receive. Each error names an input field’s
key and renders under its control. Defaults to none. A key no control renders is a
declaration error: the page would show no message.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".