defmodule MvWeb.RoleLive.Index do @moduledoc """ LiveView for displaying and managing the role list. ## Features - List all roles with name, description, permission_set_name, is_system_role - Create new roles - Navigate to role details and edit forms - Delete non-system roles ## Events - `delete` - Remove a role from the database (only non-system roles) ## Security Only admins can access this page (enforced by authorization). """ use MvWeb, :live_view alias Mv.Authorization @impl true def mount(_params, _session, socket) do socket = ensure_user_role_loaded(socket) roles = load_roles() {:ok, socket |> assign(:page_title, gettext("Listing Roles")) |> assign(:roles, roles)} end defp ensure_user_role_loaded(socket) do if socket.assigns[:current_user] do user = socket.assigns.current_user user_with_role = load_user_role(user) assign(socket, :current_user, user_with_role) else socket end end defp load_user_role(user) do case Map.get(user, :role) do %Ash.NotLoaded{} -> load_role_safely(user) nil -> load_role_safely(user) _role -> user end end defp load_role_safely(user) do case Ash.load(user, :role, domain: Mv.Accounts) do {:ok, loaded_user} -> loaded_user {:error, _} -> user end end @impl true def handle_event("delete", %{"id" => id}, socket) do {:ok, role} = Authorization.get_role(id) case Authorization.destroy_role(role) do :ok -> updated_roles = Enum.reject(socket.assigns.roles, &(&1.id == id)) {:noreply, socket |> assign(:roles, updated_roles) |> put_flash(:info, gettext("Role deleted successfully"))} {:error, error} -> error_message = format_error(error) {:noreply, put_flash( socket, :error, gettext("Failed to delete role: %{error}", error: error_message) )} end end defp load_roles do case Authorization.list_roles() do {:ok, roles} -> Enum.sort_by(roles, & &1.name) {:error, _} -> [] 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