Add complete CRUD interface for role management under /admin/roles. - Index page with table showing name, description, permission_set_name, is_system_role - Show page for role details - Form component for create/edit with permission_set_name dropdown - System role badge and disabled delete button - Flash messages for success/error - Authorization checks using MvWeb.Authorization helpers - Comprehensive test coverage (22 tests) Routes added under /admin scope. All LiveViews load user role for authorization checks. Form uses custom dropdown for permission sets.
91 lines
3 KiB
Text
91 lines
3 KiB
Text
<Layouts.app flash={@flash} current_user={@current_user}>
|
|
<.header>
|
|
{gettext("Listing Roles")}
|
|
<:subtitle>
|
|
{gettext("Manage user roles and their permission sets.")}
|
|
</:subtitle>
|
|
<:actions>
|
|
<%= if can?(@current_user, :create, Mv.Authorization.Role) do %>
|
|
<.button variant="primary" navigate={~p"/admin/roles/new"}>
|
|
<.icon name="hero-plus" /> {gettext("New Role")}
|
|
</.button>
|
|
<% end %>
|
|
</:actions>
|
|
</.header>
|
|
|
|
<.table
|
|
id="roles"
|
|
rows={@roles}
|
|
row_click={fn role -> JS.navigate(~p"/admin/roles/#{role}") end}
|
|
>
|
|
<:col :let={role} label={gettext("Name")}>
|
|
<div class="flex items-center gap-2">
|
|
<span class="font-medium">{role.name}</span>
|
|
<%= if role.is_system_role do %>
|
|
<span class="badge badge-warning badge-sm">{gettext("System Role")}</span>
|
|
<% end %>
|
|
</div>
|
|
</:col>
|
|
|
|
<:col :let={role} label={gettext("Description")}>
|
|
<%= if role.description do %>
|
|
<span class="text-sm">{role.description}</span>
|
|
<% else %>
|
|
<span class="text-base-content/50">{gettext("No description")}</span>
|
|
<% end %>
|
|
</:col>
|
|
|
|
<:col :let={role} label={gettext("Permission Set")}>
|
|
<span class={permission_set_badge_class(role.permission_set_name)}>
|
|
{role.permission_set_name}
|
|
</span>
|
|
</:col>
|
|
|
|
<:col :let={role} label={gettext("Type")}>
|
|
<%= if role.is_system_role do %>
|
|
<span class="badge badge-warning badge-sm">{gettext("System")}</span>
|
|
<% else %>
|
|
<span class="badge badge-ghost badge-sm">{gettext("Custom")}</span>
|
|
<% end %>
|
|
</:col>
|
|
|
|
<:action :let={role}>
|
|
<div class="sr-only">
|
|
<.link navigate={~p"/admin/roles/#{role}"}>{gettext("Show")}</.link>
|
|
</div>
|
|
|
|
<%= if can?(@current_user, :update, Mv.Authorization.Role) do %>
|
|
<.link navigate={~p"/admin/roles/#{role}/edit"} class="btn btn-ghost btn-xs">
|
|
<.icon name="hero-pencil" class="size-4" />
|
|
</.link>
|
|
<% end %>
|
|
</:action>
|
|
|
|
<:action :let={role}>
|
|
<%= 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}) |> hide("#row-#{role.id}")}
|
|
data-confirm={gettext("Are you sure?")}
|
|
class="btn btn-ghost btn-xs text-error"
|
|
aria-label={gettext("Delete role")}
|
|
>
|
|
<.icon name="hero-trash" class="size-4" />
|
|
</.link>
|
|
<% else %>
|
|
<div
|
|
:if={role.is_system_role}
|
|
class="tooltip tooltip-left"
|
|
data-tip={gettext("System roles cannot be deleted")}
|
|
>
|
|
<button
|
|
class="btn btn-ghost btn-xs text-error opacity-50 cursor-not-allowed"
|
|
disabled={true}
|
|
aria-label={gettext("Cannot delete system role")}
|
|
>
|
|
<.icon name="hero-trash" class="size-4" />
|
|
</button>
|
|
</div>
|
|
<% end %>
|
|
</:action>
|
|
</.table>
|
|
</Layouts.app>
|