rsb-admin 0.9.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.
Files changed (115) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +15 -0
  3. data/README.md +83 -0
  4. data/Rakefile +25 -0
  5. data/app/assets/javascripts/rsb/admin/themes/modern.js +37 -0
  6. data/app/assets/stylesheets/rsb/admin/themes/default.css +1358 -0
  7. data/app/assets/stylesheets/rsb/admin/themes/modern.css +1370 -0
  8. data/app/controllers/concerns/rsb/admin/authorization.rb +21 -0
  9. data/app/controllers/rsb/admin/admin_controller.rb +138 -0
  10. data/app/controllers/rsb/admin/admin_users_controller.rb +110 -0
  11. data/app/controllers/rsb/admin/dashboard_controller.rb +76 -0
  12. data/app/controllers/rsb/admin/profile_controller.rb +146 -0
  13. data/app/controllers/rsb/admin/profile_sessions_controller.rb +45 -0
  14. data/app/controllers/rsb/admin/resources_controller.rb +386 -0
  15. data/app/controllers/rsb/admin/roles_controller.rb +99 -0
  16. data/app/controllers/rsb/admin/sessions_controller.rb +139 -0
  17. data/app/controllers/rsb/admin/settings_controller.rb +203 -0
  18. data/app/controllers/rsb/admin/two_factor_controller.rb +105 -0
  19. data/app/helpers/rsb/admin/authorization_helper.rb +49 -0
  20. data/app/helpers/rsb/admin/branding_helper.rb +38 -0
  21. data/app/helpers/rsb/admin/formatting_helper.rb +205 -0
  22. data/app/helpers/rsb/admin/i18n_helper.rb +148 -0
  23. data/app/helpers/rsb/admin/icons_helper.rb +55 -0
  24. data/app/helpers/rsb/admin/table_helper.rb +132 -0
  25. data/app/helpers/rsb/admin/theme_helper.rb +84 -0
  26. data/app/helpers/rsb/admin/url_helper.rb +109 -0
  27. data/app/mailers/rsb/admin/admin_mailer.rb +37 -0
  28. data/app/models/rsb/admin/admin_session.rb +109 -0
  29. data/app/models/rsb/admin/admin_user.rb +153 -0
  30. data/app/models/rsb/admin/application_record.rb +10 -0
  31. data/app/models/rsb/admin/role.rb +63 -0
  32. data/app/views/layouts/rsb/admin/application.html.erb +45 -0
  33. data/app/views/rsb/admin/admin_mailer/email_verification.html.erb +11 -0
  34. data/app/views/rsb/admin/admin_mailer/email_verification.text.erb +11 -0
  35. data/app/views/rsb/admin/admin_users/_form.html.erb +52 -0
  36. data/app/views/rsb/admin/admin_users/edit.html.erb +10 -0
  37. data/app/views/rsb/admin/admin_users/index.html.erb +77 -0
  38. data/app/views/rsb/admin/admin_users/new.html.erb +10 -0
  39. data/app/views/rsb/admin/admin_users/show.html.erb +85 -0
  40. data/app/views/rsb/admin/dashboard/index.html.erb +36 -0
  41. data/app/views/rsb/admin/profile/edit.html.erb +67 -0
  42. data/app/views/rsb/admin/profile/show.html.erb +155 -0
  43. data/app/views/rsb/admin/resources/_filters.html.erb +58 -0
  44. data/app/views/rsb/admin/resources/_form.html.erb +20 -0
  45. data/app/views/rsb/admin/resources/_pagination.html.erb +33 -0
  46. data/app/views/rsb/admin/resources/_table.html.erb +70 -0
  47. data/app/views/rsb/admin/resources/edit.html.erb +7 -0
  48. data/app/views/rsb/admin/resources/index.html.erb +49 -0
  49. data/app/views/rsb/admin/resources/new.html.erb +7 -0
  50. data/app/views/rsb/admin/resources/page.html.erb +9 -0
  51. data/app/views/rsb/admin/resources/show.html.erb +55 -0
  52. data/app/views/rsb/admin/roles/_form.html.erb +197 -0
  53. data/app/views/rsb/admin/roles/edit.html.erb +7 -0
  54. data/app/views/rsb/admin/roles/index.html.erb +71 -0
  55. data/app/views/rsb/admin/roles/new.html.erb +7 -0
  56. data/app/views/rsb/admin/roles/show.html.erb +99 -0
  57. data/app/views/rsb/admin/sessions/new.html.erb +31 -0
  58. data/app/views/rsb/admin/sessions/two_factor.html.erb +39 -0
  59. data/app/views/rsb/admin/settings/_field.html.erb +115 -0
  60. data/app/views/rsb/admin/settings/index.html.erb +61 -0
  61. data/app/views/rsb/admin/shared/_badge.html.erb +1 -0
  62. data/app/views/rsb/admin/shared/_breadcrumbs.html.erb +12 -0
  63. data/app/views/rsb/admin/shared/_empty_state.html.erb +4 -0
  64. data/app/views/rsb/admin/shared/_flash.html.erb +22 -0
  65. data/app/views/rsb/admin/shared/_header.html.erb +50 -0
  66. data/app/views/rsb/admin/shared/_page_tabs.html.erb +21 -0
  67. data/app/views/rsb/admin/shared/_sidebar.html.erb +99 -0
  68. data/app/views/rsb/admin/shared/disabled.html.erb +38 -0
  69. data/app/views/rsb/admin/shared/fields/_checkbox.html.erb +6 -0
  70. data/app/views/rsb/admin/shared/fields/_datetime.html.erb +10 -0
  71. data/app/views/rsb/admin/shared/fields/_email.html.erb +10 -0
  72. data/app/views/rsb/admin/shared/fields/_hidden.html.erb +1 -0
  73. data/app/views/rsb/admin/shared/fields/_json.html.erb +11 -0
  74. data/app/views/rsb/admin/shared/fields/_number.html.erb +10 -0
  75. data/app/views/rsb/admin/shared/fields/_password.html.erb +10 -0
  76. data/app/views/rsb/admin/shared/fields/_select.html.erb +12 -0
  77. data/app/views/rsb/admin/shared/fields/_text.html.erb +10 -0
  78. data/app/views/rsb/admin/shared/fields/_textarea.html.erb +10 -0
  79. data/app/views/rsb/admin/shared/forbidden.html.erb +22 -0
  80. data/app/views/rsb/admin/themes/modern/views/shared/_header.html.erb +77 -0
  81. data/app/views/rsb/admin/themes/modern/views/shared/_sidebar.html.erb +135 -0
  82. data/app/views/rsb/admin/two_factor/backup_codes.html.erb +48 -0
  83. data/app/views/rsb/admin/two_factor/new.html.erb +53 -0
  84. data/config/locales/en.yml +140 -0
  85. data/config/locales/seo.en.yml +21 -0
  86. data/config/routes.rb +59 -0
  87. data/db/migrate/20260208000003_create_rsb_admin_tables.rb +43 -0
  88. data/db/migrate/20260214000001_add_otp_fields_to_rsb_admin_admin_users.rb +9 -0
  89. data/lib/generators/rsb/admin/install/install_generator.rb +45 -0
  90. data/lib/generators/rsb/admin/install/templates/rsb_admin_seeds.rb +24 -0
  91. data/lib/generators/rsb/admin/theme/templates/theme.css.tt +66 -0
  92. data/lib/generators/rsb/admin/theme/theme_generator.rb +218 -0
  93. data/lib/generators/rsb/admin/views/views_generator.rb +262 -0
  94. data/lib/rsb/admin/breadcrumb_item.rb +26 -0
  95. data/lib/rsb/admin/category_registration.rb +177 -0
  96. data/lib/rsb/admin/column_definition.rb +89 -0
  97. data/lib/rsb/admin/configuration.rb +69 -0
  98. data/lib/rsb/admin/engine.rb +34 -0
  99. data/lib/rsb/admin/filter_definition.rb +129 -0
  100. data/lib/rsb/admin/form_field_definition.rb +96 -0
  101. data/lib/rsb/admin/icons.rb +95 -0
  102. data/lib/rsb/admin/page_registration.rb +140 -0
  103. data/lib/rsb/admin/registry.rb +109 -0
  104. data/lib/rsb/admin/resource_dsl_context.rb +139 -0
  105. data/lib/rsb/admin/resource_registration.rb +287 -0
  106. data/lib/rsb/admin/settings_schema.rb +60 -0
  107. data/lib/rsb/admin/test_kit/helpers.rb +316 -0
  108. data/lib/rsb/admin/test_kit/resource_test_case.rb +193 -0
  109. data/lib/rsb/admin/test_kit.rb +11 -0
  110. data/lib/rsb/admin/theme_definition.rb +46 -0
  111. data/lib/rsb/admin/themes/modern.rb +44 -0
  112. data/lib/rsb/admin/version.rb +9 -0
  113. data/lib/rsb/admin.rb +177 -0
  114. data/lib/tasks/rsb/admin_tasks.rake +23 -0
  115. metadata +227 -0
@@ -0,0 +1,53 @@
1
+ <div class="max-w-lg mx-auto">
2
+ <div class="bg-rsb-card border border-rsb-border rounded-rsb-lg shadow-rsb-sm p-6">
3
+ <h2 class="text-xl font-bold mb-4">Set Up Two-Factor Authentication</h2>
4
+
5
+ <p class="mb-4 text-rsb-muted text-sm">
6
+ Scan the QR code below with your authenticator app (Google Authenticator, Authy, 1Password, etc.),
7
+ then enter the 6-digit code to confirm.
8
+ </p>
9
+
10
+ <% if flash[:alert] %>
11
+ <div class="mb-4 p-3 rounded-rsb bg-rsb-danger-bg border border-rsb-danger text-rsb-danger-text text-sm">
12
+ <%= flash[:alert] %>
13
+ </div>
14
+ <% end %>
15
+
16
+ <!-- QR Code -->
17
+ <div class="flex justify-center mb-4">
18
+ <div class="bg-white p-4 rounded">
19
+ <%= @qr_svg.html_safe %>
20
+ </div>
21
+ </div>
22
+
23
+ <!-- Manual entry key -->
24
+ <div class="mb-6">
25
+ <p class="text-sm font-medium mb-1">Can't scan? Enter this key manually:</p>
26
+ <code class="block p-2 bg-rsb-bg border border-rsb-border rounded-rsb text-sm font-mono break-all select-all">
27
+ <%= @otp_secret %>
28
+ </code>
29
+ </div>
30
+
31
+ <!-- Confirmation form -->
32
+ <%= form_tag(rsb_admin.profile_two_factor_path, method: :post) do %>
33
+ <%= hidden_field_tag :authenticity_token, form_authenticity_token %>
34
+
35
+ <div class="mb-4">
36
+ <label for="otp_code" class="block text-sm font-medium mb-1">Verification Code</label>
37
+ <input type="text" id="otp_code" name="otp_code"
38
+ class="w-full px-3 py-2 border border-rsb-border rounded-rsb text-sm focus:outline-none focus:border-rsb-primary focus:ring-2 focus:ring-rsb-primary/10"
39
+ placeholder="Enter 6-digit code"
40
+ autocomplete="one-time-code" inputmode="numeric" autofocus required />
41
+ </div>
42
+
43
+ <button type="submit"
44
+ class="w-full px-4 py-2 bg-rsb-primary text-rsb-primary-text rounded-rsb text-sm font-medium hover:bg-rsb-primary-hover">
45
+ Confirm & Enable 2FA
46
+ </button>
47
+ <% end %>
48
+
49
+ <div class="mt-4 text-center">
50
+ <a href="<%= rsb_admin.profile_path %>" class="text-sm text-rsb-muted hover:underline">Cancel</a>
51
+ </div>
52
+ </div>
53
+ </div>
@@ -0,0 +1,140 @@
1
+ en:
2
+ rsb:
3
+ admin:
4
+ shared:
5
+ dashboard: "Dashboard"
6
+ sign_out: "Sign out"
7
+ switch_language: "Switch language"
8
+ save: "Save"
9
+ cancel: "Cancel"
10
+ delete: "Delete"
11
+ edit: "Edit"
12
+ view: "View"
13
+ new: "New %{resource}"
14
+ back: "Back"
15
+ confirm_delete: "Are you sure you want to delete this %{resource}? This action cannot be undone."
16
+ no_results: "No %{resource} found"
17
+ no_results_message: "%{resource} will appear here once created."
18
+ showing: "Showing %{from}-%{to} of %{total}"
19
+ previous: "Previous"
20
+ next: "Next"
21
+ page: "Page %{number}"
22
+ filters: "Filters"
23
+ clear_filters: "Clear"
24
+ apply_filters: "Apply"
25
+ all: "All"
26
+ system: "System"
27
+ danger_zone: "Danger Zone"
28
+ required: "required"
29
+ no_access: "No access"
30
+ access_denied: "Access Denied"
31
+ access_denied_message: "You don't have permission to access this page."
32
+ go_to_dashboard: "Go to Dashboard"
33
+ sign_out_and_try: "Sign out"
34
+ panel_disabled: "Admin Panel Disabled"
35
+ panel_disabled_message: "The admin panel is temporarily disabled. Contact your system administrator or set RSB_ADMIN_ENABLED=true to re-enable."
36
+ sessions:
37
+ sign_in: "Sign in"
38
+ email: "Email"
39
+ password: "Password"
40
+ sign_in_button: "Sign in"
41
+ signed_out: "Signed out successfully."
42
+ invalid_credentials: "Invalid email or password."
43
+ settings:
44
+ title: "Settings"
45
+ locked: "Locked"
46
+ save: "Save Settings"
47
+ saved: "Setting updated."
48
+ admin_users:
49
+ title: "Admin Users"
50
+ you: "You"
51
+ no_role: "No Role"
52
+ leave_blank: "Leave blank to keep current password"
53
+ min_password: "Minimum 8 characters"
54
+ confirm_password: "Confirm Password"
55
+ role: "Role"
56
+ no_role_hint: "Admins without a role have no access to any admin features."
57
+ last_sign_in: "Last Sign In"
58
+ last_ip: "Last IP"
59
+ never: "Never"
60
+ never_signed_in: "Never signed in"
61
+ confirm_delete: "Are you sure you want to delete this admin user? This action cannot be undone."
62
+ actions: "Actions"
63
+ roles:
64
+ title: "Roles"
65
+ superadmin: "Superadmin"
66
+ custom: "Custom"
67
+ built_in: "Built-in"
68
+ full_access: "Full access to all resources"
69
+ no_permissions: "No permissions assigned"
70
+ permissions: "Permissions"
71
+ superadmin_toggle: "Grant full access to all resources"
72
+ admin_users_count: "Admin Users"
73
+ actions: "Actions"
74
+ confirm_delete: "Are you sure you want to delete this role? Admin users assigned to it will lose their permissions."
75
+ reassign_warning: "This role is assigned to %{count} admin user(s). You must reassign them before deleting."
76
+ pages: "Pages"
77
+ dashboard: "Dashboard"
78
+ dashboard:
79
+ title: "Dashboard"
80
+ guide_title: "Customize Your Dashboard"
81
+ guide_description: "This is the default dashboard. Register a custom dashboard page to replace it with your own content."
82
+ guide_step1: "1. Register your dashboard controller in an initializer:"
83
+ guide_step2: "2. Create your controller with the actions you need:"
84
+ resources:
85
+ created: "%{resource} created."
86
+ updated: "%{resource} updated."
87
+ deleted: "%{resource} deleted."
88
+ page_placeholder: "This page is provided by an extension. Implement the controller at %{controller} to customize it."
89
+ columns:
90
+ id: "ID"
91
+ email: "Email"
92
+ status: "Status"
93
+ created_at: "Created"
94
+ updated_at: "Updated"
95
+ name: "Name"
96
+ errors:
97
+ prohibited: "%{count} error(s) prohibited this record from being saved:"
98
+ theme:
99
+ toggle_dark: "Dark mode"
100
+ toggle_light: "Light mode"
101
+ footer:
102
+ powered_by: "Powered by RSB"
103
+ profile:
104
+ title: "Profile"
105
+ edit_title: "Edit Profile"
106
+ current_email: "Email"
107
+ current_role: "Role"
108
+ last_sign_in: "Last Sign In"
109
+ last_ip: "Last IP"
110
+ edit_button: "Edit Profile"
111
+ current_password: "Current Password"
112
+ current_password_hint: "Required to confirm changes"
113
+ new_password: "New Password"
114
+ new_password_hint: "Leave blank to keep current password"
115
+ confirm_password: "Confirm New Password"
116
+ password_incorrect: "Current password is incorrect"
117
+ updated: "Profile updated successfully."
118
+ verification_sent: "A verification email has been sent to your new email address."
119
+ verification_resent: "Verification email resent."
120
+ verification_invalid: "Verification link is invalid or has expired."
121
+ verification_expired: "Verification link has expired. Please request a new one from your profile."
122
+ email_verified: "Email verified and updated successfully."
123
+ pending_email: "Pending Email"
124
+ verification_sent_ago: "Verification sent %{time} ago"
125
+ resend_verification: "Resend"
126
+ pending_email_hint: "A verification email was sent to %{email}. Changing the email above will send a new verification."
127
+ sessions_title: "Active Sessions"
128
+ current_session: "Current"
129
+ "on": "on"
130
+ active_now: "Active now"
131
+ last_active: "Active %{time} ago"
132
+ revoke_session: "Revoke"
133
+ revoke_all_sessions: "Revoke all other sessions"
134
+ confirm_revoke_all: "Are you sure you want to revoke all other sessions? You will remain signed in on this device only."
135
+ session_revoked: "Session revoked."
136
+ all_sessions_revoked:
137
+ one: "1 session revoked."
138
+ other: "%{count} sessions revoked."
139
+ session_not_found: "Session not found."
140
+ cannot_revoke_current: "Cannot revoke your current session."
@@ -0,0 +1,21 @@
1
+ en:
2
+ rsb:
3
+ admin:
4
+ sessions:
5
+ new:
6
+ page_title: "Admin Sign In"
7
+ dashboard:
8
+ page_title: "Dashboard"
9
+ settings:
10
+ page_title: "Settings"
11
+ profile:
12
+ show:
13
+ page_title: "Profile"
14
+ edit:
15
+ page_title: "Edit Profile"
16
+ roles:
17
+ index:
18
+ page_title: "Roles"
19
+ admin_users:
20
+ index:
21
+ page_title: "Admin Users"
data/config/routes.rb ADDED
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSB::Admin::Engine.routes.draw do
4
+ get 'login', to: 'sessions#new', as: :login
5
+ post 'login', to: 'sessions#create'
6
+ get 'login/two_factor', to: 'sessions#two_factor', as: :two_factor_login
7
+ post 'login/two_factor', to: 'sessions#verify_two_factor', as: :verify_two_factor_login
8
+ delete 'logout', to: 'sessions#destroy', as: :logout
9
+
10
+ root to: 'dashboard#index', as: :dashboard
11
+
12
+ # Dashboard sub-actions (tab navigation for custom dashboard pages)
13
+ get 'dashboard/:action_key', to: 'dashboard#dashboard_action', as: :dashboard_action,
14
+ constraints: { action_key: /[a-z_]+/ }
15
+ post 'dashboard/:action_key', to: 'dashboard#dashboard_action', constraints: { action_key: /[a-z_]+/ }
16
+ patch 'dashboard/:action_key', to: 'dashboard#dashboard_action', constraints: { action_key: /[a-z_]+/ }
17
+ delete 'dashboard/:action_key', to: 'dashboard#dashboard_action', constraints: { action_key: /[a-z_]+/ }
18
+
19
+ get 'settings', to: 'settings#index', as: :settings
20
+ patch 'settings', to: 'settings#batch_update'
21
+ patch 'settings/:category/:key', to: 'settings#update', as: :setting
22
+
23
+ get 'profile', to: 'profile#show', as: :profile
24
+ get 'profile/edit', to: 'profile#edit', as: :edit_profile
25
+ patch 'profile', to: 'profile#update'
26
+ get 'profile/verify_email', to: 'profile#verify_email', as: :verify_email_profile
27
+ post 'profile/resend_verification', to: 'profile#resend_verification', as: :resend_verification_profile
28
+ get 'profile/two_factor/new', to: 'two_factor#new', as: :new_profile_two_factor
29
+ post 'profile/two_factor', to: 'two_factor#create', as: :profile_two_factor
30
+ get 'profile/two_factor/backup_codes', to: 'two_factor#backup_codes', as: :profile_two_factor_backup_codes
31
+ delete 'profile/two_factor', to: 'two_factor#destroy'
32
+ delete 'profile/sessions', to: 'profile_sessions#destroy_all', as: :profile_sessions
33
+ delete 'profile/sessions/:id', to: 'profile_sessions#destroy', as: :profile_session
34
+
35
+ resources :roles
36
+ resources :admin_users
37
+
38
+ # Dynamic resource routes for registered resources.
39
+ # These catch-all routes must be LAST so they don't override static routes above.
40
+ # Order matters: specific patterns before generic ':id' patterns.
41
+ get ':resource_key/new', to: 'resources#new'
42
+ post ':resource_key', to: 'resources#create'
43
+
44
+ # Static page sub-actions (must be before catch-all :id routes)
45
+ get ':resource_key/:action_key', to: 'resources#page_action', constraints: { action_key: /[a-z_]+/ }
46
+ post ':resource_key/:action_key', to: 'resources#page_action', constraints: { action_key: /[a-z_]+/ }
47
+ delete ':resource_key/:action_key', to: 'resources#page_action', constraints: { action_key: /[a-z_]+/ }
48
+ patch ':resource_key/:action_key', to: 'resources#page_action', constraints: { action_key: /[a-z_]+/ }
49
+
50
+ get ':resource_key/:id/edit', to: 'resources#edit'
51
+ patch ':resource_key/:id', to: 'resources#update'
52
+ put ':resource_key/:id', to: 'resources#update'
53
+ delete ':resource_key/:id', to: 'resources#destroy'
54
+ get ':resource_key/:id/:custom_action', to: 'resources#custom_action'
55
+ post ':resource_key/:id/:custom_action', to: 'resources#custom_action'
56
+ patch ':resource_key/:id/:custom_action', to: 'resources#custom_action'
57
+ get ':resource_key/:id', to: 'resources#show'
58
+ get ':resource_key', to: 'resources#index'
59
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreateRSBAdminTables < ActiveRecord::Migration[8.0]
4
+ def change
5
+ create_table :rsb_admin_roles do |t|
6
+ t.string :name, null: false
7
+ t.json :permissions, null: false, default: {}
8
+ t.boolean :built_in, default: false
9
+ t.timestamps
10
+ end
11
+
12
+ add_index :rsb_admin_roles, :name, unique: true
13
+
14
+ create_table :rsb_admin_admin_users do |t|
15
+ t.string :email, null: false
16
+ t.string :password_digest, null: false
17
+ t.references :role, foreign_key: { to_table: :rsb_admin_roles }
18
+ t.datetime :last_sign_in_at
19
+ t.string :last_sign_in_ip
20
+ t.string :pending_email
21
+ t.string :email_verification_token
22
+ t.datetime :email_verification_sent_at
23
+ t.timestamps
24
+ end
25
+
26
+ add_index :rsb_admin_admin_users, :email, unique: true
27
+ add_index :rsb_admin_admin_users, :email_verification_token, unique: true
28
+
29
+ create_table :rsb_admin_admin_sessions do |t|
30
+ t.references :admin_user, null: false, foreign_key: { to_table: :rsb_admin_admin_users }
31
+ t.string :session_token, null: false
32
+ t.string :ip_address
33
+ t.text :user_agent
34
+ t.string :browser
35
+ t.string :os
36
+ t.string :device_type
37
+ t.datetime :last_active_at, null: false
38
+ t.timestamps
39
+ end
40
+
41
+ add_index :rsb_admin_admin_sessions, :session_token, unique: true
42
+ end
43
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AddOtpFieldsToRSBAdminAdminUsers < ActiveRecord::Migration[8.0]
4
+ def change
5
+ add_column :rsb_admin_admin_users, :otp_secret, :string
6
+ add_column :rsb_admin_admin_users, :otp_required, :boolean, null: false, default: false
7
+ add_column :rsb_admin_admin_users, :otp_backup_codes, :text
8
+ end
9
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RSB
4
+ module Admin
5
+ class InstallGenerator < Rails::Generators::Base
6
+ namespace 'rsb:admin:install'
7
+ source_root File.expand_path('templates', __dir__)
8
+
9
+ desc 'Install rsb-admin: copy migrations, mount routes, and create seed file.'
10
+
11
+ # Copies rsb-admin migrations to the host application.
12
+ # @return [void]
13
+ def copy_migrations
14
+ rake 'rsb_admin:install:migrations'
15
+ end
16
+
17
+ # Mounts the rsb-admin engine at /admin in the host application's routes.
18
+ # @return [void]
19
+ def mount_routes
20
+ route 'mount RSB::Admin::Engine => "/admin"'
21
+ end
22
+
23
+ # Copies the seed file template to db/seeds/rsb_admin.rb.
24
+ # Uses skip: true to avoid overwriting existing seed files.
25
+ # @return [void]
26
+ def copy_seed_file
27
+ copy_file 'rsb_admin_seeds.rb', 'db/seeds/rsb_admin.rb', skip: true
28
+ end
29
+
30
+ # Prints post-installation instructions.
31
+ # @return [void]
32
+ def print_post_install
33
+ say ''
34
+ say 'rsb-admin installed successfully!', :green
35
+ say ''
36
+ say 'Next steps:'
37
+ say ' 1. rails db:migrate'
38
+ say ' 2. rails rsb:create_admin EMAIL=admin@example.com PASSWORD=changeme'
39
+ say ' OR edit db/seeds/rsb_admin.rb and run: rails db:seed'
40
+ say ' 3. Visit /admin/login'
41
+ say ''
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ # RSB Admin Seed Data
4
+ #
5
+ # This file creates a default Superadmin role and initial admin user.
6
+ # Uncomment and customize the values below, then run:
7
+ #
8
+ # rails db:seed
9
+ #
10
+ # Alternatively, use the rake task for a quick one-off setup:
11
+ #
12
+ # rails rsb:create_admin EMAIL=admin@example.com PASSWORD=changeme
13
+ #
14
+
15
+ # role = RSB::Admin::Role.find_or_create_by!(name: "Superadmin") do |r|
16
+ # r.permissions = { "*" => ["*"] }
17
+ # r.built_in = true
18
+ # end
19
+ #
20
+ # RSB::Admin::AdminUser.find_or_create_by!(email: "admin@example.com") do |u|
21
+ # u.password = "changeme123"
22
+ # u.password_confirmation = "changeme123"
23
+ # u.role = role
24
+ # end
@@ -0,0 +1,66 @@
1
+ /* <%= theme_name.titleize %> Theme for RSB Admin
2
+ *
3
+ * This file defines all CSS variables required by RSB Admin.
4
+ * Every --rsb-admin-* variable MUST be defined — there is no
5
+ * inheritance from the default theme. Missing variables will
6
+ * produce empty values, which may break layout.
7
+ *
8
+ * Customize the values below to create your theme.
9
+ */
10
+
11
+ :root {
12
+ /* ── Background ─────────────────────────────────── */
13
+ --rsb-admin-bg: #f9fafb; /* Page background */
14
+ --rsb-admin-bg-secondary: #f3f4f6; /* Secondary/alternate background */
15
+ --rsb-admin-card-bg: #ffffff; /* Card/panel background */
16
+
17
+ /* ── Text ───────────────────────────────────────── */
18
+ --rsb-admin-text: #111827; /* Primary text color */
19
+ --rsb-admin-text-muted: #6b7280; /* Muted/secondary text */
20
+
21
+ /* ── Borders ────────────────────────────────────── */
22
+ --rsb-admin-border: #e5e7eb; /* Default border color */
23
+
24
+ /* ── Primary action ─────────────────────────────── */
25
+ --rsb-admin-primary: #4f46e5; /* Primary buttons, links */
26
+ --rsb-admin-primary-hover: #4338ca; /* Primary hover state */
27
+ --rsb-admin-primary-text: #ffffff; /* Text on primary backgrounds */
28
+
29
+ /* ── Status: Success ────────────────────────────── */
30
+ --rsb-admin-success: #16a34a; /* Success accent */
31
+ --rsb-admin-success-bg: #ecfdf5; /* Success background */
32
+ --rsb-admin-success-text: #065f46; /* Success text */
33
+
34
+ /* ── Status: Warning ────────────────────────────── */
35
+ --rsb-admin-warning: #d97706; /* Warning accent */
36
+ --rsb-admin-warning-bg: #fffbeb; /* Warning background */
37
+ --rsb-admin-warning-text: #92400e; /* Warning text */
38
+
39
+ /* ── Status: Danger ─────────────────────────────── */
40
+ --rsb-admin-danger: #dc2626; /* Danger accent */
41
+ --rsb-admin-danger-bg: #fef2f2; /* Danger background */
42
+ --rsb-admin-danger-text: #991b1b; /* Danger text */
43
+
44
+ /* ── Status: Info ───────────────────────────────── */
45
+ --rsb-admin-info: #2563eb; /* Info accent */
46
+ --rsb-admin-info-bg: #eff6ff; /* Info background */
47
+ --rsb-admin-info-text: #1e40af; /* Info text */
48
+
49
+ /* ── Sidebar ────────────────────────────────────── */
50
+ --rsb-admin-sidebar-bg: #1f2937; /* Sidebar background */
51
+ --rsb-admin-sidebar-text: #d1d5db; /* Sidebar text */
52
+ --rsb-admin-sidebar-active: #4f46e5; /* Sidebar active indicator */
53
+ --rsb-admin-sidebar-hover-bg: rgba(255,255,255,0.05); /* Sidebar hover */
54
+
55
+ /* ── Shape ──────────────────────────────────────── */
56
+ --rsb-admin-radius-sm: 0.25rem; /* Small border radius */
57
+ --rsb-admin-radius: 0.375rem; /* Default border radius */
58
+ --rsb-admin-radius-lg: 0.5rem; /* Large border radius */
59
+
60
+ /* ── Shadows ────────────────────────────────────── */
61
+ --rsb-admin-shadow-sm: 0 1px 2px rgba(0,0,0,0.05);
62
+ --rsb-admin-shadow: 0 1px 3px rgba(0,0,0,0.1), 0 1px 2px rgba(0,0,0,0.06);
63
+
64
+ /* ── Transitions ────────────────────────────────── */
65
+ --rsb-admin-transition: 0.15s; /* Default transition duration */
66
+ }