easy-admin-rails 0.2.5 → 0.2.7

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.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/builds/easy_admin.base.js +95 -0
  3. data/app/assets/builds/easy_admin.base.js.map +3 -3
  4. data/app/assets/builds/easy_admin.css +226 -0
  5. data/app/components/easy_admin/fields/form/belongs_to_component.rb +0 -1
  6. data/app/components/easy_admin/form_layout_component.rb +553 -0
  7. data/app/components/easy_admin/navbar_component.rb +19 -4
  8. data/app/components/easy_admin/permissions/user_role_permissions_component.rb +1 -3
  9. data/app/components/easy_admin/profile/change_password_modal_component.rb +75 -0
  10. data/app/components/easy_admin/profile/profile_tab_component.rb +92 -0
  11. data/app/components/easy_admin/profile/security_tab_component.rb +53 -0
  12. data/app/components/easy_admin/profile/settings_component.rb +103 -0
  13. data/app/components/easy_admin/show_layout_component.rb +694 -24
  14. data/app/components/easy_admin/two_factor/backup_codes_component.rb +118 -0
  15. data/app/components/easy_admin/two_factor/setup_component.rb +124 -0
  16. data/app/components/easy_admin/two_factor/status_component.rb +92 -0
  17. data/app/controllers/concerns/easy_admin/two_factor.rb +110 -0
  18. data/app/controllers/easy_admin/application_controller.rb +10 -5
  19. data/app/controllers/easy_admin/batch_actions_controller.rb +0 -1
  20. data/app/controllers/easy_admin/concerns/inline_field_editing.rb +4 -11
  21. data/app/controllers/easy_admin/concerns/resource_loading.rb +10 -9
  22. data/app/controllers/easy_admin/concerns/resource_pagination.rb +3 -0
  23. data/app/controllers/easy_admin/dashboards_controller.rb +0 -1
  24. data/app/controllers/easy_admin/profile_controller.rb +25 -0
  25. data/app/controllers/easy_admin/resources_controller.rb +1 -5
  26. data/app/controllers/easy_admin/row_actions_controller.rb +1 -4
  27. data/app/controllers/easy_admin/sessions_controller.rb +107 -1
  28. data/app/helpers/easy_admin/fields_helper.rb +8 -22
  29. data/app/javascript/easy_admin/controllers/infinite_scroll_controller.js +12 -0
  30. data/app/javascript/easy_admin/controllers/vertical_tabs_controller.js +112 -0
  31. data/app/javascript/easy_admin/controllers.js +3 -1
  32. data/app/models/easy_admin/admin_user.rb +3 -0
  33. data/app/views/easy_admin/profile/backup_codes_regenerated.turbo_stream.erb +12 -0
  34. data/app/views/easy_admin/profile/change_password.html.erb +24 -0
  35. data/app/views/easy_admin/profile/index.html.erb +1 -0
  36. data/app/views/easy_admin/profile/password_error.turbo_stream.erb +6 -0
  37. data/app/views/easy_admin/profile/password_invalid_current.turbo_stream.erb +6 -0
  38. data/app/views/easy_admin/profile/password_updated.turbo_stream.erb +9 -0
  39. data/app/views/easy_admin/profile/two_factor_backup_codes.html.erb +24 -0
  40. data/app/views/easy_admin/profile/two_factor_enabled.turbo_stream.erb +12 -0
  41. data/app/views/easy_admin/profile/two_factor_invalid_code.turbo_stream.erb +6 -0
  42. data/app/views/easy_admin/profile/two_factor_not_enabled.turbo_stream.erb +6 -0
  43. data/app/views/easy_admin/profile/two_factor_setup.html.erb +24 -0
  44. data/app/views/easy_admin/profile/two_factor_unavailable.turbo_stream.erb +6 -0
  45. data/app/views/easy_admin/resources/edit.html.erb +2 -2
  46. data/app/views/easy_admin/resources/new.html.erb +2 -2
  47. data/app/views/easy_admin/resources/show.html.erb +3 -1
  48. data/app/views/easy_admin/sessions/two_factor_verification.html.erb +48 -0
  49. data/app/views/easy_admin/sessions/verify_2fa_error.turbo_stream.erb +13 -0
  50. data/config/routes.rb +20 -1
  51. data/lib/easy-admin-rails.rb +1 -0
  52. data/lib/easy_admin/field.rb +3 -2
  53. data/lib/easy_admin/layouts/builders/base_layout_builder.rb +245 -0
  54. data/lib/easy_admin/layouts/builders/form_layout_builder.rb +208 -0
  55. data/lib/easy_admin/layouts/builders/index_layout_builder.rb +22 -0
  56. data/lib/easy_admin/layouts/builders/show_layout_builder.rb +199 -0
  57. data/lib/easy_admin/layouts/dsl.rb +200 -0
  58. data/lib/easy_admin/layouts/layout_context.rb +189 -0
  59. data/lib/easy_admin/layouts/nodes/base_node.rb +88 -0
  60. data/lib/easy_admin/layouts/nodes/divider.rb +27 -0
  61. data/lib/easy_admin/layouts/nodes/field_node.rb +57 -0
  62. data/lib/easy_admin/layouts/nodes/grid.rb +60 -0
  63. data/lib/easy_admin/layouts/nodes/render_node.rb +41 -0
  64. data/lib/easy_admin/layouts/nodes/root.rb +25 -0
  65. data/lib/easy_admin/layouts/nodes/section.rb +46 -0
  66. data/lib/easy_admin/layouts/nodes/spacer.rb +17 -0
  67. data/lib/easy_admin/layouts/nodes/stubs.rb +109 -0
  68. data/lib/easy_admin/layouts/nodes/tab.rb +40 -0
  69. data/lib/easy_admin/layouts/nodes/tabs.rb +40 -0
  70. data/lib/easy_admin/layouts.rb +28 -0
  71. data/lib/easy_admin/permissions/resource_permissions.rb +1 -5
  72. data/lib/easy_admin/resource/base.rb +2 -2
  73. data/lib/easy_admin/resource/dsl.rb +2 -11
  74. data/lib/easy_admin/resource/field_registry.rb +58 -2
  75. data/lib/easy_admin/resource.rb +0 -9
  76. data/lib/easy_admin/resource_modules.rb +21 -4
  77. data/lib/easy_admin/two_factor_authentication.rb +156 -0
  78. data/lib/easy_admin/version.rb +1 -1
  79. data/lib/generators/easy_admin/permissions/install_generator.rb +0 -10
  80. data/lib/generators/easy_admin/permissions/templates/migrations/create_permission_tables.rb +33 -3
  81. data/lib/generators/easy_admin/two_factor/templates/README +29 -0
  82. data/lib/generators/easy_admin/two_factor/templates/migration.rb +10 -0
  83. data/lib/generators/easy_admin/two_factor/two_factor_generator.rb +22 -0
  84. metadata +49 -9
  85. data/lib/easy_admin/resource/form_builder.rb +0 -123
  86. data/lib/easy_admin/resource/layout_builder.rb +0 -249
  87. data/lib/easy_admin/resource/show_builder.rb +0 -359
  88. data/lib/generators/easy_admin/permissions/templates/migrations/update_users_for_permissions.rb +0 -6
  89. data/lib/generators/easy_admin/rbac/rbac_generator.rb +0 -244
  90. data/lib/generators/easy_admin/rbac/templates/add_rbac_to_admin_users.rb +0 -23
  91. data/lib/generators/easy_admin/rbac/templates/super_admin.rb +0 -34
@@ -0,0 +1,92 @@
1
+ module EasyAdmin
2
+ module Profile
3
+ class ProfileTabComponent < BaseComponent
4
+ def initialize(user:)
5
+ @user = user
6
+ end
7
+
8
+ def view_template
9
+ div do
10
+ # Section header
11
+ div(class: "mb-6") do
12
+ h2(class: "text-lg font-medium text-gray-900") { "Profile Information" }
13
+ p(class: "text-sm text-gray-600 mt-1") { "Update your personal information" }
14
+ end
15
+
16
+ # Profile form
17
+ form(action: EasyAdmin::Engine.routes.url_helpers.update_profile_path, method: :patch) do
18
+ # Rails CSRF token
19
+ input(type: "hidden", name: "authenticity_token", value: helpers.form_authenticity_token) if helpers.respond_to?(:form_authenticity_token)
20
+ # Rails method spoofing for PATCH
21
+ input(type: "hidden", name: "_method", value: "patch")
22
+
23
+ div(class: "space-y-6") do
24
+ # First Name
25
+ div do
26
+ label(for: "admin_user_first_name", class: "block text-sm font-medium text-gray-700 mb-2") { "First Name" }
27
+ input(
28
+ type: "text",
29
+ name: "admin_user[first_name]",
30
+ id: "admin_user_first_name",
31
+ value: @user.first_name,
32
+ class: "w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500",
33
+ placeholder: "Enter your first name"
34
+ )
35
+ render_field_errors(@user, :first_name)
36
+ end
37
+
38
+ # Last Name
39
+ div do
40
+ label(for: "admin_user_last_name", class: "block text-sm font-medium text-gray-700 mb-2") { "Last Name" }
41
+ input(
42
+ type: "text",
43
+ name: "admin_user[last_name]",
44
+ id: "admin_user_last_name",
45
+ value: @user.last_name,
46
+ class: "w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500",
47
+ placeholder: "Enter your last name"
48
+ )
49
+ render_field_errors(@user, :last_name)
50
+ end
51
+
52
+ # Email
53
+ div do
54
+ label(for: "admin_user_email", class: "block text-sm font-medium text-gray-700 mb-2") { "Email" }
55
+ input(
56
+ type: "email",
57
+ name: "admin_user[email]",
58
+ id: "admin_user_email",
59
+ value: @user.email,
60
+ class: "w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500",
61
+ placeholder: "Enter your email address"
62
+ )
63
+ render_field_errors(@user, :email)
64
+ end
65
+
66
+ # Submit button
67
+ div do
68
+ input(
69
+ type: "submit",
70
+ value: "Update Profile",
71
+ class: "bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors cursor-pointer"
72
+ )
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+
79
+ private
80
+
81
+ def render_field_errors(object, field)
82
+ return unless object.errors[field].any?
83
+
84
+ div(class: "mt-1") do
85
+ object.errors[field].each do |error|
86
+ p(class: "text-sm text-red-600") { error }
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,53 @@
1
+ module EasyAdmin
2
+ module Profile
3
+ class SecurityTabComponent < BaseComponent
4
+ def initialize(user:)
5
+ @user = user
6
+ end
7
+
8
+ def view_template
9
+ div(class: "space-y-8") do
10
+ # Password section
11
+ render_password_section
12
+
13
+ # Two-factor authentication section
14
+ div(id: "two_factor_section") do
15
+ render_two_factor_section
16
+ end
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def render_password_section
23
+ div do
24
+ # Section header
25
+ div(class: "mb-6") do
26
+ h2(class: "text-lg font-medium text-gray-900") { "Change Password" }
27
+ p(class: "text-sm text-gray-600 mt-1") { "Update your password to keep your account secure" }
28
+ end
29
+
30
+ # Change password button
31
+ a(
32
+ href: EasyAdmin::Engine.routes.url_helpers.change_password_path,
33
+ class: "bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 transition-colors",
34
+ data: { turbo_frame: "modal" }
35
+ ) { "Change Password" }
36
+ end
37
+ end
38
+
39
+ def render_two_factor_section
40
+ div(class: "pt-8 border-t border-gray-200") do
41
+ # Section header
42
+ div(class: "mb-6") do
43
+ h2(class: "text-lg font-medium text-gray-900") { "Two-Factor Authentication" }
44
+ p(class: "text-sm text-gray-600 mt-1") { "Add an extra layer of security to your account" }
45
+ end
46
+
47
+ # 2FA status and actions
48
+ render EasyAdmin::TwoFactor::StatusComponent.new(user: @user)
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,103 @@
1
+ module EasyAdmin
2
+ module Profile
3
+ class SettingsComponent < BaseComponent
4
+ def initialize(user:)
5
+ @user = user
6
+ end
7
+
8
+ def view_template
9
+ div(class: "min-h-screen bg-gray-50 py-6") do
10
+ div(class: "max-w-6xl mx-auto px-6") do
11
+ # Page header
12
+ div(class: "mb-8") do
13
+ h1(class: "text-2xl font-semibold text-gray-900") { "Settings" }
14
+ p(class: "text-gray-600 mt-1") { "Manage your account settings and preferences" }
15
+ end
16
+
17
+ # Settings layout with vertical tabs
18
+ div(
19
+ class: "bg-white rounded-lg overflow-hidden",
20
+ data: { controller: "vertical-tabs" }
21
+ ) do
22
+ div(class: "flex") do
23
+ # Left sidebar - Tab navigation
24
+ render_tab_navigation
25
+
26
+ # Right content area
27
+ render_content_area
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def render_tab_navigation
37
+ nav(class: "w-64 bg-gray-50 border-r border-gray-200 py-6") do
38
+ div(class: "px-4") do
39
+ render_tab_item("profile", "Profile", profile_icon, active: true)
40
+ render_tab_item("security", "Security", security_icon)
41
+ end
42
+ end
43
+ end
44
+
45
+ def render_tab_item(tab_id, label, icon_svg, active: false)
46
+ button(
47
+ class: "w-full flex items-center px-3 py-2 mb-2 text-left rounded-lg transition-colors #{tab_classes(active)}",
48
+ data: {
49
+ action: "click->vertical-tabs#switchTab",
50
+ vertical_tabs_target: "tab",
51
+ tab_id: tab_id
52
+ }
53
+ ) do
54
+ div(class: "w-5 h-5 mr-3") { unsafe_raw(icon_svg) }
55
+ span(class: "font-medium") { label }
56
+ end
57
+ end
58
+
59
+ def render_content_area
60
+ div(class: "flex-1 p-6") do
61
+ # Profile tab content
62
+ div(
63
+ class: "tab-content",
64
+ data: {
65
+ vertical_tabs_target: "content",
66
+ tab_id: "profile"
67
+ }
68
+ ) do
69
+ render EasyAdmin::Profile::ProfileTabComponent.new(user: @user)
70
+ end
71
+
72
+ # Security tab content
73
+ div(
74
+ class: "tab-content hidden",
75
+ data: {
76
+ vertical_tabs_target: "content",
77
+ tab_id: "security"
78
+ }
79
+ ) do
80
+ render EasyAdmin::Profile::SecurityTabComponent.new(user: @user)
81
+ end
82
+ end
83
+ end
84
+
85
+ def tab_classes(active)
86
+ if active
87
+ "bg-blue-50 text-blue-700 border-blue-200"
88
+ else
89
+ "text-gray-700 hover:bg-gray-100 hover:text-gray-900"
90
+ end
91
+ end
92
+
93
+ # SVG Icons
94
+ def profile_icon
95
+ '<svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"/></svg>'
96
+ end
97
+
98
+ def security_icon
99
+ '<svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"/></svg>'
100
+ end
101
+ end
102
+ end
103
+ end