//! The Askama entry point for the described "remove this link" button. //! //! Shape 8 (`b279b9eb`), through the glue-module ruling `27d5e5b8`. One of the //! two sites the shape recorded as unsayable: the template reached its row with //! `hx-target="closest .link-row"`, and naming a region cannot say a relative //! selector. //! //! [`Action::replacing_enclosing`] is that sentence in a spelling every //! renderer reads, and it takes no parameter because the act is inside the row //! it removes. The row says `data-row` in Askama, which is the attribute a //! described row already carries and the one the target selects on. Nothing is //! invented: the class stays where the page's own scripts still read it. //! //! `DELETE /api/links/{id}` is a plain API route the description layer does not //! serve, which is why the control names what it replaces at all. See //! [`Action::replaces`]. //! //! # Why the caller wraps this in a span //! //! `link_remove_btn` was never styling. `static/tab-user-profile.js` hides the //! Remove while a row is being edited and finds it by that class, and a //! described act carries the class every described act carries. The class moves //! to the element around the control, which is where a fact about that page //! belongs and what `export_act` already does with its layout classes. It goes //! when the profile tab is described and the edit flow with it. //! //! Ids arrive as `impl Display` rather than `&str`: the caller is Askama and //! the server's ids are typed newtypes over `Uuid`, so asking for a string //! would push a `to_string()` into every call site to say what `format!` //! already says here. use std::fmt; use makeover_layout::Tone; use quasi_router::screen::Act; use quasi_router::{Action, Node}; /// The remove button for one link row. #[must_use] pub fn html(link_id: impl fmt::Display) -> String { use quasi_axum::Serves as _; let act = Act::new( "Remove", Action::delete(format!("/api/links/{link_id}")).replacing_enclosing(), ) .tone(Tone::Danger) .confirm("Remove this link?"); quasi_webview::Webview::new().fragment(&Node::Act(act)) } #[cfg(test)] mod tests { /// The row it sits in, said without a selector the description cannot hold. #[test] fn a_removal_names_its_route_its_row_and_its_prompt() { let html = super::html("l3"); assert!(html.contains(r#"hx-delete="/api/links/l3""#), "{html}"); assert!(html.contains(r#"hx-target="closest [data-row]""#), "{html}"); assert!(html.contains(r#"hx-confirm="Remove this link?""#), "{html}"); assert!(!html.contains(".link-row"), "{html}"); } #[test] fn a_removal_says_it_is_dangerous() { assert!(super::html("l3").contains(r#"data-tone="danger""#)); } }