easy-admin-rails 0.1.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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +28 -0
- data/Rakefile +8 -0
- data/app/assets/builds/easy_admin.base.js +43505 -0
- data/app/assets/builds/easy_admin.base.js.map +7 -0
- data/app/assets/builds/easy_admin.css +6141 -0
- data/app/assets/config/easy_admin_manifest.js +1 -0
- data/app/assets/images/jsoneditor-icons.svg +749 -0
- data/app/assets/stylesheets/easy_admin/application.tailwind.css +390 -0
- data/app/components/easy_admin/base_component.rb +35 -0
- data/app/components/easy_admin/batch_action_bar_component.rb +125 -0
- data/app/components/easy_admin/batch_action_form_component.rb +124 -0
- data/app/components/easy_admin/combined_filters_component.rb +232 -0
- data/app/components/easy_admin/confirmation_modal_component.rb +61 -0
- data/app/components/easy_admin/context_menu_component.rb +161 -0
- data/app/components/easy_admin/dashboards/base_card_component.rb +152 -0
- data/app/components/easy_admin/dashboards/card_error_component.rb +23 -0
- data/app/components/easy_admin/dashboards/card_factory.rb +90 -0
- data/app/components/easy_admin/dashboards/card_stream_component.rb +22 -0
- data/app/components/easy_admin/dashboards/cards/base_card_component.rb +54 -0
- data/app/components/easy_admin/dashboards/cards/chart_card_component.rb +175 -0
- data/app/components/easy_admin/dashboards/cards/custom_card_component.rb +50 -0
- data/app/components/easy_admin/dashboards/cards/metric_card_component.rb +164 -0
- data/app/components/easy_admin/dashboards/cards/table_card_component.rb +148 -0
- data/app/components/easy_admin/dashboards/chart_card_component.rb +44 -0
- data/app/components/easy_admin/dashboards/metric_card_component.rb +56 -0
- data/app/components/easy_admin/dashboards/refresh_stream_component.rb +279 -0
- data/app/components/easy_admin/dashboards/show_component.rb +163 -0
- data/app/components/easy_admin/dashboards/table_card_component.rb +52 -0
- data/app/components/easy_admin/date_picker_component.rb +188 -0
- data/app/components/easy_admin/fields/base_component.rb +101 -0
- data/app/components/easy_admin/fields/belongs_to_edit_modal_component.rb +117 -0
- data/app/components/easy_admin/fields/form/belongs_to_component.rb +82 -0
- data/app/components/easy_admin/fields/form/boolean_component.rb +100 -0
- data/app/components/easy_admin/fields/form/date_component.rb +55 -0
- data/app/components/easy_admin/fields/form/datetime_component.rb +55 -0
- data/app/components/easy_admin/fields/form/email_component.rb +55 -0
- data/app/components/easy_admin/fields/form/file_component.rb +190 -0
- data/app/components/easy_admin/fields/form/has_many_component.rb +416 -0
- data/app/components/easy_admin/fields/form/json_component.rb +81 -0
- data/app/components/easy_admin/fields/form/number_component.rb +55 -0
- data/app/components/easy_admin/fields/form/select_component.rb +326 -0
- data/app/components/easy_admin/fields/form/text_component.rb +55 -0
- data/app/components/easy_admin/fields/form/textarea_component.rb +54 -0
- data/app/components/easy_admin/fields/index/belongs_to_component.rb +93 -0
- data/app/components/easy_admin/fields/index/boolean_component.rb +29 -0
- data/app/components/easy_admin/fields/index/date_component.rb +13 -0
- data/app/components/easy_admin/fields/index/datetime_component.rb +13 -0
- data/app/components/easy_admin/fields/index/email_component.rb +24 -0
- data/app/components/easy_admin/fields/index/filters/base_component.rb +48 -0
- data/app/components/easy_admin/fields/index/filters/boolean_component.rb +96 -0
- data/app/components/easy_admin/fields/index/filters/date_component.rb +182 -0
- data/app/components/easy_admin/fields/index/filters/number_component.rb +30 -0
- data/app/components/easy_admin/fields/index/filters/select_component.rb +101 -0
- data/app/components/easy_admin/fields/index/filters/string_component.rb +32 -0
- data/app/components/easy_admin/fields/index/json_component.rb +23 -0
- data/app/components/easy_admin/fields/index/number_component.rb +20 -0
- data/app/components/easy_admin/fields/index/select_component.rb +25 -0
- data/app/components/easy_admin/fields/index/text_component.rb +20 -0
- data/app/components/easy_admin/fields/inline_edit_modal_component.rb +135 -0
- data/app/components/easy_admin/fields/inline_edit_trigger_component.rb +144 -0
- data/app/components/easy_admin/fields/show/belongs_to_component.rb +93 -0
- data/app/components/easy_admin/fields/show/boolean_component.rb +21 -0
- data/app/components/easy_admin/fields/show/date_component.rb +13 -0
- data/app/components/easy_admin/fields/show/datetime_component.rb +13 -0
- data/app/components/easy_admin/fields/show/email_component.rb +19 -0
- data/app/components/easy_admin/fields/show/file_component.rb +304 -0
- data/app/components/easy_admin/fields/show/has_many_component.rb +192 -0
- data/app/components/easy_admin/fields/show/json_component.rb +45 -0
- data/app/components/easy_admin/fields/show/number_component.rb +20 -0
- data/app/components/easy_admin/fields/show/select_component.rb +25 -0
- data/app/components/easy_admin/fields/show/text_component.rb +17 -0
- data/app/components/easy_admin/fields/show/textarea_component.rb +26 -0
- data/app/components/easy_admin/filters_component.rb +120 -0
- data/app/components/easy_admin/form_tabs_component.rb +166 -0
- data/app/components/easy_admin/infinite_scroll_component.rb +82 -0
- data/app/components/easy_admin/lazy_chart_card_component.rb +128 -0
- data/app/components/easy_admin/lazy_metric_card_component.rb +76 -0
- data/app/components/easy_admin/modal_frame_component.rb +26 -0
- data/app/components/easy_admin/navbar_component.rb +226 -0
- data/app/components/easy_admin/notification_component.rb +83 -0
- data/app/components/easy_admin/pagination_component.rb +188 -0
- data/app/components/easy_admin/quick_filters_component.rb +65 -0
- data/app/components/easy_admin/resource_pagination_component.rb +14 -0
- data/app/components/easy_admin/resources/index_component.rb +211 -0
- data/app/components/easy_admin/resources/index_frame_component.rb +88 -0
- data/app/components/easy_admin/resources/show_page_actions_component.rb +324 -0
- data/app/components/easy_admin/resources/table_cell_component.rb +145 -0
- data/app/components/easy_admin/resources/table_component.rb +206 -0
- data/app/components/easy_admin/resources/table_row_component.rb +160 -0
- data/app/components/easy_admin/row_action_form_component.rb +127 -0
- data/app/components/easy_admin/scopes_component.rb +224 -0
- data/app/components/easy_admin/settings_sidebar_component.rb +140 -0
- data/app/components/easy_admin/show_layout_component.rb +600 -0
- data/app/components/easy_admin/sidebar_component.rb +174 -0
- data/app/components/easy_admin/turbo/response_component.rb +40 -0
- data/app/components/easy_admin/turbo/stream_component.rb +28 -0
- data/app/controllers/easy_admin/application_controller.rb +66 -0
- data/app/controllers/easy_admin/batch_actions_controller.rb +166 -0
- data/app/controllers/easy_admin/confirmation_modal_controller.rb +20 -0
- data/app/controllers/easy_admin/dashboard_controller.rb +6 -0
- data/app/controllers/easy_admin/dashboards_controller.rb +123 -0
- data/app/controllers/easy_admin/passwords_controller.rb +15 -0
- data/app/controllers/easy_admin/registrations_controller.rb +52 -0
- data/app/controllers/easy_admin/resources_controller.rb +907 -0
- data/app/controllers/easy_admin/row_actions_controller.rb +216 -0
- data/app/controllers/easy_admin/sessions_controller.rb +32 -0
- data/app/controllers/easy_admin/settings_controller.rb +94 -0
- data/app/helpers/easy_admin/application_helper.rb +4 -0
- data/app/helpers/easy_admin/dashboards_helper.rb +121 -0
- data/app/helpers/easy_admin/fields_helper.rb +27 -0
- data/app/helpers/easy_admin/pagy_helper.rb +30 -0
- data/app/helpers/easy_admin/resources_helper.rb +39 -0
- data/app/javascript/easy_admin/application.js +12 -0
- data/app/javascript/easy_admin/controllers/batch_modal_controller.js +66 -0
- data/app/javascript/easy_admin/controllers/batch_selection_controller.js +223 -0
- data/app/javascript/easy_admin/controllers/chart_controller.js +216 -0
- data/app/javascript/easy_admin/controllers/collapsible_filters_controller.js +118 -0
- data/app/javascript/easy_admin/controllers/confirmation_modal_controller.js +64 -0
- data/app/javascript/easy_admin/controllers/context_menu_controller.js +227 -0
- data/app/javascript/easy_admin/controllers/date_picker_controller.js +309 -0
- data/app/javascript/easy_admin/controllers/dropdown_controller.js +63 -0
- data/app/javascript/easy_admin/controllers/event_emitter_controller.js +19 -0
- data/app/javascript/easy_admin/controllers/file_controller.js +121 -0
- data/app/javascript/easy_admin/controllers/form_tabs_controller.js +100 -0
- data/app/javascript/easy_admin/controllers/has_many_search_controller.js +76 -0
- data/app/javascript/easy_admin/controllers/infinite_scroll_controller.js +174 -0
- data/app/javascript/easy_admin/controllers/ios_alert_controller.js +195 -0
- data/app/javascript/easy_admin/controllers/jsoneditor_controller.js +88 -0
- data/app/javascript/easy_admin/controllers/modal_controller.js +75 -0
- data/app/javascript/easy_admin/controllers/navbar_scroll_controller.js +76 -0
- data/app/javascript/easy_admin/controllers/notification_controller.js +48 -0
- data/app/javascript/easy_admin/controllers/row_action_controller.js +124 -0
- data/app/javascript/easy_admin/controllers/row_modal_controller.js +59 -0
- data/app/javascript/easy_admin/controllers/select_field_controller.js +618 -0
- data/app/javascript/easy_admin/controllers/settings_button_controller.js +8 -0
- data/app/javascript/easy_admin/controllers/settings_sidebar_controller.js +186 -0
- data/app/javascript/easy_admin/controllers/sidebar_controller.js +102 -0
- data/app/javascript/easy_admin/controllers/sidebar_mobile_controller.js +23 -0
- data/app/javascript/easy_admin/controllers/sidebar_nav_controller.js +96 -0
- data/app/javascript/easy_admin/controllers/table_controller.js +28 -0
- data/app/javascript/easy_admin/controllers/table_row_controller.js +16 -0
- data/app/javascript/easy_admin/controllers/toggle_switch_controller.js +22 -0
- data/app/javascript/easy_admin/controllers/turbo_stream_redirect.js +9 -0
- data/app/javascript/easy_admin/controllers.js +54 -0
- data/app/javascript/easy_admin.base.js +4 -0
- data/app/models/easy_admin/admin_user.rb +53 -0
- data/app/models/easy_admin/application_record.rb +5 -0
- data/app/views/easy_admin/dashboard/index.html.erb +3 -0
- data/app/views/easy_admin/dashboards/show.html.erb +7 -0
- data/app/views/easy_admin/passwords/edit.html.erb +42 -0
- data/app/views/easy_admin/passwords/new.html.erb +41 -0
- data/app/views/easy_admin/registrations/new.html.erb +65 -0
- data/app/views/easy_admin/resources/_redirect.turbo_stream.erb +3 -0
- data/app/views/easy_admin/resources/_table_rows.html.erb +46 -0
- data/app/views/easy_admin/resources/edit.html.erb +151 -0
- data/app/views/easy_admin/resources/index.html.erb +12 -0
- data/app/views/easy_admin/resources/index.turbo_stream.erb +139 -0
- data/app/views/easy_admin/resources/index_frame.html.erb +142 -0
- data/app/views/easy_admin/resources/new.html.erb +100 -0
- data/app/views/easy_admin/resources/show.html.erb +31 -0
- data/app/views/easy_admin/sessions/new.html.erb +55 -0
- data/app/views/easy_admin/settings/_form.html.erb +51 -0
- data/app/views/easy_admin/settings/index.html.erb +53 -0
- data/app/views/layouts/easy_admin/application.html.erb +48 -0
- data/app/views/layouts/easy_admin/auth.html.erb +34 -0
- data/config/initializers/easy_admin_card_factory.rb +27 -0
- data/config/initializers/pagy.rb +15 -0
- data/config/initializers/rack_mini_profiler.rb +67 -0
- data/config/routes.rb +70 -0
- data/db/migrate/20250101000001_create_easy_admin_admin_users.rb +45 -0
- data/lib/easy-admin.rb +32 -0
- data/lib/easy_admin/action.rb +159 -0
- data/lib/easy_admin/batch_action.rb +134 -0
- data/lib/easy_admin/configuration.rb +75 -0
- data/lib/easy_admin/dashboard.rb +110 -0
- data/lib/easy_admin/dashboard_registry.rb +30 -0
- data/lib/easy_admin/delete_action.rb +22 -0
- data/lib/easy_admin/engine.rb +54 -0
- data/lib/easy_admin/field.rb +118 -0
- data/lib/easy_admin/resource.rb +806 -0
- data/lib/easy_admin/resource_registry.rb +22 -0
- data/lib/easy_admin/types/json_type.rb +25 -0
- data/lib/easy_admin/version.rb +3 -0
- data/lib/generators/easy_admin/auth_generator.rb +69 -0
- data/lib/generators/easy_admin/card/card_generator.rb +94 -0
- data/lib/generators/easy_admin/card/templates/card_component.rb.erb +127 -0
- data/lib/generators/easy_admin/card/templates/card_component_spec.rb.erb +122 -0
- data/lib/generators/easy_admin/install/templates/easy_admin.rb +31 -0
- data/lib/generators/easy_admin/install_generator.rb +25 -0
- data/lib/generators/easy_admin/rbac/rbac_generator.rb +244 -0
- data/lib/generators/easy_admin/rbac/templates/add_rbac_to_admin_users.rb +23 -0
- data/lib/generators/easy_admin/rbac/templates/super_admin.rb +34 -0
- data/lib/generators/easy_admin/resource_generator.rb +43 -0
- data/lib/generators/easy_admin/templates/AUTH_README +35 -0
- data/lib/generators/easy_admin/templates/README +27 -0
- data/lib/generators/easy_admin/templates/create_easy_admin_admin_users.rb +45 -0
- data/lib/generators/easy_admin/templates/devise.rb +267 -0
- data/lib/generators/easy_admin/templates/easy_admin.rb +24 -0
- data/lib/generators/easy_admin/templates/resource.rb +29 -0
- data/lib/tasks/easy_admin_tasks.rake +4 -0
- metadata +445 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
module EasyAdmin
|
2
|
+
class ResourceRegistry
|
3
|
+
@@resources = {}
|
4
|
+
|
5
|
+
def self.register(resource_class)
|
6
|
+
route_key = resource_class.name.demodulize.gsub(/Resource$/, '').downcase.pluralize
|
7
|
+
@@resources[route_key] = resource_class
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.find_resource(route_key)
|
11
|
+
@@resources[route_key.to_s]
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.all_resources
|
15
|
+
@@resources
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.clear
|
19
|
+
@@resources = {}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module EasyAdmin
|
2
|
+
module Types
|
3
|
+
class JsonType < ActiveRecord::Type::Json
|
4
|
+
# Inherit from Rails' native JSON type for better compatibility
|
5
|
+
def type
|
6
|
+
:json
|
7
|
+
end
|
8
|
+
|
9
|
+
def cast(value)
|
10
|
+
case value
|
11
|
+
when String
|
12
|
+
# Handle JSON strings from form inputs
|
13
|
+
begin
|
14
|
+
JSON.parse(value)
|
15
|
+
rescue JSON::ParserError
|
16
|
+
value # Return original string if not valid JSON
|
17
|
+
end
|
18
|
+
else
|
19
|
+
# Let Rails handle other types
|
20
|
+
super
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
require 'rails/generators/migration'
|
3
|
+
|
4
|
+
module EasyAdmin
|
5
|
+
module Generators
|
6
|
+
class AuthGenerator < Rails::Generators::Base
|
7
|
+
include Rails::Generators::Migration
|
8
|
+
|
9
|
+
source_root File.expand_path('../templates', __FILE__)
|
10
|
+
|
11
|
+
desc 'Generate EasyAdmin authentication setup'
|
12
|
+
|
13
|
+
def self.next_migration_number(path)
|
14
|
+
Time.current.utc.strftime("%Y%m%d%H%M%S")
|
15
|
+
end
|
16
|
+
|
17
|
+
def copy_migration
|
18
|
+
migration_template(
|
19
|
+
'create_easy_admin_admin_users.rb',
|
20
|
+
'db/migrate/create_easy_admin_admin_users.rb',
|
21
|
+
migration_version: migration_version
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
def add_devise_initializer
|
26
|
+
copy_file 'devise.rb', 'config/initializers/easy_admin_devise.rb'
|
27
|
+
end
|
28
|
+
|
29
|
+
def add_routes
|
30
|
+
route "mount EasyAdmin::Engine => '/admin', as: 'easy_admin'"
|
31
|
+
end
|
32
|
+
|
33
|
+
def create_default_admin
|
34
|
+
create_file 'db/seeds/easy_admin.rb', <<~RUBY
|
35
|
+
# Create default EasyAdmin admin user
|
36
|
+
if Rails.env.development?
|
37
|
+
EasyAdmin::AdminUser.find_or_create_by(email: 'admin@example.com') do |admin|
|
38
|
+
admin.password = 'password'
|
39
|
+
admin.password_confirmation = 'password'
|
40
|
+
admin.first_name = 'Admin'
|
41
|
+
admin.last_name = 'User'
|
42
|
+
admin.confirmed_at = Time.current
|
43
|
+
end
|
44
|
+
|
45
|
+
puts "EasyAdmin default admin user created!"
|
46
|
+
puts "Email: admin@example.com"
|
47
|
+
puts "Password: password"
|
48
|
+
end
|
49
|
+
RUBY
|
50
|
+
|
51
|
+
append_to_file 'db/seeds.rb', <<~RUBY
|
52
|
+
|
53
|
+
# Load EasyAdmin seeds
|
54
|
+
load Rails.root.join('db/seeds/easy_admin.rb')
|
55
|
+
RUBY
|
56
|
+
end
|
57
|
+
|
58
|
+
def show_readme
|
59
|
+
readme 'AUTH_README'
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def migration_version
|
65
|
+
"[#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}]"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
|
3
|
+
module EasyAdmin
|
4
|
+
module Generators
|
5
|
+
class CardGenerator < Rails::Generators::NamedBase
|
6
|
+
source_root File.expand_path('templates', __dir__)
|
7
|
+
|
8
|
+
class_option :type, type: :string, default: 'custom',
|
9
|
+
desc: 'Type of card component (metric, chart, table, custom)'
|
10
|
+
|
11
|
+
def create_card_component
|
12
|
+
template 'card_component.rb.erb',
|
13
|
+
"app/components/#{application_name.underscore}/dashboards/cards/#{file_name}_card_component.rb"
|
14
|
+
end
|
15
|
+
|
16
|
+
def create_spec_file
|
17
|
+
return unless defined?(RSpec)
|
18
|
+
|
19
|
+
template 'card_component_spec.rb.erb',
|
20
|
+
"spec/components/#{application_name.underscore}/dashboards/cards/#{file_name}_card_component_spec.rb"
|
21
|
+
end
|
22
|
+
|
23
|
+
def register_card_component
|
24
|
+
initializer_path = "config/initializers/easy_admin_card_factory.rb"
|
25
|
+
|
26
|
+
if File.exist?(initializer_path)
|
27
|
+
append_to_file initializer_path, registration_code
|
28
|
+
else
|
29
|
+
create_file initializer_path, initial_configuration + registration_code
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def show_usage_example
|
34
|
+
say "\nCard component created successfully!"
|
35
|
+
say "Usage example in your dashboard:"
|
36
|
+
say ""
|
37
|
+
say " #{class_name.underscore}_card :#{file_name}, title: \"#{human_name}\""
|
38
|
+
say ""
|
39
|
+
say "Or as a custom card:"
|
40
|
+
say ""
|
41
|
+
say " card :#{file_name},"
|
42
|
+
say " type: :#{options[:type]},"
|
43
|
+
say " title: \"#{human_name}\","
|
44
|
+
say " component_class: \"#{component_class_name}\""
|
45
|
+
say ""
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def application_name
|
51
|
+
Rails.application.class.module_parent.name
|
52
|
+
end
|
53
|
+
|
54
|
+
def component_class_name
|
55
|
+
"#{application_name}::Dashboards::Cards::#{class_name}CardComponent"
|
56
|
+
end
|
57
|
+
|
58
|
+
def human_name
|
59
|
+
name.humanize
|
60
|
+
end
|
61
|
+
|
62
|
+
def card_type
|
63
|
+
options[:type]
|
64
|
+
end
|
65
|
+
|
66
|
+
def base_class
|
67
|
+
case card_type
|
68
|
+
when 'metric'
|
69
|
+
'EasyAdmin::Dashboards::Cards::MetricCardComponent'
|
70
|
+
when 'chart'
|
71
|
+
'EasyAdmin::Dashboards::Cards::ChartCardComponent'
|
72
|
+
when 'table'
|
73
|
+
'EasyAdmin::Dashboards::Cards::TableCardComponent'
|
74
|
+
else
|
75
|
+
'EasyAdmin::Dashboards::Cards::BaseCardComponent'
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def registration_code
|
80
|
+
"\n# Generated card component registration\n" +
|
81
|
+
"EasyAdmin::Dashboards::CardFactory.register(:#{file_name}, #{component_class_name})\n"
|
82
|
+
end
|
83
|
+
|
84
|
+
def initial_configuration
|
85
|
+
<<~RUBY
|
86
|
+
# EasyAdmin Card Factory Configuration
|
87
|
+
#
|
88
|
+
# This file registers custom card components with the factory.
|
89
|
+
|
90
|
+
RUBY
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
module <%= application_name %>
|
2
|
+
module Dashboards
|
3
|
+
module Cards
|
4
|
+
class <%= class_name %>CardComponent < <%= base_class %>
|
5
|
+
private
|
6
|
+
|
7
|
+
def render_card_content
|
8
|
+
div(class: "flex flex-col h-full") do
|
9
|
+
# Card Content
|
10
|
+
div(class: "flex-1 p-6") do
|
11
|
+
<% case card_type %>
|
12
|
+
<% when 'metric' %>
|
13
|
+
render_metric_content
|
14
|
+
<% when 'chart' %>
|
15
|
+
render_chart_content
|
16
|
+
<% when 'table' %>
|
17
|
+
render_table_content
|
18
|
+
<% else %>
|
19
|
+
render_custom_content
|
20
|
+
<% end %>
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
<% case card_type %>
|
26
|
+
<% when 'metric' %>
|
27
|
+
def render_metric_content
|
28
|
+
# Implement your metric card logic here
|
29
|
+
div(class: "text-center") do
|
30
|
+
div(class: "text-3xl font-bold text-gray-900 mb-2") do
|
31
|
+
card_data[:value] || "N/A"
|
32
|
+
end
|
33
|
+
if card_data[:description]
|
34
|
+
p(class: "text-sm text-gray-600") { card_data[:description] }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
<% when 'chart' %>
|
40
|
+
def render_chart_content
|
41
|
+
# Implement your chart card logic here
|
42
|
+
if card_data[:chart_data] && card_data[:chart_data].any?
|
43
|
+
div(
|
44
|
+
class: "ea-chart-container",
|
45
|
+
data: {
|
46
|
+
controller: "chart",
|
47
|
+
chart_type_value: card[:chart_type] || "line",
|
48
|
+
chart_data_value: prepare_chart_data.to_json
|
49
|
+
},
|
50
|
+
style: "height: #{chart_height}px;"
|
51
|
+
) do
|
52
|
+
unsafe_raw "<canvas></canvas>"
|
53
|
+
end
|
54
|
+
else
|
55
|
+
render_no_data_message
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def prepare_chart_data
|
60
|
+
# Customize chart data preparation
|
61
|
+
{
|
62
|
+
labels: card_data[:chart_data]&.map { |d| d[:label] || d[:date] } || [],
|
63
|
+
datasets: [{
|
64
|
+
data: card_data[:chart_data]&.map { |d| d[:value] } || [],
|
65
|
+
backgroundColor: 'rgba(59, 130, 246, 0.2)',
|
66
|
+
borderColor: 'rgb(59, 130, 246)'
|
67
|
+
}]
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
<% when 'table' %>
|
72
|
+
def render_table_content
|
73
|
+
# Implement your table card logic here
|
74
|
+
if card_data[:rows] && card_data[:rows].any?
|
75
|
+
table(class: "min-w-full") do
|
76
|
+
if card_data[:headers]
|
77
|
+
thead do
|
78
|
+
tr do
|
79
|
+
card_data[:headers].each do |header|
|
80
|
+
th(class: "px-4 py-2 text-left") { header }
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
tbody do
|
86
|
+
card_data[:rows].each do |row|
|
87
|
+
tr do
|
88
|
+
row.each do |cell|
|
89
|
+
td(class: "px-4 py-2") { cell.to_s }
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
else
|
96
|
+
render_no_data_message
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
<% else %>
|
101
|
+
def render_custom_content
|
102
|
+
# Implement your custom card logic here
|
103
|
+
div(class: "text-center text-gray-500") do
|
104
|
+
h4(class: "text-lg font-medium mb-2") { "<%= human_name %>" }
|
105
|
+
p { "Implement your custom card content here." }
|
106
|
+
|
107
|
+
# Display card data for debugging
|
108
|
+
if card_data && !card_data.empty?
|
109
|
+
div(class: "mt-4 p-4 bg-gray-100 rounded text-xs") do
|
110
|
+
pre { card_data.to_json }
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
<% end %>
|
117
|
+
<% unless card_type == 'metric' %>
|
118
|
+
def render_no_data_message
|
119
|
+
div(class: "flex items-center justify-center py-8 text-gray-500") do
|
120
|
+
p { "No data available" }
|
121
|
+
end
|
122
|
+
end
|
123
|
+
<% end %>
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
RSpec.describe <%= component_class_name %>, type: :component do
|
4
|
+
let(:card) do
|
5
|
+
{
|
6
|
+
name: :<%= file_name %>,
|
7
|
+
type: :<%= card_type %>,
|
8
|
+
title: "<%= human_name %>",
|
9
|
+
cols: 1,
|
10
|
+
rows: 1
|
11
|
+
}
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:card_data) { {} }
|
15
|
+
let(:dashboard_class) { double('DashboardClass') }
|
16
|
+
|
17
|
+
let(:component) do
|
18
|
+
described_class.new(
|
19
|
+
card: card,
|
20
|
+
card_data: card_data,
|
21
|
+
dashboard_class: dashboard_class
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#view_template' do
|
26
|
+
it 'renders without errors' do
|
27
|
+
expect { render_inline(component) }.not_to raise_error
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'includes the card title' do
|
31
|
+
render_inline(component)
|
32
|
+
|
33
|
+
expect(page).to have_content("<%= human_name %>")
|
34
|
+
end
|
35
|
+
|
36
|
+
<% case card_type %>
|
37
|
+
<% when 'metric' %>
|
38
|
+
context 'with metric data' do
|
39
|
+
let(:card_data) do
|
40
|
+
{
|
41
|
+
value: 1234,
|
42
|
+
description: 'Test metric'
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'displays the metric value' do
|
47
|
+
render_inline(component)
|
48
|
+
|
49
|
+
expect(page).to have_content('1234')
|
50
|
+
expect(page).to have_content('Test metric')
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
<% when 'chart' %>
|
55
|
+
context 'with chart data' do
|
56
|
+
let(:card_data) do
|
57
|
+
{
|
58
|
+
chart_data: [
|
59
|
+
{ label: 'Jan', value: 100 },
|
60
|
+
{ label: 'Feb', value: 200 }
|
61
|
+
]
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'renders chart container' do
|
66
|
+
render_inline(component)
|
67
|
+
|
68
|
+
expect(page).to have_css('.ea-chart-container')
|
69
|
+
expect(page).to have_css('canvas')
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'without chart data' do
|
74
|
+
it 'shows no data message' do
|
75
|
+
render_inline(component)
|
76
|
+
|
77
|
+
expect(page).to have_content('No data available')
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
<% when 'table' %>
|
82
|
+
context 'with table data' do
|
83
|
+
let(:card_data) do
|
84
|
+
{
|
85
|
+
headers: ['Name', 'Value'],
|
86
|
+
rows: [
|
87
|
+
['Item 1', '100'],
|
88
|
+
['Item 2', '200']
|
89
|
+
]
|
90
|
+
}
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'renders table with headers and rows' do
|
94
|
+
render_inline(component)
|
95
|
+
|
96
|
+
expect(page).to have_css('table')
|
97
|
+
expect(page).to have_content('Name')
|
98
|
+
expect(page).to have_content('Value')
|
99
|
+
expect(page).to have_content('Item 1')
|
100
|
+
expect(page).to have_content('Item 2')
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
context 'without table data' do
|
105
|
+
it 'shows no data message' do
|
106
|
+
render_inline(component)
|
107
|
+
|
108
|
+
expect(page).to have_content('No data available')
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
<% else %>
|
113
|
+
it 'displays custom content' do
|
114
|
+
render_inline(component)
|
115
|
+
|
116
|
+
expect(page).to have_content("<%= human_name %>")
|
117
|
+
expect(page).to have_content('Implement your custom card content')
|
118
|
+
end
|
119
|
+
|
120
|
+
<% end %>
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# EasyAdmin Configuration
|
2
|
+
EasyAdmin.configure do |config|
|
3
|
+
# Application name (shown in sidebar header)
|
4
|
+
config.app_name = "My Admin Panel"
|
5
|
+
|
6
|
+
# Enable performance profiler (rack-mini-profiler)
|
7
|
+
# Shows performance metrics in bottom-left corner
|
8
|
+
# Recommended: true for development, false for production
|
9
|
+
config.enable_profiler = Rails.env.development?
|
10
|
+
|
11
|
+
# Enable global settings panel (requires Flipper gem)
|
12
|
+
# config.global_settings = true
|
13
|
+
|
14
|
+
# Configure sidebar navigation
|
15
|
+
config.sidebar do
|
16
|
+
item "Dashboard", "/admin", icon: "🏠", active: true
|
17
|
+
|
18
|
+
group "Content", icon: "📝" do
|
19
|
+
item "Posts", "/admin/posts"
|
20
|
+
item "Categories", "/admin/categories"
|
21
|
+
item "Comments", "/admin/comments"
|
22
|
+
end
|
23
|
+
|
24
|
+
group "Users", icon: "👥" do
|
25
|
+
item "Users", "/admin/users"
|
26
|
+
item "Admin Users", "/admin/admin_users"
|
27
|
+
end
|
28
|
+
|
29
|
+
item "Settings", "/admin/settings", icon: "⚙️"
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module EasyAdmin
|
2
|
+
module Generators
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
4
|
+
desc "Creates EasyAdmin initializer"
|
5
|
+
|
6
|
+
def self.source_root
|
7
|
+
@source_root ||= File.expand_path("templates", __dir__)
|
8
|
+
end
|
9
|
+
|
10
|
+
def create_initializer
|
11
|
+
template "easy_admin.rb", "config/initializers/easy_admin.rb"
|
12
|
+
end
|
13
|
+
|
14
|
+
def show_readme
|
15
|
+
readme "README" if behavior == :invoke
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def readme(filename)
|
21
|
+
say File.read(File.join(self.class.source_root, filename))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|