madmin 1.0.2 → 1.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +29 -1
  3. data/app/controllers/madmin/base_controller.rb +0 -5
  4. data/app/controllers/madmin/resource_controller.rb +23 -2
  5. data/app/helpers/madmin/application_helper.rb +4 -0
  6. data/app/helpers/madmin/nav_helper.rb +30 -0
  7. data/app/helpers/madmin/sort_helper.rb +32 -0
  8. data/app/views/layouts/madmin/application.html.erb +5 -5
  9. data/app/views/madmin/application/_form.html.erb +6 -8
  10. data/app/views/madmin/application/_javascript.html.erb +70 -4
  11. data/app/views/madmin/application/_navigation.html.erb +31 -5
  12. data/app/views/madmin/application/edit.html.erb +5 -1
  13. data/app/views/madmin/application/index.html.erb +34 -22
  14. data/app/views/madmin/application/new.html.erb +5 -1
  15. data/app/views/madmin/application/show.html.erb +24 -17
  16. data/app/views/madmin/fields/attachment/_form.html.erb +3 -1
  17. data/app/views/madmin/fields/attachment/_show.html.erb +7 -1
  18. data/app/views/madmin/fields/attachments/_form.html.erb +3 -1
  19. data/app/views/madmin/fields/attachments/_show.html.erb +7 -3
  20. data/app/views/madmin/fields/belongs_to/_form.html.erb +4 -2
  21. data/app/views/madmin/fields/belongs_to/_show.html.erb +1 -1
  22. data/app/views/madmin/fields/boolean/_form.html.erb +3 -1
  23. data/app/views/madmin/fields/date/_form.html.erb +3 -1
  24. data/app/views/madmin/fields/date_time/_form.html.erb +3 -1
  25. data/app/views/madmin/fields/decimal/_form.html.erb +3 -1
  26. data/app/views/madmin/fields/enum/_form.html.erb +4 -2
  27. data/app/views/madmin/fields/float/_form.html.erb +3 -1
  28. data/app/views/madmin/fields/has_many/_form.html.erb +4 -2
  29. data/app/views/madmin/fields/has_many/_show.html.erb +1 -1
  30. data/app/views/madmin/fields/has_one/_form.html.erb +3 -2
  31. data/app/views/madmin/fields/integer/_form.html.erb +3 -1
  32. data/app/views/madmin/fields/json/_form.html.erb +3 -1
  33. data/app/views/madmin/fields/nested_has_many/_fields.html.erb +18 -0
  34. data/app/views/madmin/fields/nested_has_many/_form.html.erb +32 -0
  35. data/app/views/madmin/fields/nested_has_many/_index.html.erb +1 -0
  36. data/app/views/madmin/fields/nested_has_many/_show.html.erb +5 -0
  37. data/app/views/madmin/fields/password/_form.html.erb +4 -0
  38. data/app/views/madmin/fields/password/_index.html.erb +1 -0
  39. data/app/views/madmin/fields/password/_show.html.erb +1 -0
  40. data/app/views/madmin/fields/polymorphic/_form.html.erb +3 -1
  41. data/app/views/madmin/fields/polymorphic/_show.html.erb +1 -1
  42. data/app/views/madmin/fields/rich_text/_form.html.erb +3 -1
  43. data/app/views/madmin/fields/string/_form.html.erb +3 -1
  44. data/app/views/madmin/fields/text/_form.html.erb +3 -1
  45. data/app/views/madmin/fields/time/_form.html.erb +3 -1
  46. data/app/views/madmin/shared/_label.html.erb +4 -0
  47. data/lib/generators/madmin/field/field_generator.rb +31 -0
  48. data/lib/generators/madmin/field/templates/_form.html.erb +2 -0
  49. data/lib/generators/madmin/field/templates/_index.html.erb +1 -0
  50. data/lib/generators/madmin/field/templates/_show.html.erb +1 -0
  51. data/lib/generators/madmin/field/templates/field.rb.tt +26 -0
  52. data/lib/generators/madmin/install/install_generator.rb +6 -1
  53. data/lib/generators/madmin/install/templates/routes.rb.tt +3 -0
  54. data/lib/generators/madmin/resource/resource_generator.rb +15 -54
  55. data/lib/generators/madmin/resource/templates/controller.rb.tt +6 -0
  56. data/lib/generators/madmin/resource/templates/resource.rb.tt +15 -1
  57. data/lib/generators/madmin/views/javascript_generator.rb +15 -0
  58. data/lib/generators/madmin/views/views_generator.rb +6 -5
  59. data/lib/madmin/engine.rb +4 -4
  60. data/lib/madmin/field.rb +4 -0
  61. data/lib/madmin/fields/belongs_to.rb +9 -5
  62. data/lib/madmin/fields/has_many.rb +10 -5
  63. data/lib/madmin/fields/nested_has_many.rb +40 -0
  64. data/lib/madmin/fields/password.rb +6 -0
  65. data/lib/madmin/fields/string.rb +3 -0
  66. data/lib/madmin/fields/text.rb +3 -0
  67. data/lib/madmin/generator_helpers.rb +22 -4
  68. data/lib/madmin/resource.rb +76 -28
  69. data/lib/madmin/resource_builder.rb +80 -0
  70. data/lib/madmin/search.rb +60 -0
  71. data/lib/madmin/version.rb +1 -1
  72. data/lib/madmin.rb +31 -14
  73. metadata +26 -5
@@ -1,14 +1,10 @@
1
1
  module Madmin
2
2
  class Resource
3
- class_attribute :attributes, default: []
3
+ class_attribute :attributes, default: ActiveSupport::OrderedHash.new
4
4
  class_attribute :scopes, default: []
5
5
 
6
6
  class << self
7
7
  def inherited(base)
8
- # Remove any old references
9
- Madmin.resources.delete(base)
10
- Madmin.resources << base
11
-
12
8
  base.attributes = attributes.dup
13
9
  base.scopes = scopes.dup
14
10
  super
@@ -18,6 +14,10 @@ module Madmin
18
14
  model_name.constantize
19
15
  end
20
16
 
17
+ def model_find(id)
18
+ friendly_model? ? model.friendly.find(id) : model.find(id)
19
+ end
20
+
21
21
  def model_name
22
22
  to_s.chomp("Resource").classify
23
23
  end
@@ -26,11 +26,32 @@ module Madmin
26
26
  scopes << name
27
27
  end
28
28
 
29
+ def get_attribute(name)
30
+ attributes[name]
31
+ end
32
+
29
33
  def attribute(name, type = nil, **options)
30
- attributes << {
34
+ type ||= infer_type(name)
35
+ field = options[:field] || field_for_type(type)
36
+
37
+ attributes[name] = OpenStruct.new(
31
38
  name: name,
32
- field: field_for_type(name, type).new(**options.merge(attribute_name: name, model: model))
33
- }
39
+ type: type,
40
+ field: field.new(**options.merge(attribute_name: name, model: model))
41
+ )
42
+ rescue => e
43
+ builder = ResourceBuilder.new(model)
44
+ raise ArgumentError, <<~MESSAGE
45
+ Madmin couldn't find attribute or association '#{name}' on #{model} model.
46
+
47
+ We searched these attributes and associations:
48
+ #{(builder.attributes + builder.associations).join(", ")}
49
+
50
+ This attribute is defined in a Madmin resource at:
51
+ #{e.backtrace.find { |l| l =~ /_resource.rb/ }}
52
+
53
+ Either add the missing attribute or assocation, or remove this line from your Madmin resource.
54
+ MESSAGE
34
55
  end
35
56
 
36
57
  def friendly_name
@@ -38,21 +59,27 @@ module Madmin
38
59
  end
39
60
 
40
61
  def index_path(options = {})
41
- path = "/madmin/#{model.model_name.collection}"
42
- path += "?#{options.to_param}" if options.any?
43
- path
62
+ route_name = "madmin_#{model.model_name.plural}_path"
63
+
64
+ url_helpers.send(route_name, options)
44
65
  end
45
66
 
46
67
  def new_path
47
- "/madmin/#{model.model_name.collection}/new"
68
+ route_name = "new_madmin_#{model.model_name.singular}_path"
69
+
70
+ url_helpers.send(route_name)
48
71
  end
49
72
 
50
73
  def show_path(record)
51
- "/madmin/#{model.model_name.collection}/#{record.id}"
74
+ route_name = "madmin_#{model.model_name.singular}_path"
75
+
76
+ url_helpers.send(route_name, record.to_param)
52
77
  end
53
78
 
54
79
  def edit_path(record)
55
- "/madmin/#{model.model_name.collection}/#{record.id}/edit"
80
+ route_name = "edit_madmin_#{model.model_name.singular}_path"
81
+
82
+ url_helpers.send(route_name, record.to_param)
56
83
  end
57
84
 
58
85
  def param_key
@@ -60,18 +87,28 @@ module Madmin
60
87
  end
61
88
 
62
89
  def permitted_params
63
- attributes.map { |a| a[:field].to_param }
90
+ attributes.values.filter_map { |a| a.field.to_param if a.field.visible?(:form) }
64
91
  end
65
92
 
66
93
  def display_name(record)
67
94
  "#{record.class} ##{record.id}"
68
95
  end
69
96
 
70
- private
97
+ def friendly_model?
98
+ model.respond_to? :friendly
99
+ end
71
100
 
72
- def field_for_type(name, type)
73
- type ||= infer_type(name)
101
+ def sortable_columns
102
+ model.column_names
103
+ end
74
104
 
105
+ def searchable_attributes
106
+ attributes.values.select { |a| a.field.searchable? }
107
+ end
108
+
109
+ private
110
+
111
+ def field_for_type(type)
75
112
  {
76
113
  binary: Fields::String,
77
114
  blob: Fields::Text,
@@ -90,6 +127,7 @@ module Madmin
90
127
  text: Fields::Text,
91
128
  time: Fields::Time,
92
129
  timestamp: Fields::Time,
130
+ password: Fields::Password,
93
131
 
94
132
  # Postgres specific types
95
133
  bit: Fields::String,
@@ -126,17 +164,9 @@ module Madmin
126
164
  polymorphic: Fields::Polymorphic,
127
165
  has_many: Fields::HasMany,
128
166
  has_one: Fields::HasOne,
129
- rich_text: Fields::RichText
167
+ rich_text: Fields::RichText,
168
+ nested_has_many: Fields::NestedHasMany
130
169
  }.fetch(type)
131
- rescue
132
- raise ArgumentError, <<~MESSAGE
133
- Couldn't find attribute or association '#{name}' with type '#{type}' on #{model} model
134
-
135
- To fix this, either:
136
-
137
- 1. Remove 'attribute #{name}' from app/madmin/resources/#{model.to_s.underscore}_resource.rb
138
- 2. Or add the missing attribute or association to the #{model} model
139
- MESSAGE
140
170
  end
141
171
 
142
172
  def infer_type(name)
@@ -157,6 +187,14 @@ module Madmin
157
187
  :attachment
158
188
  elsif model.reflect_on_association(:"#{name_string}_attachments")
159
189
  :attachments
190
+
191
+ # has_secure_password
192
+ elsif model.attribute_types.include?("#{name_string}_digest") || name_string.ends_with?("_confirmation")
193
+ :password
194
+
195
+ # ActiveRecord Store
196
+ elsif model_store_accessors.include?(name)
197
+ :string
160
198
  end
161
199
  end
162
200
 
@@ -171,6 +209,16 @@ module Madmin
171
209
  :belongs_to
172
210
  end
173
211
  end
212
+
213
+ def url_helpers
214
+ @url_helpers ||= Rails.application.routes.url_helpers
215
+ end
216
+
217
+ def model_store_accessors
218
+ store_accessors = model.stored_attributes.values
219
+
220
+ store_accessors.flatten
221
+ end
174
222
  end
175
223
  end
176
224
  end
@@ -0,0 +1,80 @@
1
+ module Madmin
2
+ class ResourceBuilder
3
+ attr_reader :model
4
+
5
+ def initialize(model)
6
+ @model = model
7
+ end
8
+
9
+ def associations
10
+ model.reflections.reject { |name, association|
11
+ # Hide these special associations
12
+ name.starts_with?("rich_text") ||
13
+ name.ends_with?("_attachment") ||
14
+ name.ends_with?("_attachments") ||
15
+ name.ends_with?("_blob") ||
16
+ name.ends_with?("_blobs")
17
+ }.keys
18
+ end
19
+
20
+ def attributes
21
+ model.attribute_names + virtual_attributes - redundant_attributes
22
+ end
23
+
24
+ def store_accessors
25
+ model.stored_attributes.values.flatten
26
+ end
27
+
28
+ def virtual_attributes
29
+ virtual = []
30
+
31
+ # has_secure_password columns
32
+ password_attributes = model.attribute_types.keys.select { |k| k.ends_with?("_digest") }.map { |k| k.delete_suffix("_digest") }
33
+ virtual += password_attributes.map { |attr| [attr, "#{attr}_confirmation"] }.flatten
34
+
35
+ # ActiveRecord Store columns
36
+ virtual += store_accessors.map(&:to_s)
37
+
38
+ # Add virtual attributes for ActionText and ActiveStorage
39
+ model.reflections.each do |name, association|
40
+ if name.starts_with?("rich_text")
41
+ virtual << name.split("rich_text_").last
42
+ elsif name.ends_with?("_attachment")
43
+ virtual << name.split("_attachment").first
44
+ elsif name.ends_with?("_attachments")
45
+ virtual << name.split("_attachments").first
46
+ end
47
+ end
48
+
49
+ virtual
50
+ end
51
+
52
+ def redundant_attributes
53
+ redundant = []
54
+
55
+ # has_secure_password columns
56
+ redundant += model.attribute_types.keys.select { |k| k.ends_with?("_digest") }
57
+
58
+ # ActiveRecord Store columns
59
+ store_columns = model.stored_attributes.keys
60
+ redundant += store_columns.map(&:to_s)
61
+
62
+ model.reflections.each do |name, association|
63
+ if association.has_one?
64
+ next
65
+ elsif association.collection?
66
+ next
67
+ elsif association.polymorphic?
68
+ redundant << "#{name}_id"
69
+ redundant << "#{name}_type"
70
+ elsif name.starts_with?("rich_text")
71
+ redundant << name
72
+ else # belongs to
73
+ redundant << "#{name}_id"
74
+ end
75
+ end
76
+
77
+ redundant
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,60 @@
1
+ # based on Administrate Search: https://github.com/thoughtbot/administrate/blob/main/lib/administrate/search.rb
2
+
3
+ module Madmin
4
+ class Search
5
+ attr_reader :query
6
+
7
+ def initialize(scoped_resource, resource, term)
8
+ @resource = resource
9
+ @scoped_resource = scoped_resource
10
+ @query = term
11
+ end
12
+
13
+ def run
14
+ if query.blank?
15
+ @scoped_resource.all
16
+ else
17
+ search_results(@scoped_resource)
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def search_results(resources)
24
+ resources.where(query_template, *query_values)
25
+ end
26
+
27
+ def query_template
28
+ search_attributes.map do |attr|
29
+ table_name = query_table_name(attr)
30
+ searchable_fields(attr).map do |field|
31
+ column_name = column_to_query(field)
32
+ "LOWER(CAST(#{table_name}.#{column_name} AS CHAR(256))) LIKE ?"
33
+ end.join(" OR ")
34
+ end.join(" OR ")
35
+ end
36
+
37
+ def searchable_fields(attr)
38
+ [attr[:name]]
39
+ end
40
+
41
+ def query_values
42
+ fields_count = search_attributes.sum do |attr|
43
+ searchable_fields(attr).count
44
+ end
45
+ ["%#{@query.mb_chars.downcase}%"] * fields_count
46
+ end
47
+
48
+ def search_attributes
49
+ @resource.searchable_attributes
50
+ end
51
+
52
+ def query_table_name(attr)
53
+ ActiveRecord::Base.connection.quote_column_name(@scoped_resource.table_name)
54
+ end
55
+
56
+ def column_to_query(attr)
57
+ ActiveRecord::Base.connection.quote_column_name(attr)
58
+ end
59
+ end
60
+ end
@@ -1,3 +1,3 @@
1
1
  module Madmin
2
- VERSION = "1.0.2"
2
+ VERSION = "1.2.2"
3
3
  end
data/lib/madmin.rb CHANGED
@@ -6,36 +6,53 @@ module Madmin
6
6
  autoload :Field, "madmin/field"
7
7
  autoload :GeneratorHelpers, "madmin/generator_helpers"
8
8
  autoload :Resource, "madmin/resource"
9
+ autoload :ResourceBuilder, "madmin/resource_builder"
10
+ autoload :Search, "madmin/search"
9
11
 
10
12
  module Fields
13
+ autoload :Attachment, "madmin/fields/attachment"
14
+ autoload :Attachments, "madmin/fields/attachments"
15
+ autoload :BelongsTo, "madmin/fields/belongs_to"
11
16
  autoload :Boolean, "madmin/fields/boolean"
12
- autoload :Integer, "madmin/fields/integer"
13
- autoload :String, "madmin/fields/string"
14
- autoload :Text, "madmin/fields/text"
15
17
  autoload :Date, "madmin/fields/date"
16
18
  autoload :DateTime, "madmin/fields/date_time"
17
19
  autoload :Decimal, "madmin/fields/decimal"
18
- autoload :Json, "madmin/fields/json"
19
20
  autoload :Enum, "madmin/fields/enum"
20
21
  autoload :Float, "madmin/fields/float"
21
- autoload :Time, "madmin/fields/time"
22
- autoload :BelongsTo, "madmin/fields/belongs_to"
23
- autoload :Polymorphic, "madmin/fields/polymorphic"
24
22
  autoload :HasMany, "madmin/fields/has_many"
25
23
  autoload :HasOne, "madmin/fields/has_one"
24
+ autoload :Integer, "madmin/fields/integer"
25
+ autoload :Json, "madmin/fields/json"
26
+ autoload :NestedHasMany, "madmin/fields/nested_has_many"
27
+ autoload :Password, "madmin/fields/password"
28
+ autoload :Polymorphic, "madmin/fields/polymorphic"
26
29
  autoload :RichText, "madmin/fields/rich_text"
27
- autoload :Attachment, "madmin/fields/attachment"
28
- autoload :Attachments, "madmin/fields/attachments"
30
+ autoload :String, "madmin/fields/string"
31
+ autoload :Text, "madmin/fields/text"
32
+ autoload :Time, "madmin/fields/time"
29
33
  end
30
34
 
31
- mattr_accessor :resources, default: []
32
-
33
35
  class << self
34
36
  def resource_for(object)
35
- Rails.application.eager_load!
37
+ "#{object.class.name}Resource".constantize
38
+ end
39
+
40
+ def resource_by_name(name)
41
+ "#{name}Resource".constantize
42
+ end
43
+
44
+ def resources
45
+ @resources ||= resource_names.map(&:constantize)
46
+ end
47
+
48
+ def reset_resources!
49
+ @resources = nil
50
+ end
36
51
 
37
- klass_name = object.class.name
38
- Madmin.resources.find { |r| r.model_name == klass_name }
52
+ def resource_names
53
+ root = Rails.root.join("app/madmin/resources/")
54
+ files = Dir.glob(root.join("**/*.rb"))
55
+ files.sort!.map! { |f| f.split(root.to_s).last.delete_suffix(".rb").classify }
39
56
  end
40
57
  end
41
58
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: madmin
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Oliver
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2021-03-04 00:00:00.000000000 Z
12
+ date: 2021-09-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -34,7 +34,7 @@ dependencies:
34
34
  version: '3.5'
35
35
  - - "<"
36
36
  - !ruby/object:Gem::Version
37
- version: '4.0'
37
+ version: '5.0'
38
38
  type: :runtime
39
39
  prerelease: false
40
40
  version_requirements: !ruby/object:Gem::Requirement
@@ -44,7 +44,7 @@ dependencies:
44
44
  version: '3.5'
45
45
  - - "<"
46
46
  - !ruby/object:Gem::Version
47
- version: '4.0'
47
+ version: '5.0'
48
48
  description: It's an admin, obviously.
49
49
  email:
50
50
  - excid3@gmail.com
@@ -63,6 +63,8 @@ files:
63
63
  - app/controllers/madmin/dashboard_controller.rb
64
64
  - app/controllers/madmin/resource_controller.rb
65
65
  - app/helpers/madmin/application_helper.rb
66
+ - app/helpers/madmin/nav_helper.rb
67
+ - app/helpers/madmin/sort_helper.rb
66
68
  - app/views/layouts/madmin/application.html.erb
67
69
  - app/views/madmin/application/_form.html.erb
68
70
  - app/views/madmin/application/_javascript.html.erb
@@ -111,6 +113,13 @@ files:
111
113
  - app/views/madmin/fields/json/_form.html.erb
112
114
  - app/views/madmin/fields/json/_index.html.erb
113
115
  - app/views/madmin/fields/json/_show.html.erb
116
+ - app/views/madmin/fields/nested_has_many/_fields.html.erb
117
+ - app/views/madmin/fields/nested_has_many/_form.html.erb
118
+ - app/views/madmin/fields/nested_has_many/_index.html.erb
119
+ - app/views/madmin/fields/nested_has_many/_show.html.erb
120
+ - app/views/madmin/fields/password/_form.html.erb
121
+ - app/views/madmin/fields/password/_index.html.erb
122
+ - app/views/madmin/fields/password/_show.html.erb
114
123
  - app/views/madmin/fields/polymorphic/_form.html.erb
115
124
  - app/views/madmin/fields/polymorphic/_index.html.erb
116
125
  - app/views/madmin/fields/polymorphic/_show.html.erb
@@ -126,14 +135,22 @@ files:
126
135
  - app/views/madmin/fields/time/_form.html.erb
127
136
  - app/views/madmin/fields/time/_index.html.erb
128
137
  - app/views/madmin/fields/time/_show.html.erb
138
+ - app/views/madmin/shared/_label.html.erb
139
+ - lib/generators/madmin/field/field_generator.rb
140
+ - lib/generators/madmin/field/templates/_form.html.erb
141
+ - lib/generators/madmin/field/templates/_index.html.erb
142
+ - lib/generators/madmin/field/templates/_show.html.erb
143
+ - lib/generators/madmin/field/templates/field.rb.tt
129
144
  - lib/generators/madmin/install/install_generator.rb
130
145
  - lib/generators/madmin/install/templates/controller.rb.tt
146
+ - lib/generators/madmin/install/templates/routes.rb.tt
131
147
  - lib/generators/madmin/resource/resource_generator.rb
132
148
  - lib/generators/madmin/resource/templates/controller.rb.tt
133
149
  - lib/generators/madmin/resource/templates/resource.rb.tt
134
150
  - lib/generators/madmin/views/edit_generator.rb
135
151
  - lib/generators/madmin/views/form_generator.rb
136
152
  - lib/generators/madmin/views/index_generator.rb
153
+ - lib/generators/madmin/views/javascript_generator.rb
137
154
  - lib/generators/madmin/views/layout_generator.rb
138
155
  - lib/generators/madmin/views/navigation_generator.rb
139
156
  - lib/generators/madmin/views/new_generator.rb
@@ -155,6 +172,8 @@ files:
155
172
  - lib/madmin/fields/has_one.rb
156
173
  - lib/madmin/fields/integer.rb
157
174
  - lib/madmin/fields/json.rb
175
+ - lib/madmin/fields/nested_has_many.rb
176
+ - lib/madmin/fields/password.rb
158
177
  - lib/madmin/fields/polymorphic.rb
159
178
  - lib/madmin/fields/rich_text.rb
160
179
  - lib/madmin/fields/string.rb
@@ -163,6 +182,8 @@ files:
163
182
  - lib/madmin/generator_helpers.rb
164
183
  - lib/madmin/namespace.rb
165
184
  - lib/madmin/resource.rb
185
+ - lib/madmin/resource_builder.rb
186
+ - lib/madmin/search.rb
166
187
  - lib/madmin/version.rb
167
188
  - lib/madmin/view_generator.rb
168
189
  - lib/tasks/madmin_tasks.rake
@@ -185,7 +206,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
185
206
  - !ruby/object:Gem::Version
186
207
  version: '0'
187
208
  requirements: []
188
- rubygems_version: 3.2.3
209
+ rubygems_version: 3.2.22
189
210
  signing_key:
190
211
  specification_version: 4
191
212
  summary: A modern admin for Ruby on Rails apps