defmodule MvWeb.RoleLive.Show do @moduledoc """ LiveView for displaying a single role's details. ## Features - Display role information (name, description, permission_set_name, is_system_role) - Navigate to edit form - Return to role list ## Security Only admins can access this page (enforced by authorization). """ use MvWeb, :live_view @impl true def mount(%{"id" => id}, _session, socket) do # Ensure current_user has role loaded for authorization checks socket = if socket.assigns[:current_user] do user = socket.assigns.current_user user_with_role = case Map.get(user, :role) do %Ash.NotLoaded{} -> Ash.load!(user, :role, domain: Mv.Accounts) nil -> Ash.load!(user, :role, domain: Mv.Accounts) role when not is_nil(role) -> user end assign(socket, :current_user, user_with_role) else socket end role = Ash.get!(Mv.Authorization.Role, id, domain: Mv.Authorization) {:ok, socket |> assign(:page_title, gettext("Show Role")) |> assign(:role, role)} end @impl true def handle_event("delete", %{"id" => id}, socket) do {:ok, role} = Mv.Authorization.get_role(id) case Mv.Authorization.destroy_role(role) do :ok -> {:noreply, socket |> put_flash(:info, gettext("Role deleted successfully.")) |> push_navigate(to: ~p"/admin/roles")} {:error, error} -> error_message = format_error(error) {:noreply, put_flash( socket, :error, gettext("Failed to delete role: %{error}", error: error_message) )} end end @impl true def render(assigns) do ~H""" <.header> {gettext("Role")} {@role.name} <:subtitle>{gettext("Role details and permissions.")} <:actions> <.button navigate={~p"/admin/roles"} aria-label={gettext("Back to roles list")}> <.icon name="hero-arrow-left" /> {gettext("Back to roles list")} <%= if can?(@current_user, :update, Mv.Authorization.Role) do %> <.button variant="primary" navigate={~p"/admin/roles/#{@role}/edit"}> <.icon name="hero-pencil-square" /> {gettext("Edit Role")} <% end %> <%= if can?(@current_user, :destroy, Mv.Authorization.Role) and not @role.is_system_role do %> <.link phx-click={JS.push("delete", value: %{id: @role.id})} data-confirm={gettext("Are you sure?")} class="btn btn-error" > <.icon name="hero-trash" /> {gettext("Delete Role")} <% end %> <.list> <:item title={gettext("Name")}>{@role.name} <:item title={gettext("Description")}> <%= if @role.description do %> {@role.description} <% else %> {gettext("No description")} <% end %> <:item title={gettext("Permission Set")}> {@role.permission_set_name} <:item title={gettext("System Role")}> <%= if @role.is_system_role do %> {gettext("Yes")} <% else %> {gettext("No")} <% end %> """ end defp format_error(%Ash.Error.Invalid{} = error) do Enum.map_join(error.errors, ", ", fn e -> e.message end) end defp format_error(error) when is_binary(error), do: error defp format_error(_error), do: gettext("An error occurred") defp permission_set_badge_class("own_data"), do: "badge badge-neutral badge-sm" defp permission_set_badge_class("read_only"), do: "badge badge-info badge-sm" defp permission_set_badge_class("normal_user"), do: "badge badge-success badge-sm" defp permission_set_badge_class("admin"), do: "badge badge-error badge-sm" defp permission_set_badge_class(_), do: "badge badge-ghost badge-sm" end