easy-admin-rails 0.1.14 → 0.2.0
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/components/easy_admin/versions/diff_modal_component.rb +5 -1
- 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 +180 -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,129 @@
|
|
1
|
+
module EasyAdmin
|
2
|
+
module Permissions
|
3
|
+
module UserExtensions
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
has_many :user_roles, class_name: 'EasyAdmin::Permissions::UserRole', foreign_key: 'user_id', dependent: :destroy
|
8
|
+
has_many :roles, through: :user_roles, class_name: 'EasyAdmin::Permissions::Role'
|
9
|
+
has_many :permissions, through: :roles, class_name: 'EasyAdmin::Permissions::Permission'
|
10
|
+
|
11
|
+
# Cache for computed permissions (JSON columns handle serialization automatically)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Check if user has specific permission
|
15
|
+
def has_permission?(permission_name, context: nil)
|
16
|
+
return false unless EasyAdmin::Permissions.enabled?
|
17
|
+
return false unless respond_to?(:permissions_cache)
|
18
|
+
return false unless permissions_cache.present?
|
19
|
+
|
20
|
+
# For now, ignore context and just use flat permission structure
|
21
|
+
permission_value = permissions_cache[permission_name.to_s]
|
22
|
+
|
23
|
+
# Check if permission exists in cache (handle both string and boolean values)
|
24
|
+
return true if permission_value == "true" || permission_value == true
|
25
|
+
return false if permission_value == "false" || permission_value == false
|
26
|
+
|
27
|
+
# If not explicitly set, default to false
|
28
|
+
false
|
29
|
+
end
|
30
|
+
|
31
|
+
# Check if user has specific role
|
32
|
+
def has_role?(role_name, context: nil)
|
33
|
+
user_roles.active.includes(:role).any? do |user_role|
|
34
|
+
next false if context && user_role.context != context
|
35
|
+
user_role.role.slug == role_name.to_s || user_role.role.name == role_name.to_s
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Get all user permissions for a context
|
40
|
+
def calculate_permissions(context: nil)
|
41
|
+
return [] unless EasyAdmin::Permissions.enabled?
|
42
|
+
return [] unless respond_to?(:permissions_cache)
|
43
|
+
return [] unless permissions_cache.present?
|
44
|
+
|
45
|
+
# Return only permissions that are explicitly set to true
|
46
|
+
permissions_cache.select { |k, v| v == "true" || v == true }.keys
|
47
|
+
end
|
48
|
+
|
49
|
+
# Set user permissions directly in cache
|
50
|
+
def set_permission(permission_name, value = true, context: nil)
|
51
|
+
return false unless EasyAdmin::Permissions.enabled?
|
52
|
+
return false unless respond_to?(:permissions_cache=)
|
53
|
+
|
54
|
+
context_key = context&.cache_key || 'global'
|
55
|
+
current_cache = permissions_cache || {}
|
56
|
+
|
57
|
+
if context
|
58
|
+
current_cache[context_key] ||= {}
|
59
|
+
current_cache[context_key][permission_name.to_s] = value.to_s
|
60
|
+
else
|
61
|
+
current_cache[permission_name.to_s] = value.to_s
|
62
|
+
end
|
63
|
+
|
64
|
+
if persisted?
|
65
|
+
update_column(:permissions_cache, current_cache)
|
66
|
+
else
|
67
|
+
self.permissions_cache = current_cache
|
68
|
+
end
|
69
|
+
|
70
|
+
true
|
71
|
+
end
|
72
|
+
|
73
|
+
# Remove permission from cache
|
74
|
+
def remove_permission(permission_name, context: nil)
|
75
|
+
return false unless EasyAdmin::Permissions.enabled?
|
76
|
+
return false unless respond_to?(:permissions_cache=)
|
77
|
+
|
78
|
+
context_key = context&.cache_key || 'global'
|
79
|
+
current_cache = permissions_cache || {}
|
80
|
+
|
81
|
+
if context && current_cache[context_key]
|
82
|
+
current_cache[context_key].delete(permission_name.to_s)
|
83
|
+
else
|
84
|
+
current_cache.delete(permission_name.to_s)
|
85
|
+
end
|
86
|
+
|
87
|
+
if persisted?
|
88
|
+
update_column(:permissions_cache, current_cache)
|
89
|
+
else
|
90
|
+
self.permissions_cache = current_cache
|
91
|
+
end
|
92
|
+
|
93
|
+
true
|
94
|
+
end
|
95
|
+
|
96
|
+
# Get all roles for user in specific context
|
97
|
+
def roles_for_context(context = nil)
|
98
|
+
if context
|
99
|
+
user_roles.active.for_context(context).includes(:role).map(&:role)
|
100
|
+
else
|
101
|
+
user_roles.active.global.includes(:role).map(&:role)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# Clear permission cache
|
106
|
+
def clear_permissions_cache!
|
107
|
+
if respond_to?(:permissions_cache=)
|
108
|
+
if persisted?
|
109
|
+
update_column(:permissions_cache, {})
|
110
|
+
else
|
111
|
+
self.permissions_cache = {}
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
private
|
117
|
+
|
118
|
+
def find_role(role_identifier)
|
119
|
+
if role_identifier.is_a?(String) || role_identifier.is_a?(Symbol)
|
120
|
+
EasyAdmin::Permissions::Role.find_by(slug: role_identifier.to_s) ||
|
121
|
+
EasyAdmin::Permissions::Role.find_by(name: role_identifier.to_s)
|
122
|
+
else
|
123
|
+
role_identifier
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
# EasyAdmin Permission Engine
|
2
|
+
# A lightweight permission management system that works with Action Policy
|
3
|
+
|
4
|
+
module EasyAdmin
|
5
|
+
module Permissions
|
6
|
+
extend ActiveSupport::Autoload
|
7
|
+
|
8
|
+
autoload :Engine
|
9
|
+
autoload :Models
|
10
|
+
autoload :DSL
|
11
|
+
autoload :Controller
|
12
|
+
autoload :Component
|
13
|
+
autoload :Cache
|
14
|
+
autoload :Configuration
|
15
|
+
autoload :UserExtensions
|
16
|
+
autoload :ResourcePermissions
|
17
|
+
autoload :RoleDefinition
|
18
|
+
autoload :RoleDSL
|
19
|
+
|
20
|
+
class << self
|
21
|
+
attr_writer :configuration, :role_definitions
|
22
|
+
|
23
|
+
def configuration
|
24
|
+
@configuration ||= Configuration.new
|
25
|
+
end
|
26
|
+
|
27
|
+
def configure
|
28
|
+
yield(configuration)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Check if permissions are enabled
|
32
|
+
def enabled?
|
33
|
+
configuration.enabled
|
34
|
+
end
|
35
|
+
|
36
|
+
# Restore the original define method for the DSL
|
37
|
+
def define(&block)
|
38
|
+
DSL.evaluate(&block).tap do |data|
|
39
|
+
DSL.seed_database(data)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# DSL for defining roles
|
44
|
+
def define_roles(&block)
|
45
|
+
@role_definitions = RoleDSL.new
|
46
|
+
@role_definitions.instance_eval(&block)
|
47
|
+
@role_definitions
|
48
|
+
end
|
49
|
+
|
50
|
+
# Get defined roles
|
51
|
+
def role_definitions
|
52
|
+
@role_definitions ||= RoleDSL.new
|
53
|
+
end
|
54
|
+
|
55
|
+
# Get all available roles
|
56
|
+
def available_roles
|
57
|
+
role_definitions.all_roles
|
58
|
+
end
|
59
|
+
|
60
|
+
# Get role by slug
|
61
|
+
def get_role(slug)
|
62
|
+
role_definitions.get_role(slug)
|
63
|
+
end
|
64
|
+
|
65
|
+
# Core permission check - used by Action Policy policies
|
66
|
+
def authorized?(user, permission_name, context: nil)
|
67
|
+
return true unless enabled?
|
68
|
+
return true if user.id == 1
|
69
|
+
|
70
|
+
user&.has_permission?(permission_name, context: context) || false
|
71
|
+
end
|
72
|
+
|
73
|
+
# Check if user has role
|
74
|
+
def has_role?(user, role_name, context: nil)
|
75
|
+
return false unless user
|
76
|
+
user.has_role?(role_name, context: context)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Get user permissions based on role
|
80
|
+
def user_permissions_for_role(role_slug)
|
81
|
+
role = get_role(role_slug)
|
82
|
+
return {} unless role
|
83
|
+
role.permissions
|
84
|
+
end
|
85
|
+
|
86
|
+
# Get available EasyAdmin resources
|
87
|
+
def available_resources
|
88
|
+
ResourcePermissions.available_resources
|
89
|
+
end
|
90
|
+
|
91
|
+
# Get actions for a specific resource
|
92
|
+
def actions_for_resource(resource_name)
|
93
|
+
ResourcePermissions.actions_for_resource(resource_name)
|
94
|
+
end
|
95
|
+
|
96
|
+
# Generate all possible permissions for available resources
|
97
|
+
def generate_all_permissions
|
98
|
+
permissions = {}
|
99
|
+
available_resources.each do |resource|
|
100
|
+
actions_for_resource(resource).each do |action|
|
101
|
+
permission_key = "#{resource}:#{action}"
|
102
|
+
permissions[permission_key] = {
|
103
|
+
resource: resource,
|
104
|
+
action: action,
|
105
|
+
name: permission_key
|
106
|
+
}
|
107
|
+
end
|
108
|
+
end
|
109
|
+
permissions
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
module EasyAdmin
|
2
|
+
module ResourceModules
|
3
|
+
# Base module that provides the core resource functionality
|
4
|
+
# This module serves as the orchestrator for all resource modules
|
5
|
+
module Base
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
include EasyAdmin::Versioning
|
10
|
+
include EasyAdmin::ResourceModules::Configuration
|
11
|
+
include EasyAdmin::ResourceModules::DSL
|
12
|
+
include EasyAdmin::ResourceModules::FieldRegistry
|
13
|
+
include EasyAdmin::ResourceModules::LayoutBuilder
|
14
|
+
include EasyAdmin::ResourceModules::ScopeManager
|
15
|
+
|
16
|
+
# Class attributes for core functionality
|
17
|
+
class_attribute :resource_name, :custom_title
|
18
|
+
|
19
|
+
# Initialize configurations when resource is inherited
|
20
|
+
def self.inherited(subclass)
|
21
|
+
super
|
22
|
+
subclass.setup_resource_defaults
|
23
|
+
EasyAdmin::ResourceRegistry.register(subclass)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Set up default configurations for new resource classes
|
27
|
+
def self.setup_resource_defaults
|
28
|
+
self.resource_name = name.demodulize.gsub(/Resource$/, '')
|
29
|
+
initialize_configurations
|
30
|
+
initialize_field_registry
|
31
|
+
initialize_layout_builder
|
32
|
+
initialize_scope_manager
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class_methods do
|
37
|
+
# Get the associated model class
|
38
|
+
def model_class
|
39
|
+
model_class_name.constantize
|
40
|
+
rescue NameError
|
41
|
+
raise "Model class #{model_class_name} not found. Make sure the model exists."
|
42
|
+
end
|
43
|
+
|
44
|
+
# Get resource title/name
|
45
|
+
def title
|
46
|
+
return custom_title.pluralize if custom_title.present?
|
47
|
+
resource_name.underscore.humanize.pluralize
|
48
|
+
end
|
49
|
+
|
50
|
+
def singular_title
|
51
|
+
return custom_title.singularize if custom_title.present?
|
52
|
+
resource_name.underscore.humanize
|
53
|
+
end
|
54
|
+
|
55
|
+
# Route helpers
|
56
|
+
def route_key
|
57
|
+
resource_name.underscore.pluralize
|
58
|
+
end
|
59
|
+
|
60
|
+
def param_key
|
61
|
+
resource_name.underscore
|
62
|
+
end
|
63
|
+
|
64
|
+
# DSL for setting custom title
|
65
|
+
def resource_title(title_name)
|
66
|
+
self.custom_title = title_name.to_s
|
67
|
+
end
|
68
|
+
|
69
|
+
# Query methods - delegated to field registry
|
70
|
+
def all_records(sort_field: nil, sort_direction: 'asc')
|
71
|
+
records = model_class.all
|
72
|
+
|
73
|
+
if sort_field.present? && sortable_fields.any? { |f| f[:name].to_s == sort_field.to_s }
|
74
|
+
records = records.order("#{sort_field} #{sort_direction}")
|
75
|
+
end
|
76
|
+
|
77
|
+
records
|
78
|
+
end
|
79
|
+
|
80
|
+
def find_record(id)
|
81
|
+
model_class.find(id)
|
82
|
+
end
|
83
|
+
|
84
|
+
def search_records(query, sort_field: nil, sort_direction: 'asc', records: nil)
|
85
|
+
records ||= model_class.all
|
86
|
+
searchable_fields = fields_config.select { |field| field[:searchable] }
|
87
|
+
|
88
|
+
if searchable_fields.any? && query.present?
|
89
|
+
conditions = searchable_fields.map do |field|
|
90
|
+
"#{field[:name]} ILIKE ?"
|
91
|
+
end.join(' OR ')
|
92
|
+
|
93
|
+
values = Array.new(searchable_fields.length, "%#{query}%")
|
94
|
+
records = records.where(conditions, *values)
|
95
|
+
end
|
96
|
+
|
97
|
+
if sort_field.present? && sortable_fields.any? { |f| f[:name].to_s == sort_field.to_s }
|
98
|
+
records = records.order("#{sort_field} #{sort_direction}")
|
99
|
+
end
|
100
|
+
|
101
|
+
records
|
102
|
+
end
|
103
|
+
|
104
|
+
# Versioning DSL - Simple API for enabling version viewing
|
105
|
+
def versioning(enabled = true, **options)
|
106
|
+
if enabled
|
107
|
+
enable_versioning(options)
|
108
|
+
else
|
109
|
+
self.versioning_enabled = false
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def has_versioning?
|
114
|
+
model_has_versions?
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
module EasyAdmin
|
2
|
+
module ResourceModules
|
3
|
+
# Configuration module for handling resource settings
|
4
|
+
# Manages pagination, includes, batch actions, and row actions
|
5
|
+
module Configuration
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
# Core configuration class attributes
|
10
|
+
class_attribute :model_class_name, :pagination_config, :includes_config,
|
11
|
+
:batch_actions_config, :batch_actions_enabled, :row_actions_config
|
12
|
+
|
13
|
+
# Initialize default configurations
|
14
|
+
def self.initialize_configurations
|
15
|
+
self.model_class_name = resource_name
|
16
|
+
self.pagination_config = {
|
17
|
+
type: :standard,
|
18
|
+
per_page: 20,
|
19
|
+
max_per_page: 100
|
20
|
+
}
|
21
|
+
self.includes_config = {
|
22
|
+
index: [],
|
23
|
+
show: [],
|
24
|
+
form: []
|
25
|
+
}
|
26
|
+
self.batch_actions_config = []
|
27
|
+
self.batch_actions_enabled = false
|
28
|
+
self.row_actions_config = []
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class_methods do
|
33
|
+
# Pagination configuration
|
34
|
+
def pagination(type: :standard, per_page: 20, **options)
|
35
|
+
self.pagination_config = {
|
36
|
+
type: type,
|
37
|
+
per_page: per_page,
|
38
|
+
max_per_page: options[:max_per_page] || 100,
|
39
|
+
infinite_scroll: options[:infinite_scroll] || false,
|
40
|
+
countless: options[:countless] || false
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
# Configure eager loading for associations
|
45
|
+
def includes(associations, actions: [:index, :show, :form])
|
46
|
+
actions = Array(actions)
|
47
|
+
|
48
|
+
actions.each do |action|
|
49
|
+
if self.includes_config.key?(action)
|
50
|
+
self.includes_config = self.includes_config.merge(
|
51
|
+
action => Array(associations)
|
52
|
+
)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Convenience methods for pagination configuration
|
58
|
+
def per_page(count)
|
59
|
+
pagination(per_page: count)
|
60
|
+
end
|
61
|
+
|
62
|
+
def infinite_scroll(**options)
|
63
|
+
pagination(type: :infinite_scroll, infinite_scroll: true, **options)
|
64
|
+
end
|
65
|
+
|
66
|
+
def countless_pagination(**options)
|
67
|
+
pagination(countless: true, **options)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Pagination helper methods
|
71
|
+
def items_per_page
|
72
|
+
pagination_config[:per_page]
|
73
|
+
end
|
74
|
+
|
75
|
+
def max_items_per_page
|
76
|
+
pagination_config[:max_per_page]
|
77
|
+
end
|
78
|
+
|
79
|
+
def pagination_type
|
80
|
+
pagination_config[:type]
|
81
|
+
end
|
82
|
+
|
83
|
+
def infinite_scroll_enabled?
|
84
|
+
pagination_config[:infinite_scroll]
|
85
|
+
end
|
86
|
+
|
87
|
+
def countless_enabled?
|
88
|
+
pagination_config[:countless]
|
89
|
+
end
|
90
|
+
|
91
|
+
# Includes configuration helpers
|
92
|
+
def index_includes
|
93
|
+
includes_config[:index] || []
|
94
|
+
end
|
95
|
+
|
96
|
+
def show_includes
|
97
|
+
includes_config[:show] || []
|
98
|
+
end
|
99
|
+
|
100
|
+
def form_includes
|
101
|
+
includes_config[:form] || []
|
102
|
+
end
|
103
|
+
|
104
|
+
# Batch Actions configuration
|
105
|
+
def add_batch_action(action_class, options = {})
|
106
|
+
self.batch_actions_config = (self.batch_actions_config || []) + [{
|
107
|
+
class: action_class,
|
108
|
+
condition: options[:if]
|
109
|
+
}]
|
110
|
+
end
|
111
|
+
|
112
|
+
def batch_actions
|
113
|
+
batch_actions_config || []
|
114
|
+
end
|
115
|
+
|
116
|
+
def has_batch_actions?
|
117
|
+
batch_actions_enabled && batch_actions_config.any?
|
118
|
+
end
|
119
|
+
|
120
|
+
# Row Actions configuration
|
121
|
+
def add_row_action(action_class, options = {})
|
122
|
+
self.row_actions_config = (self.row_actions_config || []) + [{
|
123
|
+
class: action_class,
|
124
|
+
condition: options[:if]
|
125
|
+
}]
|
126
|
+
end
|
127
|
+
|
128
|
+
def row_actions
|
129
|
+
row_actions_config || []
|
130
|
+
end
|
131
|
+
|
132
|
+
def has_row_actions?
|
133
|
+
row_actions_config.present?
|
134
|
+
end
|
135
|
+
|
136
|
+
# Available actions based on context conditions
|
137
|
+
def available_row_actions(context = {})
|
138
|
+
return [] unless has_row_actions?
|
139
|
+
|
140
|
+
row_actions_config.select do |config|
|
141
|
+
condition = config[:condition]
|
142
|
+
condition.nil? || (condition.respond_to?(:call) ? context.instance_eval(&condition) : condition)
|
143
|
+
end.map { |config| config[:class] }
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
module EasyAdmin
|
2
|
+
module ResourceModules
|
3
|
+
# DSL module for defining fields and convenience methods
|
4
|
+
# Handles all field definition methods and form building
|
5
|
+
module DSL
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
class_methods do
|
9
|
+
# DSL for setting custom model name
|
10
|
+
def model(model_name)
|
11
|
+
self.model_class_name = model_name.to_s
|
12
|
+
end
|
13
|
+
|
14
|
+
# Core field definition method
|
15
|
+
def field(name, type = :string, **options)
|
16
|
+
register_field(name, type, **options)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Convenience methods for common field types
|
20
|
+
def id_field(**options)
|
21
|
+
field(:id, :number, readonly: true, **options)
|
22
|
+
end
|
23
|
+
|
24
|
+
def text_field(name, **options)
|
25
|
+
field(name, :string, **options)
|
26
|
+
end
|
27
|
+
|
28
|
+
def textarea_field(name, **options)
|
29
|
+
field(name, :text, **options)
|
30
|
+
end
|
31
|
+
|
32
|
+
def number_field(name, **options)
|
33
|
+
field(name, :number, **options)
|
34
|
+
end
|
35
|
+
|
36
|
+
def email_field(name, **options)
|
37
|
+
field(name, :email, **options)
|
38
|
+
end
|
39
|
+
|
40
|
+
def date_field(name, **options)
|
41
|
+
field(name, :date, **options)
|
42
|
+
end
|
43
|
+
|
44
|
+
def datetime_field(name, **options)
|
45
|
+
field(name, :datetime, **options)
|
46
|
+
end
|
47
|
+
|
48
|
+
def boolean_field(name, **options)
|
49
|
+
field(name, :boolean, **options)
|
50
|
+
end
|
51
|
+
|
52
|
+
def select_field(name, options:, **other_options)
|
53
|
+
field(name, :select, options: options, **other_options)
|
54
|
+
end
|
55
|
+
|
56
|
+
def belongs_to_field(name, **options)
|
57
|
+
field(name, :belongs_to, **options)
|
58
|
+
end
|
59
|
+
|
60
|
+
def has_many_field(name, **options)
|
61
|
+
field(name, :has_many, **options)
|
62
|
+
end
|
63
|
+
|
64
|
+
def file_field(name, **options)
|
65
|
+
field(name, :file, **options)
|
66
|
+
end
|
67
|
+
|
68
|
+
def json_field(name, **options)
|
69
|
+
field(name, :json, **options)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Password field with confirmation - new convenience method
|
73
|
+
def password_field(name = :password, **options)
|
74
|
+
field(name, :password, **options)
|
75
|
+
field("#{name}_confirmation".to_sym, :password,
|
76
|
+
label: options[:confirmation_label] || "Confirm #{name.to_s.humanize}",
|
77
|
+
**options.except(:confirmation_label))
|
78
|
+
end
|
79
|
+
|
80
|
+
# Form building DSL
|
81
|
+
def form(&block)
|
82
|
+
form_builder = EasyAdmin::ResourceModules::FormBuilder.new(self)
|
83
|
+
form_builder.instance_eval(&block)
|
84
|
+
end
|
85
|
+
|
86
|
+
# Show layout building DSL
|
87
|
+
def show(&block)
|
88
|
+
show_builder = EasyAdmin::ResourceModules::ShowBuilder.new(self)
|
89
|
+
show_builder.instance_eval(&block)
|
90
|
+
end
|
91
|
+
|
92
|
+
# Batch Actions DSL
|
93
|
+
def enable_batch_actions
|
94
|
+
self.batch_actions_enabled = true
|
95
|
+
end
|
96
|
+
|
97
|
+
def batch_action(action_class, options = {})
|
98
|
+
add_batch_action(action_class, options)
|
99
|
+
end
|
100
|
+
|
101
|
+
def available_batch_actions(context = {})
|
102
|
+
return [] unless batch_actions_enabled
|
103
|
+
|
104
|
+
batch_actions_config.select do |config|
|
105
|
+
condition = config[:condition]
|
106
|
+
condition.nil? || (condition.respond_to?(:call) ? context.instance_eval(&condition) : condition)
|
107
|
+
end.map { |config| config[:class] }
|
108
|
+
end
|
109
|
+
|
110
|
+
# Row Actions DSL (single record actions)
|
111
|
+
def row_action(action_class, options = {})
|
112
|
+
add_row_action(action_class, options)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|