use std::convert::Infallible;
use topcoat::{
context::Cx,
icon::{IconData, icon},
view::{BoxView, ViewExt, attributes, view},
};
use crate::{Action, Outcome, PanelUser, Places, Resource, WriteError};
#[derive(Debug, Clone, Copy)]
pub struct Impersonate;
impl<R: Resource> Action<R> for Impersonate
where
R::Model: PanelUser,
{
type Input = ();
const NAME: &'static str = "impersonate";
const PLACES: Places = Places::RECORD;
const ICON: Option<IconData> = Some(tablo_ui::icons::EYE);
fn label() -> crate::Text {
crate::text!("tablo-impersonation-start")
}
fn can_run(cx: &Cx, record: &R::Model) -> bool {
crate::auth::may_impersonate(cx, record)
}
async fn run(
cx: &Cx,
records: &[R::Model],
(): (),
ex: &mut dyn toasty::Executor,
) -> Result<Outcome, WriteError<Infallible>> {
let [target] = records else {
return Err(WriteError::declined(crate::text!(
"tablo-impersonation-one"
)));
};
crate::auth::impersonate(cx, ex, target)
.await
.map_err(WriteError::Failed)?;
Ok(Outcome::done().redirect(crate::auth::panel_prefix(cx)))
}
fn success(_count: usize) -> crate::Text {
crate::text!("tablo-impersonation-started")
}
}
pub(super) fn banner(cx: &Cx) -> BoxView<'_> {
match crate::auth::signed(cx) {
Some(signed) if signed.impersonator.is_some() => strip(cx, signed),
_ => view! {}.boxed(),
}
}
fn strip<'a>(cx: &'a Cx, signed: &'a crate::auth::SignedIn) -> BoxView<'a> {
let csrf = crate::csrf::ensure_token(cx);
let stop = crate::auth::stop_impersonating_url(cx);
let name = signed.user.display_name().to_owned();
view! {
<div
class="flex flex-wrap items-center justify-between gap-2 border-b border-warning/40 \
bg-warning/15 px-4 py-2 text-sm text-foreground"
role="status"
data-impersonating=(signed.user.user_id())
>
<span>(crate::t!(cx, "tablo-impersonation-banner", name = name))</span>
<form method="post" action=(stop)>
(crate::csrf::field(cx, &csrf))
tablo_ui::button(
variant: tablo_ui::ButtonVariant::Outline,
size: tablo_ui::ButtonSize::Sm,
attrs: attributes! { type="submit" },
icon(data: tablo_ui::icons::LOG_OUT)
(crate::t!(cx, "tablo-impersonation-stop"))
)
</form>
</div>
}
.boxed()
}