easy-admin-rails 0.1.15 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/assets/builds/easy_admin.base.js +254 -18
- data/app/assets/builds/easy_admin.base.js.map +4 -4
- data/app/assets/builds/easy_admin.css +112 -18
- data/app/components/easy_admin/base_component.rb +1 -0
- data/app/components/easy_admin/form_tabs_component.rb +5 -2
- data/app/components/easy_admin/navbar_component.rb +5 -1
- data/app/components/easy_admin/permissions/user_role_assignment_component.rb +254 -0
- data/app/components/easy_admin/permissions/user_role_permissions_component.rb +186 -0
- data/app/components/easy_admin/resources/index_component.rb +1 -4
- data/app/components/easy_admin/sidebar_component.rb +67 -2
- data/app/controllers/easy_admin/application_controller.rb +131 -1
- data/app/controllers/easy_admin/batch_actions_controller.rb +27 -0
- data/app/controllers/easy_admin/concerns/belongs_to_editing.rb +201 -0
- data/app/controllers/easy_admin/concerns/inline_field_editing.rb +297 -0
- data/app/controllers/easy_admin/concerns/resource_authorization.rb +55 -0
- data/app/controllers/easy_admin/concerns/resource_filtering.rb +178 -0
- data/app/controllers/easy_admin/concerns/resource_loading.rb +149 -0
- data/app/controllers/easy_admin/concerns/resource_pagination.rb +135 -0
- data/app/controllers/easy_admin/dashboard_controller.rb +2 -1
- data/app/controllers/easy_admin/dashboards_controller.rb +6 -40
- data/app/controllers/easy_admin/resources_controller.rb +13 -762
- data/app/controllers/easy_admin/row_actions_controller.rb +25 -0
- data/app/helpers/easy_admin/fields_helper.rb +61 -9
- data/app/javascript/easy_admin/controllers/event_emitter_controller.js +2 -4
- data/app/javascript/easy_admin/controllers/infinite_scroll_controller.js +0 -10
- data/app/javascript/easy_admin/controllers/jsoneditor_controller.js +1 -4
- data/app/javascript/easy_admin/controllers/permission_toggle_controller.js +227 -0
- data/app/javascript/easy_admin/controllers/role_preview_controller.js +93 -0
- data/app/javascript/easy_admin/controllers/select_field_controller.js +1 -2
- data/app/javascript/easy_admin/controllers/settings_button_controller.js +1 -2
- data/app/javascript/easy_admin/controllers/settings_sidebar_controller.js +1 -4
- data/app/javascript/easy_admin/controllers/turbo_stream_redirect.js +0 -2
- data/app/javascript/easy_admin/controllers.js +5 -1
- data/app/models/easy_admin/admin_user.rb +6 -0
- data/app/policies/admin_user_policy.rb +36 -0
- data/app/policies/application_policy.rb +83 -0
- data/app/views/easy_admin/application/authorization_failure.turbo_stream.erb +8 -0
- data/app/views/easy_admin/dashboards/card.html.erb +5 -0
- data/app/views/easy_admin/dashboards/card.turbo_stream.erb +7 -0
- data/app/views/easy_admin/dashboards/card_error.html.erb +3 -0
- data/app/views/easy_admin/dashboards/card_error.turbo_stream.erb +5 -0
- data/app/views/easy_admin/dashboards/show.turbo_stream.erb +7 -0
- data/app/views/easy_admin/resources/belongs_to_edit_attached.html.erb +6 -0
- data/app/views/easy_admin/resources/belongs_to_edit_attached.turbo_stream.erb +8 -0
- data/app/views/easy_admin/resources/belongs_to_reattach.html.erb +5 -0
- data/app/views/easy_admin/resources/edit.html.erb +1 -1
- data/app/views/easy_admin/resources/edit_field.html.erb +5 -0
- data/app/views/easy_admin/resources/edit_field.turbo_stream.erb +7 -0
- data/app/views/easy_admin/resources/index.html.erb +1 -1
- data/app/views/easy_admin/resources/index_frame.html.erb +8 -142
- data/app/views/easy_admin/resources/update_belongs_to_attached.turbo_stream.erb +25 -0
- data/app/views/layouts/easy_admin/application.html.erb +15 -2
- data/config/initializers/easy_admin_permissions.rb +73 -0
- data/db/seeds/easy_admin_permissions.rb +121 -0
- data/lib/easy-admin-rails.rb +2 -0
- data/lib/easy_admin/permissions/component.rb +168 -0
- data/lib/easy_admin/permissions/configuration.rb +37 -0
- data/lib/easy_admin/permissions/controller.rb +164 -0
- data/lib/easy_admin/permissions/dsl.rb +160 -0
- data/lib/easy_admin/permissions/models.rb +44 -0
- data/lib/easy_admin/permissions/permission_denied_component.rb +121 -0
- data/lib/easy_admin/permissions/resource_permissions.rb +231 -0
- data/lib/easy_admin/permissions/role_definition.rb +45 -0
- data/lib/easy_admin/permissions/role_denied_component.rb +159 -0
- data/lib/easy_admin/permissions/role_dsl.rb +73 -0
- data/lib/easy_admin/permissions/user_extensions.rb +129 -0
- data/lib/easy_admin/permissions.rb +113 -0
- data/lib/easy_admin/resource/base.rb +119 -0
- data/lib/easy_admin/resource/configuration.rb +148 -0
- data/lib/easy_admin/resource/dsl.rb +117 -0
- data/lib/easy_admin/resource/field_registry.rb +189 -0
- data/lib/easy_admin/resource/form_builder.rb +123 -0
- data/lib/easy_admin/resource/layout_builder.rb +249 -0
- data/lib/easy_admin/resource/scope_manager.rb +252 -0
- data/lib/easy_admin/resource/show_builder.rb +359 -0
- data/lib/easy_admin/resource.rb +8 -835
- data/lib/easy_admin/resource_modules.rb +11 -0
- data/lib/easy_admin/version.rb +1 -1
- data/lib/generators/easy_admin/permissions/install_generator.rb +90 -0
- data/lib/generators/easy_admin/permissions/templates/initializers/permissions.rb +37 -0
- data/lib/generators/easy_admin/permissions/templates/migrations/create_permission_tables.rb +27 -0
- data/lib/generators/easy_admin/permissions/templates/migrations/update_users_for_permissions.rb +6 -0
- data/lib/generators/easy_admin/permissions/templates/models/permission.rb +9 -0
- data/lib/generators/easy_admin/permissions/templates/models/role.rb +9 -0
- data/lib/generators/easy_admin/permissions/templates/models/role_permission.rb +9 -0
- data/lib/generators/easy_admin/permissions/templates/models/user_role.rb +9 -0
- data/lib/generators/easy_admin/permissions/templates/policies/application_policy.rb +47 -0
- data/lib/generators/easy_admin/permissions/templates/policies/user_policy.rb +36 -0
- data/lib/generators/easy_admin/permissions/templates/seeds/permissions.rb +89 -0
- metadata +62 -5
- data/db/migrate/20250101000001_create_easy_admin_admin_users.rb +0 -45
@@ -0,0 +1,83 @@
|
|
1
|
+
class ApplicationPolicy < ActionPolicy::Base
|
2
|
+
# Configure authorization context
|
3
|
+
authorize :user, allow_nil: true
|
4
|
+
|
5
|
+
# Make this the default policy for EasyAdmin models
|
6
|
+
self.identifier = :application
|
7
|
+
|
8
|
+
# Basic authorization rules using EasyAdmin permissions
|
9
|
+
def index?
|
10
|
+
user_has_permission?("#{resource_name}:read")
|
11
|
+
end
|
12
|
+
|
13
|
+
def show?
|
14
|
+
user_has_permission?("#{resource_name}:read")
|
15
|
+
end
|
16
|
+
|
17
|
+
def create?
|
18
|
+
user_has_permission?("#{resource_name}:create")
|
19
|
+
end
|
20
|
+
|
21
|
+
def update?
|
22
|
+
user_has_permission?("#{resource_name}:update")
|
23
|
+
end
|
24
|
+
|
25
|
+
def destroy?
|
26
|
+
user_has_permission?("#{resource_name}:delete")
|
27
|
+
end
|
28
|
+
|
29
|
+
# Versioning permissions (requires update permission + additional versioning permission)
|
30
|
+
def manage_versions?
|
31
|
+
user_has_permission?("#{resource_name}:update") && user_has_permission?("#{resource_name}:manage_versions")
|
32
|
+
end
|
33
|
+
|
34
|
+
# Batch actions permission (requires update permission + batch action permission)
|
35
|
+
def batch_action?
|
36
|
+
user_has_permission?("#{resource_name}:update") && user_has_permission?("#{resource_name}:batch_actions")
|
37
|
+
end
|
38
|
+
|
39
|
+
# Row actions permission (requires read permission + row action permission)
|
40
|
+
def row_action?
|
41
|
+
user_has_permission?("#{resource_name}:read") && user_has_permission?("#{resource_name}:row_actions")
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def user_has_permission?(permission_name, context: nil)
|
48
|
+
EasyAdmin::Permissions.authorized?(user, permission_name, context: context)
|
49
|
+
end
|
50
|
+
|
51
|
+
def admin_user?
|
52
|
+
# Check if user has admin privileges through EasyAdmin permissions
|
53
|
+
return false unless user
|
54
|
+
|
55
|
+
# Check if user has a super_admin or admin role
|
56
|
+
if user.respond_to?(:role) && user.role
|
57
|
+
return true if %w[super_admin admin].include?(user.role.slug)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Fallback: check if user has manage permissions for admin_users
|
61
|
+
user_has_permission?("admin_users:manage") || user_has_permission?("admin_users:create")
|
62
|
+
end
|
63
|
+
|
64
|
+
def resource_name
|
65
|
+
if record.is_a?(Class)
|
66
|
+
# For class-level authorization
|
67
|
+
model_class = record
|
68
|
+
else
|
69
|
+
# For instance-level authorization
|
70
|
+
model_class = record.class
|
71
|
+
end
|
72
|
+
|
73
|
+
# Handle EasyAdmin namespaced models
|
74
|
+
class_name = model_class.name
|
75
|
+
if class_name.start_with?('EasyAdmin::')
|
76
|
+
# Extract the model name after the namespace
|
77
|
+
class_name.split('::').last.underscore
|
78
|
+
else
|
79
|
+
# Regular models
|
80
|
+
class_name.underscore
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -117,7 +117,7 @@
|
|
117
117
|
|
118
118
|
<!-- Form Fields -->
|
119
119
|
<% if @resource_class.has_form_tabs? %>
|
120
|
-
<%= EasyAdmin::FormTabsComponent.new(resource_class: @resource_class, form: form).call.html_safe %>
|
120
|
+
<%= EasyAdmin::FormTabsComponent.new(resource_class: @resource_class, form: form, record: @record).call.html_safe %>
|
121
121
|
<% else %>
|
122
122
|
<!-- Default Single Card Layout -->
|
123
123
|
<div class="bg-white shadow-sm rounded-lg border border-gray-200">
|
@@ -1,142 +1,8 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
<tr>
|
10
|
-
<% @resource_class.index_fields.each_with_index do |field, index| %>
|
11
|
-
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wide <%= 'mobile-hide' if index > 2 %>">
|
12
|
-
<% if field[:sortable] %>
|
13
|
-
<div class="flex items-center justify-between">
|
14
|
-
<%
|
15
|
-
# Determine next direction: if currently sorting by this field and direction is 'asc', toggle to 'desc'
|
16
|
-
# Otherwise default to 'asc' for new sort or when toggling from 'desc'
|
17
|
-
next_direction = (params[:sort] == field[:name].to_s && params[:direction] == 'asc') ? 'desc' : 'asc'
|
18
|
-
%>
|
19
|
-
<%= link_to url_for(request.params.merge(sort: field[:name], direction: next_direction)),
|
20
|
-
class: "group hover:text-gray-900 transition-colors duration-150" do %>
|
21
|
-
<%= field[:label] %>
|
22
|
-
<% end %>
|
23
|
-
<span class="ml-2 flex-none text-gray-400 hover:text-gray-600">
|
24
|
-
<% if params[:sort] == field[:name].to_s %>
|
25
|
-
<% if params[:direction] == 'asc' %>
|
26
|
-
<svg class="h-4 w-4" viewBox="0 0 20 20" fill="currentColor">
|
27
|
-
<path fill-rule="evenodd" d="M14.77 12.79a.75.75 0 01-1.06-.02L10 8.832 6.29 12.77a.75.75 0 11-1.08-1.04l4.25-4.5a.75.75 0 011.08 0l4.25 4.5a.75.75 0 01-.02 1.06z" clip-rule="evenodd"/>
|
28
|
-
</svg>
|
29
|
-
<% else %>
|
30
|
-
<svg class="h-4 w-4" viewBox="0 0 20 20" fill="currentColor">
|
31
|
-
<path fill-rule="evenodd" d="M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z" clip-rule="evenodd"/>
|
32
|
-
</svg>
|
33
|
-
<% end %>
|
34
|
-
<% else %>
|
35
|
-
<svg class="h-4 w-4" viewBox="0 0 20 20" fill="currentColor">
|
36
|
-
<path fill-rule="evenodd" d="M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z" clip-rule="evenodd"/>
|
37
|
-
</svg>
|
38
|
-
<% end %>
|
39
|
-
</span>
|
40
|
-
</div>
|
41
|
-
<% else %>
|
42
|
-
<%= field[:label] %>
|
43
|
-
<% end %>
|
44
|
-
</th>
|
45
|
-
<% end %>
|
46
|
-
<th scope="col" class="relative px-6 py-3">
|
47
|
-
<span class="sr-only">Actions</span>
|
48
|
-
</th>
|
49
|
-
</tr>
|
50
|
-
</thead>
|
51
|
-
<tbody id="records-container" class="divide-y divide-gray-200 bg-white">
|
52
|
-
<% @records.each do |record| %>
|
53
|
-
<tr class="hover:bg-gray-100 cursor-pointer transition-colors duration-150"
|
54
|
-
onclick="window.location='<%= easy_admin.resource_path(@resource_class.route_key, record) %>'">
|
55
|
-
<% @resource_class.index_fields.each_with_index do |field, index| %>
|
56
|
-
<td class="whitespace-nowrap px-6 py-4 text-sm <%= 'mobile-hide' if index > 2 %>">
|
57
|
-
<div class="text-gray-900 font-medium">
|
58
|
-
<%== render_field(field, action: :index, value: record.public_send(field[:name]), record: record) %>
|
59
|
-
</div>
|
60
|
-
</td>
|
61
|
-
<% end %>
|
62
|
-
<td class="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6">
|
63
|
-
<div class="flex items-center justify-end space-x-2 sm:mobile-actions">
|
64
|
-
<%= link_to easy_admin.resource_path(@resource_class.route_key, record),
|
65
|
-
class: "inline-flex items-center justify-center w-8 h-8 text-blue-600 hover:text-blue-800 hover:bg-blue-50 rounded-lg transition-colors duration-150",
|
66
|
-
onclick: "event.stopPropagation()",
|
67
|
-
title: "View" do %>
|
68
|
-
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
69
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/>
|
70
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"/>
|
71
|
-
</svg>
|
72
|
-
<% end %>
|
73
|
-
<%= link_to easy_admin.edit_resource_path(@resource_class.route_key, record),
|
74
|
-
class: "inline-flex items-center justify-center w-8 h-8 text-green-600 hover:text-green-800 hover:bg-green-50 rounded-lg transition-colors duration-150",
|
75
|
-
onclick: "event.stopPropagation()",
|
76
|
-
title: "Edit" do %>
|
77
|
-
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
78
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"/>
|
79
|
-
</svg>
|
80
|
-
<% end %>
|
81
|
-
<%= link_to easy_admin.resource_path(@resource_class.route_key, record),
|
82
|
-
method: :delete,
|
83
|
-
class: "inline-flex items-center justify-center w-8 h-8 text-red-600 hover:text-red-800 hover:bg-red-50 rounded-lg transition-colors duration-150",
|
84
|
-
onclick: "event.stopPropagation()",
|
85
|
-
title: "Delete",
|
86
|
-
data: {
|
87
|
-
confirm: "Are you sure you want to delete this #{@resource_class.singular_title.downcase}?",
|
88
|
-
method: :delete
|
89
|
-
} do %>
|
90
|
-
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
91
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/>
|
92
|
-
</svg>
|
93
|
-
<% end %>
|
94
|
-
</div>
|
95
|
-
</td>
|
96
|
-
</tr>
|
97
|
-
<% end %>
|
98
|
-
</tbody>
|
99
|
-
</table>
|
100
|
-
</div>
|
101
|
-
</div>
|
102
|
-
</div>
|
103
|
-
</div>
|
104
|
-
|
105
|
-
<!-- Pagination within the turbo frame -->
|
106
|
-
<div id="infinite-scroll-container">
|
107
|
-
<% if @resource_class.respond_to?(:infinite_scroll_enabled?) && @resource_class.infinite_scroll_enabled? %>
|
108
|
-
<%== EasyAdmin::InfiniteScrollComponent.new(
|
109
|
-
pagy: @pagy,
|
110
|
-
resource_class: @resource_class,
|
111
|
-
current_params: params.permit(:search, :scope, :sort, :direction, :period, :page, q: {}),
|
112
|
-
current_path: request.path
|
113
|
-
).call %>
|
114
|
-
<% else %>
|
115
|
-
<%== EasyAdmin::ResourcePaginationComponent.new(
|
116
|
-
pagy: @pagy,
|
117
|
-
resource_class: @resource_class,
|
118
|
-
request_params: params
|
119
|
-
).call %>
|
120
|
-
<% end %>
|
121
|
-
</div>
|
122
|
-
|
123
|
-
<!-- Empty state within the turbo frame -->
|
124
|
-
<% if @records.empty? && @pagy.page == 1 %>
|
125
|
-
<div class="text-center py-12">
|
126
|
-
<svg class="mx-auto h-12 w-12 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
127
|
-
<path vector-effect="non-scaling-stroke" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 13h6m-3-3v6m-9 1V7a2 2 0 012-2h6l2 2h6a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2z"/>
|
128
|
-
</svg>
|
129
|
-
<h3 class="mt-2 text-sm font-semibold text-gray-900">No <%= @resource_class.title.downcase %></h3>
|
130
|
-
<p class="mt-1 text-sm text-gray-500">Get started by creating a new <%= @resource_class.singular_title.downcase %>.</p>
|
131
|
-
<div class="mt-6">
|
132
|
-
<%= link_to easy_admin.new_resource_path(@resource_class.route_key),
|
133
|
-
class: "inline-flex items-center rounded-md bg-blue-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-blue-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600" do %>
|
134
|
-
<svg class="-ml-0.5 mr-1.5 h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
135
|
-
<path d="M10.75 4.75a.75.75 0 00-1.5 0v4.5h-4.5a.75.75 0 000 1.5h4.5v4.5a.75.75 0 001.5 0v-4.5h4.5a.75.75 0 000-1.5h-4.5v-4.5z"/>
|
136
|
-
</svg>
|
137
|
-
New <%= @resource_class.singular_title %>
|
138
|
-
<% end %>
|
139
|
-
</div>
|
140
|
-
</div>
|
141
|
-
<% end %>
|
142
|
-
</turbo-frame>
|
1
|
+
<%== EasyAdmin::Resources::IndexFrameComponent.new(
|
2
|
+
resource_class: @resource_class,
|
3
|
+
records: @records,
|
4
|
+
pagy: @pagy,
|
5
|
+
current_params: @current_params,
|
6
|
+
current_path: request.path,
|
7
|
+
current_user: current_admin_user
|
8
|
+
).call %>
|
@@ -0,0 +1,25 @@
|
|
1
|
+
<% if @success %>
|
2
|
+
<%= turbo_stream.replace "#{dom_id(@record)}_#{@association_name}" do %>
|
3
|
+
<%== EasyAdmin::Resources::TableCellComponent.new(
|
4
|
+
record: @record.reload,
|
5
|
+
field_config: @field_config,
|
6
|
+
resource_class: @resource_class
|
7
|
+
).call %>
|
8
|
+
<% end %>
|
9
|
+
|
10
|
+
<%= turbo_stream.update "notifications" do %>
|
11
|
+
<%== EasyAdmin::NotificationComponent.new(
|
12
|
+
type: :success,
|
13
|
+
message: "#{@field_config[:label]} updated successfully!",
|
14
|
+
title: "Success"
|
15
|
+
).call %>
|
16
|
+
<% end %>
|
17
|
+
<% else %>
|
18
|
+
<%= turbo_stream.update "notifications" do %>
|
19
|
+
<%== EasyAdmin::NotificationComponent.new(
|
20
|
+
type: :error,
|
21
|
+
message: @attached_record.errors.full_messages.join(', '),
|
22
|
+
title: "Error"
|
23
|
+
).call %>
|
24
|
+
<% end %>
|
25
|
+
<% end %>
|
@@ -20,11 +20,12 @@
|
|
20
20
|
</svg>
|
21
21
|
</button>
|
22
22
|
|
23
|
-
<%== EasyAdmin::SidebarComponent.new(current_path: request.path).call %>
|
23
|
+
<%== EasyAdmin::SidebarComponent.new(current_path: request.path, current_user: current_admin_user).call %>
|
24
24
|
|
25
25
|
<%== EasyAdmin::NavbarComponent.new(
|
26
26
|
page_title: content_for?(:page_title) ? yield(:page_title) : "Dashboard",
|
27
|
-
breadcrumbs: content_for?(:breadcrumbs) ? yield(:breadcrumbs) : nil
|
27
|
+
breadcrumbs: content_for?(:breadcrumbs) ? yield(:breadcrumbs) : nil,
|
28
|
+
current_user: current_admin_user
|
28
29
|
).call %>
|
29
30
|
|
30
31
|
<main class="flex-1 overflow-x-hidden overflow-y-auto bg-gray-50 lg:ml-64 transition-all duration-300" data-sidebar-target="content">
|
@@ -33,6 +34,18 @@
|
|
33
34
|
</div>
|
34
35
|
</main>
|
35
36
|
|
37
|
+
<!-- Flash Messages -->
|
38
|
+
<% if flash.any? %>
|
39
|
+
<% flash.each do |type, message| %>
|
40
|
+
<% next if message.blank? %>
|
41
|
+
<%== EasyAdmin::NotificationComponent.new(
|
42
|
+
type: flash_type_to_notification_type(type),
|
43
|
+
message: message,
|
44
|
+
duration: 6000
|
45
|
+
).call %>
|
46
|
+
<% end %>
|
47
|
+
<% end %>
|
48
|
+
|
36
49
|
<!-- Notifications Turbo Frame -->
|
37
50
|
<turbo-frame id="notifications"></turbo-frame>
|
38
51
|
|
@@ -0,0 +1,73 @@
|
|
1
|
+
EasyAdmin::Permissions.configure do |config|
|
2
|
+
# Enable the permissions system
|
3
|
+
config.enabled = true
|
4
|
+
|
5
|
+
# Cache duration for permission lookups (default: 1 hour)
|
6
|
+
config.cache_duration = 1.hour
|
7
|
+
|
8
|
+
# Allow admin users to bypass permissions (default: true)
|
9
|
+
config.admin_bypass = true
|
10
|
+
|
11
|
+
# Set the user model class name (default: 'User')
|
12
|
+
config.user_class 'EasyAdmin::AdminUser'
|
13
|
+
|
14
|
+
# Define permission contexts (optional - for scoped permissions)
|
15
|
+
|
16
|
+
# config.contexts :organization, :project
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
# Define your permissions here
|
21
|
+
# Note: This will only run if the database tables exist
|
22
|
+
if ActiveRecord::Base.connection.table_exists?(:easy_admin_permissions)
|
23
|
+
EasyAdmin::Permissions.define do
|
24
|
+
# Dashboard permissions
|
25
|
+
permission :dashboard, :view, description: "Access admin dashboard"
|
26
|
+
|
27
|
+
# Admin user management permissions
|
28
|
+
resource :admin_users, actions: [:read, :create, :update, :delete]
|
29
|
+
permission :admin_users, :manage_roles, description: "Assign and remove user roles"
|
30
|
+
|
31
|
+
# Reports permissions
|
32
|
+
permission :reports, :view, description: "View reports"
|
33
|
+
permission :reports, :export, description: "Export reports"
|
34
|
+
|
35
|
+
# Settings permissions
|
36
|
+
permission :settings, :read, description: "View system settings"
|
37
|
+
permission :settings, :update, description: "Update system settings"
|
38
|
+
|
39
|
+
# Role definitions
|
40
|
+
role :super_admin,
|
41
|
+
description: "Full system access",
|
42
|
+
permissions: %w[
|
43
|
+
dashboard:view admin_users:read admin_users:create admin_users:update
|
44
|
+
admin_users:delete admin_users:manage_roles reports:view reports:export
|
45
|
+
settings:read settings:update
|
46
|
+
]
|
47
|
+
|
48
|
+
role :admin,
|
49
|
+
description: "Administrative access with user management",
|
50
|
+
permissions: %w[
|
51
|
+
dashboard:view admin_users:read admin_users:create admin_users:update
|
52
|
+
admin_users:manage_roles reports:view reports:export settings:read
|
53
|
+
]
|
54
|
+
|
55
|
+
role :manager,
|
56
|
+
description: "Management access with limited user permissions",
|
57
|
+
permissions: %w[
|
58
|
+
dashboard:view admin_users:read admin_users:update reports:view reports:export
|
59
|
+
]
|
60
|
+
|
61
|
+
role :editor,
|
62
|
+
description: "Content editing permissions",
|
63
|
+
permissions: %w[
|
64
|
+
dashboard:view admin_users:read
|
65
|
+
]
|
66
|
+
|
67
|
+
role :viewer,
|
68
|
+
description: "Read-only access",
|
69
|
+
permissions: %w[
|
70
|
+
dashboard:view admin_users:read reports:view
|
71
|
+
]
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
# EasyAdmin Permission System Seeds
|
2
|
+
# Load these seeds after running: rails easy_admin:permissions:install
|
3
|
+
|
4
|
+
puts "🔐 Setting up EasyAdmin Permission System..."
|
5
|
+
|
6
|
+
# Create basic permissions
|
7
|
+
permissions_data = [
|
8
|
+
# Dashboard permissions
|
9
|
+
{ name: "dashboard:view", resource_type: "dashboard", action: "view", description: "Access admin dashboard" },
|
10
|
+
|
11
|
+
# User management permissions
|
12
|
+
{ name: "admin_users:read", resource_type: "admin_users", action: "read", description: "View admin users" },
|
13
|
+
{ name: "admin_users:create", resource_type: "admin_users", action: "create", description: "Create new admin users" },
|
14
|
+
{ name: "admin_users:update", resource_type: "admin_users", action: "update", description: "Edit existing admin users" },
|
15
|
+
{ name: "admin_users:delete", resource_type: "admin_users", action: "delete", description: "Delete admin users" },
|
16
|
+
{ name: "admin_users:manage_roles", resource_type: "admin_users", action: "manage_roles", description: "Assign and remove user roles" },
|
17
|
+
|
18
|
+
# Reports permissions
|
19
|
+
{ name: "reports:view", resource_type: "reports", action: "view", description: "View reports" },
|
20
|
+
{ name: "reports:export", resource_type: "reports", action: "export", description: "Export reports" },
|
21
|
+
|
22
|
+
# Settings permissions
|
23
|
+
{ name: "settings:read", resource_type: "settings", action: "read", description: "View system settings" },
|
24
|
+
{ name: "settings:update", resource_type: "settings", action: "update", description: "Update system settings" }
|
25
|
+
]
|
26
|
+
|
27
|
+
puts " Creating permissions..."
|
28
|
+
permissions = {}
|
29
|
+
permissions_data.each do |perm_data|
|
30
|
+
permission = EasyAdmin::Permissions::Permission.find_or_create_by(name: perm_data[:name]) do |p|
|
31
|
+
p.resource_type = perm_data[:resource_type]
|
32
|
+
p.action = perm_data[:action]
|
33
|
+
p.description = perm_data[:description]
|
34
|
+
end
|
35
|
+
permissions[perm_data[:name]] = permission
|
36
|
+
puts " ✓ #{perm_data[:name]}"
|
37
|
+
end
|
38
|
+
|
39
|
+
# Create roles
|
40
|
+
roles_data = [
|
41
|
+
{
|
42
|
+
name: "Super Admin",
|
43
|
+
slug: "super_admin",
|
44
|
+
description: "Full system access - all permissions",
|
45
|
+
permissions: permissions.keys
|
46
|
+
},
|
47
|
+
{
|
48
|
+
name: "Admin",
|
49
|
+
slug: "admin",
|
50
|
+
description: "Administrative access with user management",
|
51
|
+
permissions: [
|
52
|
+
"dashboard:view", "admin_users:read", "admin_users:create", "admin_users:update", "admin_users:manage_roles",
|
53
|
+
"reports:view", "reports:export", "settings:read"
|
54
|
+
]
|
55
|
+
},
|
56
|
+
{
|
57
|
+
name: "Manager",
|
58
|
+
slug: "manager",
|
59
|
+
description: "Management access with limited user permissions",
|
60
|
+
permissions: [
|
61
|
+
"dashboard:view", "admin_users:read", "admin_users:update", "reports:view", "reports:export"
|
62
|
+
]
|
63
|
+
},
|
64
|
+
{
|
65
|
+
name: "Editor",
|
66
|
+
slug: "editor",
|
67
|
+
description: "Content editing permissions",
|
68
|
+
permissions: [
|
69
|
+
"dashboard:view", "admin_users:read"
|
70
|
+
]
|
71
|
+
},
|
72
|
+
{
|
73
|
+
name: "Viewer",
|
74
|
+
slug: "viewer",
|
75
|
+
description: "Read-only access",
|
76
|
+
permissions: [
|
77
|
+
"dashboard:view", "admin_users:read", "reports:view"
|
78
|
+
]
|
79
|
+
}
|
80
|
+
]
|
81
|
+
|
82
|
+
puts " Creating roles..."
|
83
|
+
roles_data.each do |role_data|
|
84
|
+
role = EasyAdmin::Permissions::Role.find_or_create_by(slug: role_data[:slug]) do |r|
|
85
|
+
r.name = role_data[:name]
|
86
|
+
r.description = role_data[:description]
|
87
|
+
r.active = true
|
88
|
+
end
|
89
|
+
|
90
|
+
# Assign permissions to role
|
91
|
+
role_data[:permissions].each do |permission_name|
|
92
|
+
permission = permissions[permission_name]
|
93
|
+
if permission
|
94
|
+
EasyAdmin::Permissions::RolePermission.find_or_create_by(
|
95
|
+
role: role,
|
96
|
+
permission: permission
|
97
|
+
)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
puts " ✓ #{role_data[:name]} (#{role.permissions.count} permissions)"
|
102
|
+
end
|
103
|
+
|
104
|
+
# Assign super admin role to the first admin user
|
105
|
+
if EasyAdmin::AdminUser.exists?
|
106
|
+
first_admin = EasyAdmin::AdminUser.first
|
107
|
+
super_admin_role = EasyAdmin::Permissions::Role.find_by(slug: "super_admin")
|
108
|
+
|
109
|
+
if first_admin && super_admin_role
|
110
|
+
first_admin.assign_role(super_admin_role)
|
111
|
+
puts " ✓ Assigned Super Admin role to #{first_admin.email}"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
puts "✅ EasyAdmin Permission System setup complete!"
|
116
|
+
puts ""
|
117
|
+
puts "Next steps:"
|
118
|
+
puts "1. Configure permissions in config/initializers/easy_admin_permissions.rb"
|
119
|
+
puts "2. Assign roles to users: admin_user.assign_role(:admin)"
|
120
|
+
puts "3. Check permissions: admin_user.has_permission?('admin_users:read')"
|
121
|
+
puts ""
|
data/lib/easy-admin-rails.rb
CHANGED
@@ -5,6 +5,7 @@ require "easy_admin/version"
|
|
5
5
|
require "easy_admin/configuration"
|
6
6
|
require "easy_admin/resource_registry"
|
7
7
|
require "easy_admin/versioning"
|
8
|
+
require "easy_admin/resource_modules"
|
8
9
|
require "easy_admin/resource"
|
9
10
|
require "easy_admin/dashboard_registry"
|
10
11
|
require "easy_admin/dashboard"
|
@@ -12,6 +13,7 @@ require "easy_admin/field"
|
|
12
13
|
require "easy_admin/action"
|
13
14
|
require "easy_admin/delete_action"
|
14
15
|
require "easy_admin/batch_action"
|
16
|
+
require "easy_admin/permissions"
|
15
17
|
require "easy_admin/engine"
|
16
18
|
|
17
19
|
module EasyAdmin
|