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
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 3071fe9fb7627de15eb032d8ae6c15059f3131b3f1b659621a39e642a6222bdc
4
+ data.tar.gz: 9a80f870291efcc587c5c065e8daad3435e07ef3cf2fede88b2a5146f6a7fe91
5
+ SHA512:
6
+ metadata.gz: 04bcb5b79f9670a8037d46ad7de412c4c2dea86419ae707a51504971e6e70cede74005ee6db11d20d8339055cd1b03a022fe964b869e166420c5a0a2197caf95
7
+ data.tar.gz: be1e160d6579cfd6cb1c1a08e0ccb9d5adc30bc39cd16ca1a09df3b255896ed98d77caa1a97377b932ab9e6d49a82b29509622a680fc825d4b4068c8de13c125
data/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ Rails SaaS Builder (RSB)
2
+ Copyright (C) 2026 Aleksandr Marchenko
3
+
4
+ This program is free software: you can redistribute it and/or modify
5
+ it under the terms of the GNU Lesser General Public License as published by
6
+ the Free Software Foundation, either version 3 of the License, or
7
+ (at your option) any later version.
8
+
9
+ This program is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU Lesser General Public License for more details.
13
+
14
+ You should have received a copy of the GNU Lesser General Public License
15
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
data/README.md ADDED
@@ -0,0 +1,83 @@
1
+ # rsb-admin
2
+
3
+ Lightweight, registrable admin panel for Rails SaaS Builder. Features dynamic resource CRUD, role-based access control with granular permissions, settings management, multi-theme support, and optional two-factor authentication. Other gems register resources and pages lazily via `ActiveSupport.on_load(:rsb_admin)`.
4
+
5
+ ## Installation
6
+
7
+ ### As part of Rails SaaS Builder
8
+
9
+ ```ruby
10
+ gem "rails-saas-builder"
11
+ ```
12
+
13
+ ### Standalone
14
+
15
+ ```ruby
16
+ gem "rsb-admin"
17
+ ```
18
+
19
+ Then run:
20
+
21
+ ```bash
22
+ bundle install
23
+ rails generate rsb_admin:install
24
+ rails db:migrate
25
+ ```
26
+
27
+ ## Key Features
28
+
29
+ - Dynamic resource registration with DSL (columns, filters, form fields)
30
+ - Role-based access control with per-resource, per-action permissions
31
+ - Settings management page (tabbed by category)
32
+ - Built-in themes: default and modern (dark/light)
33
+ - Admin user management with email verification
34
+ - Two-factor authentication (TOTP with backup codes)
35
+ - Session management and device tracking
36
+ - Breadcrumb navigation and pagination
37
+ - Test kit for extension developers
38
+ - Lazy resource registration via `on_load(:rsb_admin)` hooks
39
+
40
+ ## Basic Usage
41
+
42
+ ```ruby
43
+ # Register resources from another gem
44
+ ActiveSupport.on_load(:rsb_admin) do |registry|
45
+ registry.register_category "Content" do
46
+ resource Post, icon: "file-text", actions: [:index, :show, :edit, :update] do
47
+ column :title, sortable: true, link: true
48
+ column :status, formatter: :badge
49
+ filter :status, type: :select, options: %w[draft published]
50
+ form_field :title, type: :text, required: true
51
+ form_field :body, type: :textarea
52
+ end
53
+ end
54
+ end
55
+ ```
56
+
57
+ ## Configuration
58
+
59
+ ```ruby
60
+ RSB::Admin.configure do |config|
61
+ config.app_name = "My SaaS Admin"
62
+ config.company_name = "Acme Inc"
63
+ config.theme = :modern
64
+ end
65
+ ```
66
+
67
+ ## Test Kit
68
+
69
+ ```ruby
70
+ # In your integration tests
71
+ include RSB::Admin::TestKit::Helpers
72
+
73
+ admin = create_test_admin!(superadmin: true)
74
+ sign_in_admin(admin)
75
+ ```
76
+
77
+ ## Documentation
78
+
79
+ Part of [Rails SaaS Builder](../README.md). See the main README for the full picture.
80
+
81
+ ## License
82
+
83
+ [LGPL-3.0](../LICENSE)
data/Rakefile ADDED
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'fileutils'
5
+ require 'rake/testtask'
6
+
7
+ task :prepare_test_db do
8
+ ENV['RAILS_ENV'] = 'test'
9
+ db = File.expand_path('test/dummy/db/test.sqlite3', __dir__)
10
+ FileUtils.rm_f(db)
11
+ require_relative 'test/dummy/config/environment'
12
+ ActiveRecord::Migration.verbose = false
13
+ ActiveRecord::MigrationContext.new(Rails.application.paths['db/migrate'].to_a).migrate
14
+ schema = File.expand_path('test/dummy/db/schema.rb', __dir__)
15
+ File.open(schema, 'w') { |f| ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection_pool, f) }
16
+ end
17
+
18
+ Rake::TestTask.new(:test) do |t|
19
+ t.libs << 'test'
20
+ t.pattern = 'test/**/*_test.rb'
21
+ t.verbose = false
22
+ end
23
+
24
+ task test: :prepare_test_db
25
+ task default: :test
@@ -0,0 +1,37 @@
1
+ (function() {
2
+ var STORAGE_KEY = 'rsb-admin-mode';
3
+
4
+ function getPreferred() {
5
+ var stored = localStorage.getItem(STORAGE_KEY);
6
+ if (stored) return stored;
7
+ return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
8
+ }
9
+
10
+ function apply(mode) {
11
+ document.documentElement.setAttribute('data-rsb-mode', mode);
12
+ localStorage.setItem(STORAGE_KEY, mode);
13
+ }
14
+
15
+ // Apply on load (rule #17)
16
+ apply(getPreferred());
17
+
18
+ // Toggle function exposed globally for the button
19
+ window.rsbToggleMode = function() {
20
+ var current = document.documentElement.getAttribute('data-rsb-mode');
21
+ apply(current === 'dark' ? 'light' : 'dark');
22
+ };
23
+
24
+ // Sidebar section collapse/expand toggle
25
+ window.rsbToggleSection = function(id) {
26
+ var content = document.getElementById(id);
27
+ var chevron = document.getElementById(id + '-chevron');
28
+ if (!content) return;
29
+ if (content.classList.contains('hidden')) {
30
+ content.classList.remove('hidden');
31
+ if (chevron) chevron.classList.add('rotate-90');
32
+ } else {
33
+ content.classList.add('hidden');
34
+ if (chevron) chevron.classList.remove('rotate-90');
35
+ }
36
+ };
37
+ })();