super_admin 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.
Files changed (100) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +216 -0
  3. data/Rakefile +30 -0
  4. data/app/assets/stylesheets/super_admin/application.css +15 -0
  5. data/app/assets/stylesheets/super_admin/tailwind.css +1 -0
  6. data/app/assets/stylesheets/super_admin/tailwind.source.css +25 -0
  7. data/app/controllers/super_admin/application_controller.rb +89 -0
  8. data/app/controllers/super_admin/associations_controller.rb +136 -0
  9. data/app/controllers/super_admin/audit_logs_controller.rb +39 -0
  10. data/app/controllers/super_admin/base_controller.rb +133 -0
  11. data/app/controllers/super_admin/dashboard_controller.rb +29 -0
  12. data/app/controllers/super_admin/exports_controller.rb +109 -0
  13. data/app/controllers/super_admin/resources_controller.rb +201 -0
  14. data/app/dashboards/super_admin/base_dashboard.rb +200 -0
  15. data/app/errors/super_admin/configuration_error.rb +6 -0
  16. data/app/helpers/super_admin/application_helper.rb +84 -0
  17. data/app/helpers/super_admin/exports_helper.rb +16 -0
  18. data/app/helpers/super_admin/resources_helper.rb +204 -0
  19. data/app/helpers/super_admin/route_helper.rb +7 -0
  20. data/app/javascript/super_admin/application.js +263 -0
  21. data/app/jobs/super_admin/application_job.rb +4 -0
  22. data/app/jobs/super_admin/generate_super_admin_csv_export_job.rb +100 -0
  23. data/app/mailers/super_admin/application_mailer.rb +6 -0
  24. data/app/models/super_admin/application_record.rb +5 -0
  25. data/app/models/super_admin/audit_log.rb +35 -0
  26. data/app/models/super_admin/csv_export.rb +67 -0
  27. data/app/services/super_admin/auditing.rb +74 -0
  28. data/app/services/super_admin/authorization.rb +113 -0
  29. data/app/services/super_admin/authorization_adapters/base_adapter.rb +100 -0
  30. data/app/services/super_admin/authorization_adapters/default_adapter.rb +77 -0
  31. data/app/services/super_admin/authorization_adapters/proc_adapter.rb +65 -0
  32. data/app/services/super_admin/authorization_adapters/pundit_adapter.rb +81 -0
  33. data/app/services/super_admin/csv_export_creator.rb +45 -0
  34. data/app/services/super_admin/dashboard_registry.rb +90 -0
  35. data/app/services/super_admin/dashboard_resolver.rb +100 -0
  36. data/app/services/super_admin/filter_builder.rb +185 -0
  37. data/app/services/super_admin/form_builder.rb +59 -0
  38. data/app/services/super_admin/form_fields/array_field.rb +35 -0
  39. data/app/services/super_admin/form_fields/association_field.rb +146 -0
  40. data/app/services/super_admin/form_fields/base_field.rb +53 -0
  41. data/app/services/super_admin/form_fields/boolean_field.rb +29 -0
  42. data/app/services/super_admin/form_fields/date_field.rb +15 -0
  43. data/app/services/super_admin/form_fields/date_time_field.rb +15 -0
  44. data/app/services/super_admin/form_fields/enum_field.rb +27 -0
  45. data/app/services/super_admin/form_fields/factory.rb +102 -0
  46. data/app/services/super_admin/form_fields/nested_field.rb +120 -0
  47. data/app/services/super_admin/form_fields/number_field.rb +29 -0
  48. data/app/services/super_admin/form_fields/text_area_field.rb +19 -0
  49. data/app/services/super_admin/model_inspector.rb +182 -0
  50. data/app/services/super_admin/queries/base_query.rb +45 -0
  51. data/app/services/super_admin/queries/filter_query.rb +188 -0
  52. data/app/services/super_admin/queries/resource_scope_query.rb +74 -0
  53. data/app/services/super_admin/queries/search_query.rb +146 -0
  54. data/app/services/super_admin/queries/sort_query.rb +41 -0
  55. data/app/services/super_admin/resource_configuration.rb +63 -0
  56. data/app/services/super_admin/resource_exporter.rb +78 -0
  57. data/app/services/super_admin/resource_query.rb +40 -0
  58. data/app/services/super_admin/resources/association_inspector.rb +112 -0
  59. data/app/services/super_admin/resources/collection_presenter.rb +63 -0
  60. data/app/services/super_admin/resources/context.rb +63 -0
  61. data/app/services/super_admin/resources/filter_params.rb +29 -0
  62. data/app/services/super_admin/resources/permitted_attributes.rb +104 -0
  63. data/app/services/super_admin/resources/value_normalizer.rb +121 -0
  64. data/app/services/super_admin/sensitive_attributes.rb +166 -0
  65. data/app/views/layouts/super_admin.html.erb +74 -0
  66. data/app/views/super_admin/audit_logs/index.html.erb +143 -0
  67. data/app/views/super_admin/dashboard/index.html.erb +79 -0
  68. data/app/views/super_admin/exports/index.html.erb +84 -0
  69. data/app/views/super_admin/exports/show.html.erb +57 -0
  70. data/app/views/super_admin/resources/_form.html.erb +42 -0
  71. data/app/views/super_admin/resources/destroy.turbo_stream.erb +17 -0
  72. data/app/views/super_admin/resources/edit.html.erb +37 -0
  73. data/app/views/super_admin/resources/index.html.erb +189 -0
  74. data/app/views/super_admin/resources/new.html.erb +31 -0
  75. data/app/views/super_admin/resources/show.html.erb +106 -0
  76. data/app/views/super_admin/shared/_breadcrumbs.html.erb +12 -0
  77. data/app/views/super_admin/shared/_custom_styles.html.erb +132 -0
  78. data/app/views/super_admin/shared/_flash.html.erb +55 -0
  79. data/app/views/super_admin/shared/_form_field.html.erb +35 -0
  80. data/app/views/super_admin/shared/_navigation.html.erb +92 -0
  81. data/app/views/super_admin/shared/_nested_fields.html.erb +59 -0
  82. data/app/views/super_admin/shared/_nested_record_fields.html.erb +45 -0
  83. data/config/importmap.rb +4 -0
  84. data/config/initializers/rack_attack.rb +134 -0
  85. data/config/initializers/super_admin.rb +117 -0
  86. data/config/locales/super_admin.en.yml +197 -0
  87. data/config/locales/super_admin.fr.yml +197 -0
  88. data/config/routes.rb +22 -0
  89. data/lib/generators/super_admin/dashboard_generator.rb +50 -0
  90. data/lib/generators/super_admin/install_generator.rb +58 -0
  91. data/lib/generators/super_admin/templates/20240101000001_create_super_admin_audit_logs.rb +24 -0
  92. data/lib/generators/super_admin/templates/20240101000002_create_super_admin_csv_exports.rb +33 -0
  93. data/lib/generators/super_admin/templates/super_admin.rb +58 -0
  94. data/lib/super_admin/dashboard_creator.rb +256 -0
  95. data/lib/super_admin/engine.rb +53 -0
  96. data/lib/super_admin/install_task.rb +96 -0
  97. data/lib/super_admin/version.rb +3 -0
  98. data/lib/super_admin.rb +7 -0
  99. data/lib/tasks/super_admin_tasks.rake +38 -0
  100. metadata +239 -0
@@ -0,0 +1,256 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+ require "pathname"
5
+ require "active_support/inflector"
6
+
7
+ module SuperAdmin
8
+ # Utility object responsible for creating dashboard skeleton files.
9
+ class DashboardCreator
10
+ def self.call(model_name: nil, stdout: $stdout)
11
+ new(model_name:, stdout:).call
12
+ end
13
+
14
+ def initialize(model_name:, stdout:)
15
+ @model_name = model_name
16
+ @stdout = stdout
17
+ end
18
+
19
+ def call
20
+ models = determine_models
21
+
22
+ if models.empty?
23
+ stdout.puts "No models found to generate dashboards for."
24
+ return { generated: [], skipped: [] }
25
+ end
26
+
27
+ generated = []
28
+ skipped = []
29
+
30
+ models.each do |model|
31
+ unless constantizable_model?(model)
32
+ stdout.puts "Skipping #{model.inspect}: model is not constantizable."
33
+ next
34
+ end
35
+
36
+ result = generate_dashboard(model)
37
+ next unless result
38
+
39
+ case result[:status]
40
+ when :generated
41
+ generated << result[:path]
42
+ when :skipped
43
+ skipped << result[:path]
44
+ end
45
+ end
46
+
47
+ print_summary(generated, skipped)
48
+
49
+ { generated:, skipped: }
50
+ end
51
+
52
+ private
53
+
54
+ attr_reader :model_name, :stdout
55
+
56
+ def determine_models
57
+ models = if model_name && !model_name.to_s.strip.empty?
58
+ [ resolve_model(model_name) ]
59
+ else
60
+ SuperAdmin::ModelInspector.discoverable_models
61
+ end
62
+
63
+ Array(models).compact.each_with_object([]) do |model, list|
64
+ if engine_owned_model?(model)
65
+ stdout.puts "Skipping #{model.name}: managed internally by SuperAdmin."
66
+ next
67
+ end
68
+
69
+ list << model
70
+ end
71
+ end
72
+
73
+ def constantizable_model?(model)
74
+ return false unless model.respond_to?(:name)
75
+ name = model.name
76
+ return false if name.nil? || name.empty?
77
+
78
+ constant = name.safe_constantize
79
+ constant == model
80
+ end
81
+
82
+ def resolve_model(name)
83
+ return name if name.is_a?(Class) && name < ActiveRecord::Base
84
+
85
+ constant_name = normalize_model_name(name)
86
+ klass = constant_name.constantize
87
+ if engine_owned_model?(klass)
88
+ raise ArgumentError, "#{constant_name} is managed internally by SuperAdmin and should not receive a dashboard."
89
+ end
90
+ return klass if klass < ActiveRecord::Base
91
+
92
+ raise ArgumentError, "#{constant_name} is not an ActiveRecord model"
93
+ rescue NameError
94
+ raise ArgumentError, "Unable to find model for '#{name}'"
95
+ end
96
+
97
+ def normalize_model_name(name)
98
+ raw = name.to_s.tr("/", "::").split("::").reject(&:empty?)
99
+ segments = raw.map { |segment| segment.underscore.singularize.camelize }
100
+ segments.join("::")
101
+ end
102
+
103
+ def generate_dashboard(model_class)
104
+ if dashboard_exists?(model_class)
105
+ stdout.puts "Skipping #{model_class.name}: dashboard already exists."
106
+ return { status: :skipped, path: relative_dashboard_path(model_class).to_s }
107
+ end
108
+
109
+ path = absolute_dashboard_path(model_class)
110
+ FileUtils.mkdir_p(path.dirname)
111
+ File.write(path, dashboard_template(model_class))
112
+ stdout.puts "Created #{relative_dashboard_path(model_class)}"
113
+
114
+ { status: :generated, path: relative_dashboard_path(model_class).to_s }
115
+ end
116
+
117
+ def dashboard_exists?(model_class)
118
+ registry = SuperAdmin::DashboardRegistry.instance
119
+ return true if registry.dashboard_for(model_class)
120
+
121
+ absolute_dashboard_path(model_class).exist?
122
+ end
123
+
124
+ def absolute_dashboard_path(model_class)
125
+ Rails.root.join(relative_dashboard_path(model_class))
126
+ end
127
+
128
+ def relative_dashboard_path(model_class)
129
+ Pathname.new(File.join("app", "dashboards", "super_admin", *namespace_segments(model_class), "#{model_basename(model_class)}_dashboard.rb"))
130
+ end
131
+
132
+ def namespace_segments(model_class)
133
+ relative_namespace_constants(model_class).map { |segment| segment.underscore }
134
+ end
135
+
136
+ def namespace_constants(model_class)
137
+ namespace = model_class.name.deconstantize
138
+ return [] if namespace.empty?
139
+
140
+ namespace.split("::")
141
+ end
142
+
143
+ def relative_namespace_constants(model_class)
144
+ segments = namespace_constants(model_class)
145
+ segments.shift if segments.first == root_namespace
146
+ segments
147
+ end
148
+
149
+ def model_basename(model_class)
150
+ model_class.name.demodulize.underscore
151
+ end
152
+
153
+ def dashboard_template(model_class)
154
+ collection_attrs = default_collection_attributes(model_class)
155
+ show_attrs = default_show_attributes(model_class)
156
+ form_attrs = default_form_attributes(model_class)
157
+
158
+ lines = []
159
+ lines << "# frozen_string_literal: true"
160
+ lines << ""
161
+
162
+ indent = 0
163
+ append(lines, indent, "module SuperAdmin")
164
+ indent += 1
165
+
166
+ relative_namespace_constants(model_class).each do |namespace|
167
+ append(lines, indent, "module #{namespace}")
168
+ indent += 1
169
+ end
170
+
171
+ append(lines, indent, "class #{model_class.name.demodulize}Dashboard < SuperAdmin::BaseDashboard")
172
+ indent += 1
173
+ append(lines, indent, "resource #{model_class.name}")
174
+ append_attribute_declaration(lines, indent, "collection_attributes", collection_attrs)
175
+ append_attribute_declaration(lines, indent, "show_attributes", show_attrs)
176
+ append_attribute_declaration(lines, indent, "form_attributes", form_attrs)
177
+ indent -= 1
178
+ append(lines, indent, "end")
179
+
180
+ relative_namespace_constants(model_class).reverse_each do |_namespace|
181
+ indent -= 1
182
+ append(lines, indent, "end")
183
+ end
184
+
185
+ indent -= 1
186
+ append(lines, indent, "end")
187
+
188
+ lines.join("\n") + "\n"
189
+ end
190
+
191
+ def append(lines, indent, text)
192
+ lines << (" " * indent + text)
193
+ end
194
+
195
+ def append_attribute_declaration(lines, indent, macro, attributes)
196
+ return if attributes.empty?
197
+
198
+ append(lines, indent, "#{macro} #{format_attribute_list(attributes, indent)}")
199
+ end
200
+
201
+ def default_collection_attributes(model_class)
202
+ SuperAdmin::ResourceConfiguration
203
+ .displayable_attributes(model_class)
204
+ .map { |attr| normalize_attribute_name(attr) }
205
+ end
206
+
207
+ def default_show_attributes(model_class)
208
+ SuperAdmin::ResourceConfiguration
209
+ .displayable_attributes(model_class)
210
+ .map { |attr| normalize_attribute_name(attr) }
211
+ end
212
+
213
+ def default_form_attributes(model_class)
214
+ SuperAdmin::ResourceConfiguration
215
+ .editable_attributes(model_class)
216
+ .map { |attr| normalize_attribute_name(attr) }
217
+ end
218
+
219
+ def normalize_attribute_name(attribute)
220
+ attribute.is_a?(Symbol) ? attribute : attribute.to_s.to_sym
221
+ end
222
+
223
+ def format_attribute_list(attributes, indent)
224
+ tokens = attributes.map { |attr| ":#{attr}" }
225
+ single_line = tokens.join(", ")
226
+ return single_line if single_line.length <= 80
227
+
228
+ continuation_indent = "\n" + (" " * indent) + " "
229
+ tokens.join(",#{continuation_indent}")
230
+ end
231
+
232
+ def root_namespace
233
+ "SuperAdmin"
234
+ end
235
+
236
+ def engine_owned_model?(model)
237
+ model.name.start_with?("#{root_namespace}::")
238
+ end
239
+
240
+ def print_summary(generated, skipped)
241
+ stdout.puts
242
+ stdout.puts "Dashboards generated: #{generated.count}"
243
+ stdout.puts " - #{generated.join("\n - ")}" if generated.any?
244
+ stdout.puts "Dashboards skipped: #{skipped.count}"
245
+ stdout.puts " - #{skipped.join("\n - ")}" if skipped.any?
246
+
247
+ if generated.empty?
248
+ if skipped.any?
249
+ stdout.puts "No dashboards created; all models already have dashboards."
250
+ else
251
+ stdout.puts "No dashboards created."
252
+ end
253
+ end
254
+ end
255
+ end
256
+ end
@@ -0,0 +1,53 @@
1
+ module SuperAdmin
2
+ # :nocov:
3
+ class Engine < ::Rails::Engine
4
+ isolate_namespace SuperAdmin
5
+
6
+ initializer "super_admin.assets" do |app|
7
+ # Add engine's JavaScript to asset paths so they can be served
8
+ app.config.assets.paths << root.join("app/javascript") if app.config.respond_to?(:assets)
9
+ # Add engine's stylesheets to asset paths for propshaft/sprockets
10
+ app.config.assets.paths << root.join("app/assets/stylesheets") if app.config.respond_to?(:assets)
11
+ end
12
+
13
+ initializer "super_admin.importmap", before: "importmap" do |app|
14
+ # Register SuperAdmin importmap if importmap-rails is available
15
+ if app.config.respond_to?(:importmap)
16
+ app.config.importmap.paths << root.join("config/importmap.rb")
17
+ app.config.importmap.cache_sweepers << root.join("app/javascript")
18
+ end
19
+ end
20
+
21
+ initializer "super_admin.route_helpers" do
22
+ require_relative "../../app/helpers/super_admin/route_helper"
23
+
24
+ ActiveSupport.on_load(:action_view) do
25
+ include ::SuperAdmin::RouteHelper
26
+ end
27
+
28
+ ActiveSupport.on_load(:action_controller) do
29
+ helper ::SuperAdmin::RouteHelper
30
+ end
31
+
32
+ config.to_prepare do
33
+ if defined?(ViewComponent::Base) && !ViewComponent::Base.included_modules.include?(::SuperAdmin::RouteHelper)
34
+ ViewComponent::Base.include(::SuperAdmin::RouteHelper)
35
+ end
36
+
37
+ if defined?(ActionView::Component::Base) && !ActionView::Component::Base.included_modules.include?(::SuperAdmin::RouteHelper)
38
+ ActionView::Component::Base.include(::SuperAdmin::RouteHelper)
39
+ end
40
+ end
41
+ end
42
+
43
+ initializer "super_admin.rack_attack", after: :load_config_initializers do
44
+ # Load Rack::Attack configuration for SuperAdmin endpoints
45
+ if defined?(Rack::Attack)
46
+ require "rack-attack"
47
+ config_file = root.join("config/initializers/rack_attack.rb")
48
+ load(config_file) if config_file.exist?
49
+ end
50
+ end
51
+ end
52
+ # :nocov:
53
+ end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+ require "pathname"
5
+
6
+ module SuperAdmin
7
+ # Handles bootstrapping host applications with required SuperAdmin assets.
8
+ class InstallTask
9
+ INITIALIZER_PATH = "config/initializers/super_admin.rb"
10
+
11
+ def self.call(stdout: $stdout)
12
+ new(stdout:).call
13
+ end
14
+
15
+ def initialize(stdout: $stdout)
16
+ @stdout = stdout
17
+ @engine_root = Pathname.new(SuperAdmin::Engine.root)
18
+ @app_root = Pathname.new(Rails.root)
19
+ end
20
+
21
+ def call
22
+ copy_initializer
23
+ copy_migrations
24
+ stdout.puts "SuperAdmin installation complete."
25
+ end
26
+
27
+ # Public method for copying migrations (used by rake task)
28
+ def copy_migrations
29
+ migration_files.each do |source_path|
30
+ copy_migration(source_path)
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ attr_reader :stdout, :engine_root, :app_root
37
+
38
+ def copy_initializer
39
+ target = app_root.join(INITIALIZER_PATH)
40
+ if target.exist?
41
+ stdout.puts "Initializer already exists at #{relative_to_app(target)} (skipping)."
42
+ return
43
+ end
44
+
45
+ source = engine_root.join(INITIALIZER_PATH)
46
+ FileUtils.mkdir_p(target.dirname)
47
+ FileUtils.cp(source, target)
48
+ stdout.puts "Initializer copied to #{relative_to_app(target)}."
49
+ end
50
+
51
+ def migration_files
52
+ # Dir[] does not guarantee order, so we must sort to preserve migration sequence.
53
+ # We filter to only include files starting with a timestamp (e.g., 20240101000001_)
54
+ # to avoid copying non-migration files like super_admin.rb
55
+ Dir[engine_root.join("lib", "generators", "super_admin", "templates", "*.rb")]
56
+ .select { |f| File.basename(f) =~ /^\d+_/ }
57
+ .sort
58
+ end
59
+
60
+ def copy_migration(source_path)
61
+ basename = File.basename(source_path).sub(/^\d+_/, "")
62
+
63
+ if migration_exists?(basename)
64
+ stdout.puts "Migration #{basename} already present (skipping)."
65
+ return
66
+ end
67
+
68
+ timestamp = next_migration_timestamp
69
+ target = app_root.join("db", "migrate", "#{timestamp}_#{basename}")
70
+ FileUtils.mkdir_p(target.dirname)
71
+ FileUtils.cp(source_path, target)
72
+ stdout.puts "Migration created at #{relative_to_app(target)}."
73
+ end
74
+
75
+ def migration_exists?(basename)
76
+ Dir[app_root.join("db", "migrate", "*_#{basename}").to_s].any?
77
+ end
78
+
79
+ def next_migration_timestamp
80
+ now = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i
81
+ @migration_counter ||= begin
82
+ existing = Dir[app_root.join("db", "migrate", "*.rb").to_s]
83
+ existing.map { |path| File.basename(path).split("_", 2).first.to_i }.max || 0
84
+ end
85
+
86
+ @migration_counter = [ @migration_counter + 1, now ].max
87
+ format("%014d", @migration_counter)
88
+ end
89
+
90
+ def relative_to_app(path)
91
+ path.relative_path_from(app_root)
92
+ rescue ArgumentError
93
+ path
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,3 @@
1
+ module SuperAdmin
2
+ VERSION = "0.2.0"
3
+ end
@@ -0,0 +1,7 @@
1
+ require "super_admin/version"
2
+ require "super_admin/engine"
3
+ require "pagy"
4
+
5
+ module SuperAdmin
6
+ # Your code goes here...
7
+ end
@@ -0,0 +1,38 @@
1
+ require "super_admin/dashboard_creator"
2
+ require "super_admin/install_task"
3
+
4
+ namespace :super_admin do
5
+ desc "Install SuperAdmin (use 'rails generate super_admin:install' instead)"
6
+ task install: :environment do
7
+ puts "⚠️ This rake task is deprecated. Please use the generator instead:"
8
+ puts " rails generate super_admin:install"
9
+ puts "\nRunning generator..."
10
+ Rails::Generators.invoke("super_admin:install")
11
+ rescue StandardError => e
12
+ abort "SuperAdmin install failed: #{e.message}"
13
+ end
14
+
15
+ namespace :install do
16
+ desc "Copy migrations from SuperAdmin to application"
17
+ task :migrations do
18
+ SuperAdmin::InstallTask.new.send(:copy_migrations)
19
+ end
20
+ end
21
+
22
+ namespace :dashboards do
23
+ desc "Generate SuperAdmin dashboards (use 'rails generate super_admin:dashboard' instead)"
24
+ task :generate, [ :model_name ] => :environment do |_task, args|
25
+ model_name = args[:model_name] || ENV["MODEL"]
26
+ puts "⚠️ This rake task is deprecated. Please use the generator instead:"
27
+ if model_name
28
+ puts " rails generate super_admin:dashboard #{model_name}"
29
+ else
30
+ puts " rails generate super_admin:dashboard"
31
+ end
32
+ puts "\nRunning generator..."
33
+ Rails::Generators.invoke("super_admin:dashboard", [ model_name ].compact)
34
+ rescue ArgumentError => e
35
+ abort e.message
36
+ end
37
+ end
38
+ end
metadata ADDED
@@ -0,0 +1,239 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: super_admin
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Thibaut Baissac
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2025-11-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '7.1'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '9.0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '7.1'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '9.0'
33
+ - !ruby/object:Gem::Dependency
34
+ name: pagy
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '9.0'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '9.0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: turbo-rails
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '2.0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '2.0'
61
+ - !ruby/object:Gem::Dependency
62
+ name: stimulus-rails
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '1.3'
68
+ type: :runtime
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '1.3'
75
+ - !ruby/object:Gem::Dependency
76
+ name: rack-attack
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '6.0'
82
+ type: :runtime
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '6.0'
89
+ - !ruby/object:Gem::Dependency
90
+ name: csv
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ type: :runtime
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ description: SuperAdmin is a mountable Rails engine that provides a full-featured
104
+ administration interface inspired by Administrate and ActiveAdmin, built for modern
105
+ Rails 7+ applications.
106
+ email:
107
+ - tbaissac@gmail.com
108
+ executables: []
109
+ extensions: []
110
+ extra_rdoc_files: []
111
+ files:
112
+ - README.md
113
+ - Rakefile
114
+ - app/assets/stylesheets/super_admin/application.css
115
+ - app/assets/stylesheets/super_admin/tailwind.css
116
+ - app/assets/stylesheets/super_admin/tailwind.source.css
117
+ - app/controllers/super_admin/application_controller.rb
118
+ - app/controllers/super_admin/associations_controller.rb
119
+ - app/controllers/super_admin/audit_logs_controller.rb
120
+ - app/controllers/super_admin/base_controller.rb
121
+ - app/controllers/super_admin/dashboard_controller.rb
122
+ - app/controllers/super_admin/exports_controller.rb
123
+ - app/controllers/super_admin/resources_controller.rb
124
+ - app/dashboards/super_admin/base_dashboard.rb
125
+ - app/errors/super_admin/configuration_error.rb
126
+ - app/helpers/super_admin/application_helper.rb
127
+ - app/helpers/super_admin/exports_helper.rb
128
+ - app/helpers/super_admin/resources_helper.rb
129
+ - app/helpers/super_admin/route_helper.rb
130
+ - app/javascript/super_admin/application.js
131
+ - app/jobs/super_admin/application_job.rb
132
+ - app/jobs/super_admin/generate_super_admin_csv_export_job.rb
133
+ - app/mailers/super_admin/application_mailer.rb
134
+ - app/models/super_admin/application_record.rb
135
+ - app/models/super_admin/audit_log.rb
136
+ - app/models/super_admin/csv_export.rb
137
+ - app/services/super_admin/auditing.rb
138
+ - app/services/super_admin/authorization.rb
139
+ - app/services/super_admin/authorization_adapters/base_adapter.rb
140
+ - app/services/super_admin/authorization_adapters/default_adapter.rb
141
+ - app/services/super_admin/authorization_adapters/proc_adapter.rb
142
+ - app/services/super_admin/authorization_adapters/pundit_adapter.rb
143
+ - app/services/super_admin/csv_export_creator.rb
144
+ - app/services/super_admin/dashboard_registry.rb
145
+ - app/services/super_admin/dashboard_resolver.rb
146
+ - app/services/super_admin/filter_builder.rb
147
+ - app/services/super_admin/form_builder.rb
148
+ - app/services/super_admin/form_fields/array_field.rb
149
+ - app/services/super_admin/form_fields/association_field.rb
150
+ - app/services/super_admin/form_fields/base_field.rb
151
+ - app/services/super_admin/form_fields/boolean_field.rb
152
+ - app/services/super_admin/form_fields/date_field.rb
153
+ - app/services/super_admin/form_fields/date_time_field.rb
154
+ - app/services/super_admin/form_fields/enum_field.rb
155
+ - app/services/super_admin/form_fields/factory.rb
156
+ - app/services/super_admin/form_fields/nested_field.rb
157
+ - app/services/super_admin/form_fields/number_field.rb
158
+ - app/services/super_admin/form_fields/text_area_field.rb
159
+ - app/services/super_admin/model_inspector.rb
160
+ - app/services/super_admin/queries/base_query.rb
161
+ - app/services/super_admin/queries/filter_query.rb
162
+ - app/services/super_admin/queries/resource_scope_query.rb
163
+ - app/services/super_admin/queries/search_query.rb
164
+ - app/services/super_admin/queries/sort_query.rb
165
+ - app/services/super_admin/resource_configuration.rb
166
+ - app/services/super_admin/resource_exporter.rb
167
+ - app/services/super_admin/resource_query.rb
168
+ - app/services/super_admin/resources/association_inspector.rb
169
+ - app/services/super_admin/resources/collection_presenter.rb
170
+ - app/services/super_admin/resources/context.rb
171
+ - app/services/super_admin/resources/filter_params.rb
172
+ - app/services/super_admin/resources/permitted_attributes.rb
173
+ - app/services/super_admin/resources/value_normalizer.rb
174
+ - app/services/super_admin/sensitive_attributes.rb
175
+ - app/views/layouts/super_admin.html.erb
176
+ - app/views/super_admin/audit_logs/index.html.erb
177
+ - app/views/super_admin/dashboard/index.html.erb
178
+ - app/views/super_admin/exports/index.html.erb
179
+ - app/views/super_admin/exports/show.html.erb
180
+ - app/views/super_admin/resources/_form.html.erb
181
+ - app/views/super_admin/resources/destroy.turbo_stream.erb
182
+ - app/views/super_admin/resources/edit.html.erb
183
+ - app/views/super_admin/resources/index.html.erb
184
+ - app/views/super_admin/resources/new.html.erb
185
+ - app/views/super_admin/resources/show.html.erb
186
+ - app/views/super_admin/shared/_breadcrumbs.html.erb
187
+ - app/views/super_admin/shared/_custom_styles.html.erb
188
+ - app/views/super_admin/shared/_flash.html.erb
189
+ - app/views/super_admin/shared/_form_field.html.erb
190
+ - app/views/super_admin/shared/_navigation.html.erb
191
+ - app/views/super_admin/shared/_nested_fields.html.erb
192
+ - app/views/super_admin/shared/_nested_record_fields.html.erb
193
+ - config/importmap.rb
194
+ - config/initializers/rack_attack.rb
195
+ - config/initializers/super_admin.rb
196
+ - config/locales/super_admin.en.yml
197
+ - config/locales/super_admin.fr.yml
198
+ - config/routes.rb
199
+ - lib/generators/super_admin/dashboard_generator.rb
200
+ - lib/generators/super_admin/install_generator.rb
201
+ - lib/generators/super_admin/templates/20240101000001_create_super_admin_audit_logs.rb
202
+ - lib/generators/super_admin/templates/20240101000002_create_super_admin_csv_exports.rb
203
+ - lib/generators/super_admin/templates/super_admin.rb
204
+ - lib/super_admin.rb
205
+ - lib/super_admin/dashboard_creator.rb
206
+ - lib/super_admin/engine.rb
207
+ - lib/super_admin/install_task.rb
208
+ - lib/super_admin/version.rb
209
+ - lib/tasks/super_admin_tasks.rake
210
+ homepage: https://github.com/ThibautBaissac/super_admin
211
+ licenses:
212
+ - MIT
213
+ metadata:
214
+ homepage_uri: https://github.com/ThibautBaissac/super_admin
215
+ source_code_uri: https://github.com/ThibautBaissac/super_admin
216
+ changelog_uri: https://github.com/ThibautBaissac/super_admin/blob/main/CHANGELOG.md
217
+ bug_tracker_uri: https://github.com/ThibautBaissac/super_admin/issues
218
+ documentation_uri: https://github.com/ThibautBaissac/super_admin#readme
219
+ rubygems_mfa_required: 'true'
220
+ post_install_message:
221
+ rdoc_options: []
222
+ require_paths:
223
+ - lib
224
+ required_ruby_version: !ruby/object:Gem::Requirement
225
+ requirements:
226
+ - - ">="
227
+ - !ruby/object:Gem::Version
228
+ version: '3.2'
229
+ required_rubygems_version: !ruby/object:Gem::Requirement
230
+ requirements:
231
+ - - ">="
232
+ - !ruby/object:Gem::Version
233
+ version: '0'
234
+ requirements: []
235
+ rubygems_version: 3.5.22
236
+ signing_key:
237
+ specification_version: 4
238
+ summary: A modern, flexible administration engine for Rails applications
239
+ test_files: []