Packages
phoenix_kit
1.7.34
1.7.210
1.7.209
1.7.208
1.7.207
1.7.206
1.7.205
1.7.204
1.7.203
1.7.202
1.7.201
1.7.200
1.7.199
1.7.198
1.7.197
1.7.196
1.7.194
1.7.193
1.7.192
1.7.191
1.7.190
1.7.189
1.7.187
1.7.186
1.7.185
1.7.184
1.7.183
1.7.182
1.7.181
1.7.180
1.7.179
1.7.178
1.7.177
1.7.176
1.7.175
1.7.174
1.7.173
1.7.172
1.7.171
1.7.170
1.7.169
1.7.168
1.7.167
1.7.166
1.7.165
1.7.164
1.7.162
1.7.161
1.7.160
1.7.159
1.7.157
1.7.156
1.7.155
1.7.154
1.7.153
1.7.152
1.7.151
1.7.150
1.7.149
1.7.146
1.7.145
1.7.144
1.7.143
1.7.138
1.7.133
1.7.132
1.7.131
1.7.130
1.7.128
1.7.126
1.7.125
1.7.121
1.7.120
1.7.119
1.7.118
1.7.117
1.7.116
1.7.115
1.7.114
1.7.113
1.7.112
1.7.111
1.7.110
1.7.109
1.7.108
1.7.107
1.7.106
1.7.105
1.7.104
1.7.103
1.7.102
1.7.101
1.7.100
1.7.99
1.7.98
1.7.97
1.7.96
1.7.95
1.7.94
1.7.93
1.7.92
1.7.91
1.7.90
1.7.89
1.7.88
1.7.87
1.7.86
1.7.85
1.7.84
1.7.83
1.7.82
1.7.81
1.7.80
1.7.79
1.7.78
1.7.77
1.7.76
1.7.75
1.7.74
1.7.71
1.7.70
1.7.69
1.7.66
1.7.65
1.7.64
1.7.63
1.7.62
1.7.61
1.7.59
1.7.58
1.7.57
1.7.56
1.7.55
1.7.54
1.7.53
1.7.52
1.7.51
1.7.49
1.7.44
1.7.43
1.7.42
1.7.41
1.7.39
1.7.38
1.7.37
1.7.36
1.7.34
1.7.33
1.7.31
1.7.30
1.7.29
1.7.28
1.7.27
1.7.26
1.7.25
1.7.24
1.7.23
1.7.22
1.7.21
1.7.20
1.7.19
1.7.18
1.7.17
1.7.16
1.7.15
1.7.14
1.7.13
1.7.12
1.7.11
1.7.10
1.7.9
1.7.8
1.7.7
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
1.7.1
1.7.0
1.6.20
1.6.19
1.6.18
1.6.17
1.6.16
1.6.15
1.6.14
1.6.13
1.6.12
1.6.11
1.6.10
1.6.9
1.6.8
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.5.2
1.5.1
1.5.0
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.10
1.2.9
1.2.8
1.2.7
1.2.5
1.2.4
1.2.2
1.2.1
1.2.0
1.1.0
1.0.0
A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more
Current section
Files
Jump to
Current section
Files
lib/phoenix_kit_web/live/users/permissions_matrix.ex
defmodule PhoenixKitWeb.Live.Users.PermissionsMatrix do
@moduledoc """
Interactive permissions matrix view for PhoenixKit admin panel.
Displays a matrix of roles vs module permission keys, showing which
roles have access to which sections. Owner column shows "always" badge.
Cells are clickable to toggle permissions directly.
"""
use PhoenixKitWeb, :live_view
use Gettext, backend: PhoenixKitWeb.Gettext
alias PhoenixKit.Admin.Events
alias PhoenixKit.Settings
alias PhoenixKit.Users.Auth.Scope
alias PhoenixKit.Users.Permissions
alias PhoenixKit.Users.Roles
def mount(_params, _session, socket) do
if connected?(socket) do
Events.subscribe_to_roles()
Events.subscribe_to_permissions()
Events.subscribe_to_modules()
end
project_title = Settings.get_project_title()
socket =
socket
|> assign(:page_title, "Permissions Matrix")
|> assign(:project_title, project_title)
|> load_matrix()
{:ok, socket}
end
# --- PubSub Handlers ---
def handle_info({:role_created, _role}, socket) do
{:noreply, load_matrix(socket)}
end
def handle_info({:role_updated, _role}, socket) do
{:noreply, load_matrix(socket)}
end
def handle_info({:role_deleted, _role}, socket) do
{:noreply, load_matrix(socket)}
end
def handle_info({:permission_granted, _role_id, _key}, socket) do
{:noreply, refresh_matrix(socket)}
end
def handle_info({:permission_revoked, _role_id, _key}, socket) do
{:noreply, refresh_matrix(socket)}
end
def handle_info({:permissions_synced, _role_id, _keys}, socket) do
{:noreply, refresh_matrix(socket)}
end
def handle_info({:module_enabled, _key}, socket) do
{:noreply, load_matrix(socket)}
end
def handle_info({:module_disabled, _key}, socket) do
{:noreply, load_matrix(socket)}
end
def handle_info(_msg, socket), do: {:noreply, socket}
# --- Events ---
def handle_event("toggle_permission", %{"role_id" => role_id_str, "key" => key}, socket) do
scope = socket.assigns[:phoenix_kit_current_scope]
with {role_id, ""} <- Integer.parse(role_id_str),
role when not is_nil(role) <- Enum.find(socket.assigns.roles, &(&1.id == role_id)),
false <- role.name == "Owner",
true <- scope != nil && Scope.has_module_access?(scope, "users") do
grantable =
if Scope.owner?(scope),
do: MapSet.new(Permissions.all_module_keys()),
else: Scope.accessible_modules(scope)
if MapSet.member?(grantable, key) do
granted_by_id = Scope.user_id(scope)
role_keys = Map.get(socket.assigns.matrix, role_id, MapSet.new())
label = Permissions.module_label(key)
if MapSet.member?(role_keys, key) do
Permissions.revoke_permission(role_id, key)
{:noreply,
socket |> put_flash(:info, "Revoked #{label} from #{role.name}") |> refresh_matrix()}
else
Permissions.grant_permission(role_id, key, granted_by_id)
{:noreply,
socket |> put_flash(:info, "Granted #{label} to #{role.name}") |> refresh_matrix()}
end
else
{:noreply, put_flash(socket, :error, "You can only manage permissions you have")}
end
else
_ ->
{:noreply, socket}
end
end
# --- Helpers ---
defp load_matrix(socket) do
roles = Roles.list_roles()
matrix = Permissions.get_permissions_matrix()
all_count = length(Permissions.all_module_keys())
# Sort: Owner first, then by permission count descending, then name
sorted_roles =
Enum.sort_by(roles, fn role ->
count =
if role.name == "Owner",
do: all_count,
else: Map.get(matrix, role.id, MapSet.new()) |> MapSet.size()
{role.name != "Owner", -count, role.name}
end)
enabled = Permissions.enabled_module_keys()
enabled_feature_keys =
Enum.filter(Permissions.feature_module_keys(), &MapSet.member?(enabled, &1))
socket
|> assign(:roles, sorted_roles)
|> assign(:matrix, matrix)
|> assign(:core_keys, Permissions.core_section_keys())
|> assign(:feature_keys, enabled_feature_keys)
end
# Refresh matrix data only, keep existing role order stable
defp refresh_matrix(socket) do
matrix = Permissions.get_permissions_matrix()
assign(socket, :matrix, matrix)
end
end