Packages
phoenix_kit
1.7.89
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.html.heex
<PhoenixKitWeb.Components.LayoutWrapper.app_layout
flash={@flash}
phoenix_kit_current_scope={assigns[:phoenix_kit_current_scope]}
page_title={gettext("Permissions")}
current_path={@url_path}
project_title={@project_title}
current_locale={@current_locale}
>
<div class="container flex-col mx-auto px-4 py-6">
<.admin_page_header
back={PhoenixKit.Utils.Routes.path("/admin/users/roles")}
title={gettext("Permissions")}
subtitle={gettext("Overview of role permissions across all modules")}
/>
<%!-- Matrix Table --%>
<div class="bg-base-100">
<div class="rounded-lg shadow-md overflow-x-auto overflow-y-clip">
<table class="table table-sm table-zebra">
<thead class="bg-primary text-primary-content">
<tr>
<th class="sticky left-0 z-0 whitespace-nowrap">{gettext("Module")}</th>
<%= for role <- @roles do %>
<th class="text-center min-w-[100px]">
<.pk_link navigate="/admin/users/roles" class="link link-hover">
{role.name}
</.pk_link>
</th>
<% end %>
</tr>
</thead>
<tbody>
<%!-- Core Sections Header --%>
<tr class="bg-primary/10">
<td
colspan={length(@roles) + 1}
class="sticky left-0 bg-primary/10 font-semibold text-xs uppercase tracking-wide text-primary py-2"
>
{gettext("Core Sections")}
</td>
</tr>
<%= for {key, _idx} <- Enum.with_index(@core_keys) do %>
<tr>
<td class="sticky left-0 z-[1] font-medium whitespace-nowrap">
{PhoenixKit.Users.Permissions.module_label(key)}
</td>
<%= for role <- @roles do %>
<td class="text-center">
<%= if role.name == "Owner" do %>
<span class="badge badge-sm badge-primary badge-outline">
{gettext("always")}
</span>
<% else %>
<%= if MapSet.member?(@uneditable_role_uuids, to_string(role.uuid)) do %>
<%!-- Read-only: user's own role or Admin (non-Owner) --%>
<%= if Map.get(@matrix, to_string(role.uuid), MapSet.new()) |> MapSet.member?(key) do %>
<.icon name="hero-check-circle" class="w-5 h-5 text-success/50" />
<% else %>
<.icon name="hero-x-circle" class="w-5 h-5 text-base-content/10" />
<% end %>
<% else %>
<button
phx-click="toggle_permission"
phx-value-role_uuid={role.uuid}
phx-value-key={key}
class="cursor-pointer hover:opacity-70 transition-opacity"
>
<%= if Map.get(@matrix, to_string(role.uuid), MapSet.new()) |> MapSet.member?(key) do %>
<.icon name="hero-check-circle" class="w-5 h-5 text-success" />
<% else %>
<.icon name="hero-x-circle" class="w-5 h-5 text-base-content/20" />
<% end %>
</button>
<% end %>
<% end %>
</td>
<% end %>
</tr>
<% end %>
<%!-- Feature Modules Header --%>
<tr class="bg-primary/10">
<td
colspan={length(@roles) + 1}
class="sticky left-0 bg-primary/10 font-semibold text-xs uppercase tracking-wide text-primary py-2"
>
{gettext("Feature Modules")}
</td>
</tr>
<%= for {key, _idx} <- Enum.with_index(@feature_keys) do %>
<tr>
<td class="sticky left-0 z-[1] font-medium whitespace-nowrap">
{PhoenixKit.Users.Permissions.module_label(key)}
</td>
<%= for role <- @roles do %>
<td class="text-center">
<%= if role.name == "Owner" do %>
<span class="badge badge-sm badge-primary badge-outline">
{gettext("always")}
</span>
<% else %>
<%= if MapSet.member?(@uneditable_role_uuids, to_string(role.uuid)) do %>
<%!-- Read-only: user's own role or Admin (non-Owner) --%>
<%= if Map.get(@matrix, to_string(role.uuid), MapSet.new()) |> MapSet.member?(key) do %>
<.icon name="hero-check-circle" class="w-5 h-5 text-success/50" />
<% else %>
<.icon name="hero-x-circle" class="w-5 h-5 text-base-content/10" />
<% end %>
<% else %>
<button
phx-click="toggle_permission"
phx-value-role_uuid={role.uuid}
phx-value-key={key}
class="cursor-pointer hover:opacity-70 transition-opacity"
>
<%= if Map.get(@matrix, to_string(role.uuid), MapSet.new()) |> MapSet.member?(key) do %>
<.icon name="hero-check-circle" class="w-5 h-5 text-success" />
<% else %>
<.icon name="hero-x-circle" class="w-5 h-5 text-base-content/20" />
<% end %>
</button>
<% end %>
<% end %>
</td>
<% end %>
</tr>
<% end %>
<%!-- Custom (permission keys registered by parent app) --%>
<%= if length(@custom_keys) > 0 do %>
<tr class="bg-primary/10">
<td
colspan={length(@roles) + 1}
class="sticky left-0 bg-primary/10 font-semibold text-xs uppercase tracking-wide text-primary py-2"
>
{gettext("Custom")}
</td>
</tr>
<%= for {key, _idx} <- Enum.with_index(@custom_keys) do %>
<tr>
<td class="sticky left-0 z-[1] font-medium whitespace-nowrap">
{PhoenixKit.Users.Permissions.module_label(key)}
</td>
<%= for role <- @roles do %>
<td class="text-center">
<%= if role.name == "Owner" do %>
<span class="badge badge-sm badge-primary badge-outline">
{gettext("always")}
</span>
<% else %>
<%= if MapSet.member?(@uneditable_role_uuids, to_string(role.uuid)) do %>
<%!-- Read-only: user's own role or Admin (non-Owner) --%>
<%= if Map.get(@matrix, to_string(role.uuid), MapSet.new()) |> MapSet.member?(key) do %>
<.icon name="hero-check-circle" class="w-5 h-5 text-success/50" />
<% else %>
<.icon name="hero-x-circle" class="w-5 h-5 text-base-content/10" />
<% end %>
<% else %>
<button
phx-click="toggle_permission"
phx-value-role_uuid={role.uuid}
phx-value-key={key}
class="cursor-pointer hover:opacity-70 transition-opacity"
>
<%= if Map.get(@matrix, to_string(role.uuid), MapSet.new()) |> MapSet.member?(key) do %>
<.icon name="hero-check-circle" class="w-5 h-5 text-success" />
<% else %>
<.icon name="hero-x-circle" class="w-5 h-5 text-base-content/20" />
<% end %>
</button>
<% end %>
<% end %>
</td>
<% end %>
</tr>
<% end %>
<% end %>
<%!-- Summary Row --%>
<tr class="font-semibold">
<td class="sticky left-0 z-[1] whitespace-nowrap">
{gettext("Total")}
</td>
<%= for role <- @roles do %>
<td class="text-center">
<%= if role.name == "Owner" do %>
{MapSet.size(@visible_keys)} / {MapSet.size(@visible_keys)}
<% else %>
{Map.get(@matrix, to_string(role.uuid), MapSet.new())
|> MapSet.intersection(@visible_keys)
|> MapSet.size()} / {MapSet.size(@visible_keys)}
<% end %>
</td>
<% end %>
</tr>
</tbody>
</table>
</div>
</div>
<%!-- Help Info --%>
<div class="alert alert-info mt-6">
<.icon name="hero-information-circle" class="w-5 h-5" />
<div>
<h3 class="font-bold">{gettext("About Permissions")}</h3>
<p class="text-sm">
{gettext(
"Click any check or cross icon to toggle a permission for that role. The Owner role always has full access and cannot be modified. You cannot edit permissions for your own role or for roles with higher authority. You can only grant or revoke permissions that your own role has."
)}
</p>
</div>
</div>
</div>
</PhoenixKitWeb.Components.LayoutWrapper.app_layout>