madmin 1.2.11 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/config/madmin_manifest.js +3 -0
  3. data/app/assets/stylesheets/madmin/actiontext.css +31 -0
  4. data/app/assets/stylesheets/madmin/application.css +88 -0
  5. data/app/assets/stylesheets/madmin/buttons.css +46 -0
  6. data/app/assets/stylesheets/madmin/forms.css +82 -0
  7. data/app/assets/stylesheets/madmin/pagination.css +59 -0
  8. data/app/assets/stylesheets/madmin/reset.css +242 -0
  9. data/app/assets/stylesheets/madmin/sidebar.css +80 -0
  10. data/app/assets/stylesheets/madmin/tables.css +56 -0
  11. data/app/controllers/madmin/application_controller.rb +7 -12
  12. data/app/controllers/madmin/base_controller.rb +1 -0
  13. data/app/helpers/madmin/application_helper.rb +1 -12
  14. data/app/helpers/madmin/sort_helper.rb +17 -1
  15. data/app/javascript/madmin/application.js +4 -0
  16. data/app/javascript/madmin/controllers/application.js +12 -0
  17. data/app/javascript/madmin/controllers/index.js +5 -0
  18. data/app/javascript/madmin/controllers/nested_form_controller.js +34 -0
  19. data/app/javascript/madmin/controllers/select_controller.js +32 -0
  20. data/app/views/layouts/madmin/application.html.erb +11 -13
  21. data/app/views/madmin/application/_form.html.erb +13 -12
  22. data/app/views/madmin/application/_javascript.html.erb +3 -136
  23. data/app/views/madmin/application/_navigation.html.erb +22 -27
  24. data/app/views/madmin/application/edit.html.erb +9 -5
  25. data/app/views/madmin/application/index.html.erb +37 -31
  26. data/app/views/madmin/application/new.html.erb +9 -5
  27. data/app/views/madmin/application/show.html.erb +28 -22
  28. data/app/views/madmin/dashboard/show.html.erb +4 -1
  29. data/app/views/madmin/fields/attachment/_form.html.erb +11 -4
  30. data/app/views/madmin/fields/attachment/_index.html.erb +5 -1
  31. data/app/views/madmin/fields/attachment/_show.html.erb +4 -4
  32. data/app/views/madmin/fields/attachments/_form.html.erb +1 -4
  33. data/app/views/madmin/fields/belongs_to/_form.html.erb +1 -4
  34. data/app/views/madmin/fields/belongs_to/_index.html.erb +2 -1
  35. data/app/views/madmin/fields/boolean/_form.html.erb +3 -4
  36. data/app/views/madmin/fields/currency/_form.html.erb +1 -0
  37. data/app/views/madmin/fields/currency/_index.html.erb +1 -0
  38. data/app/views/madmin/fields/currency/_show.html.erb +1 -0
  39. data/app/views/madmin/fields/date/_form.html.erb +1 -4
  40. data/app/views/madmin/fields/date_time/_form.html.erb +1 -4
  41. data/app/views/madmin/fields/decimal/_form.html.erb +1 -4
  42. data/app/views/madmin/fields/enum/_form.html.erb +1 -4
  43. data/app/views/madmin/fields/file/_form.html.erb +1 -4
  44. data/app/views/madmin/fields/float/_form.html.erb +1 -4
  45. data/app/views/madmin/fields/has_many/_form.html.erb +1 -4
  46. data/app/views/madmin/fields/has_one/_form.html.erb +0 -3
  47. data/app/views/madmin/fields/integer/_form.html.erb +1 -4
  48. data/app/views/madmin/fields/integer/_index.html.erb +1 -5
  49. data/app/views/madmin/fields/json/_form.html.erb +1 -4
  50. data/app/views/madmin/fields/nested_has_many/_fields.html.erb +4 -5
  51. data/app/views/madmin/fields/nested_has_many/_form.html.erb +0 -4
  52. data/app/views/madmin/fields/password/_form.html.erb +1 -4
  53. data/app/views/madmin/fields/polymorphic/_form.html.erb +1 -4
  54. data/app/views/madmin/fields/rich_text/_form.html.erb +1 -6
  55. data/app/views/madmin/fields/select/_form.html.erb +1 -0
  56. data/app/views/madmin/fields/select/_index.html.erb +1 -0
  57. data/app/views/madmin/fields/select/_show.html.erb +1 -0
  58. data/app/views/madmin/fields/string/_form.html.erb +1 -4
  59. data/app/views/madmin/fields/text/_form.html.erb +1 -4
  60. data/app/views/madmin/shared/_label.html.erb +2 -2
  61. data/config/importmap.rb +10 -0
  62. data/lib/generators/madmin/field/templates/_form.html.erb +1 -4
  63. data/lib/generators/madmin/install/templates/controller.rb.tt +5 -12
  64. data/lib/generators/madmin/resource/templates/resource.rb.tt +12 -10
  65. data/lib/madmin/engine.rb +20 -0
  66. data/lib/madmin/field.rb +17 -5
  67. data/lib/madmin/fields/belongs_to.rb +10 -5
  68. data/lib/madmin/fields/currency.rb +15 -0
  69. data/lib/madmin/fields/polymorphic.rb +1 -1
  70. data/lib/madmin/fields/select.rb +9 -0
  71. data/lib/madmin/menu.rb +70 -0
  72. data/lib/madmin/resource.rb +56 -24
  73. data/lib/madmin/search.rb +1 -1
  74. data/lib/madmin/version.rb +1 -1
  75. data/lib/madmin.rb +22 -1
  76. metadata +61 -13
  77. data/app/assets/config/manifest.js +0 -2
  78. data/app/assets/stylesheets/actiontext.scss +0 -36
  79. data/app/assets/stylesheets/application.css +0 -15
  80. data/app/views/madmin/application/_menu_resources.html.erb +0 -7
@@ -1,10 +1,11 @@
1
- require "ostruct"
2
-
3
1
  module Madmin
4
2
  class Resource
3
+ Attribute = Data.define(:name, :type, :field)
4
+
5
5
  class_attribute :attributes, default: ActiveSupport::OrderedHash.new
6
6
  class_attribute :member_actions, default: []
7
7
  class_attribute :scopes, default: []
8
+ class_attribute :menu_options, instance_reader: false
8
9
 
9
10
  class << self
10
11
  def inherited(base)
@@ -14,12 +15,17 @@ module Madmin
14
15
  super
15
16
  end
16
17
 
17
- def model
18
- @model ||= model_name.constantize
18
+ def model(value = nil)
19
+ if value
20
+ @model = value
21
+ else
22
+ @model ||= model_name.constantize
23
+ end
19
24
  end
20
25
 
21
26
  def model_find(id)
22
- friendly_model? ? model.friendly.find(id) : model.find(id)
27
+ record = friendly_model? ? model.friendly.find(id) : model.find(id)
28
+ becomes(record)
23
29
  end
24
30
 
25
31
  def model_name
@@ -36,26 +42,36 @@ module Madmin
36
42
 
37
43
  def attribute(name, type = nil, **options)
38
44
  type ||= infer_type(name)
39
- field = options[:field] || field_for_type(type)
45
+ field = options.delete(:field) || field_for_type(type)
40
46
 
41
- attributes[name] = OpenStruct.new(
42
- name: name,
43
- type: type,
44
- field: field.new(**options.merge(attribute_name: name, model: model, resource: self))
45
- )
46
- rescue => e
47
- builder = ResourceBuilder.new(model)
48
- raise ArgumentError, <<~MESSAGE
49
- Madmin couldn't find attribute or association '#{name}' on #{model} model.
47
+ if field.nil?
48
+ Rails.logger.warn <<~MESSAGE
49
+ WARNING: Madmin could not infer a field type for `#{name}` attribute. Defaulting to a String type.
50
+ You can set the type by specifying the type on the attribute:
51
+
52
+ attribute :#{name}, :boolean
53
+ MESSAGE
54
+ field = Fields::String
55
+ end
56
+
57
+ config = ActiveSupport::OrderedOptions.new.merge(options)
58
+ yield config if block_given?
50
59
 
51
- We searched these attributes and associations:
52
- #{(builder.attributes + builder.associations).join(", ")}
60
+ # Form is an alias for new & edit
61
+ if config.has_key?(:form)
62
+ config.new = config[:form]
63
+ config.edit = config[:form]
64
+ end
53
65
 
54
- This attribute is defined in a Madmin resource at:
55
- #{e.backtrace.find { |l| l =~ /_resource.rb/ }}
66
+ # New/create and edit/update need to match
67
+ config.create = config[:create] if config.has_key?(:new)
68
+ config.update = config[:update] if config.has_key?(:edit)
56
69
 
57
- Either add the missing attribute or assocation, or remove this line from your Madmin resource.
58
- MESSAGE
70
+ attributes[name] = Attribute.new(
71
+ name: name,
72
+ type: type,
73
+ field: field.new(attribute_name: name, model: model, resource: self, options: config)
74
+ )
59
75
  end
60
76
 
61
77
  def friendly_name
@@ -81,11 +97,15 @@ module Madmin
81
97
  end
82
98
 
83
99
  def show_path(record)
84
- url_helpers.polymorphic_path([:madmin, route_namespace, record])
100
+ url_helpers.polymorphic_path([:madmin, route_namespace, becomes(record)])
85
101
  end
86
102
 
87
103
  def edit_path(record)
88
- url_helpers.polymorphic_path([:madmin, route_namespace, record], action: :edit)
104
+ url_helpers.polymorphic_path([:madmin, route_namespace, becomes(record)], action: :edit)
105
+ end
106
+
107
+ def becomes(record)
108
+ record.instance_of?(model) ? record : record.becomes(model)
89
109
  end
90
110
 
91
111
  def param_key
@@ -121,6 +141,7 @@ module Madmin
121
141
  binary: Fields::String,
122
142
  blob: Fields::Text,
123
143
  boolean: Fields::Boolean,
144
+ currency: Fields::Currency,
124
145
  date: Fields::Date,
125
146
  datetime: Fields::DateTime,
126
147
  decimal: Fields::Decimal,
@@ -131,6 +152,7 @@ module Madmin
131
152
  json: Fields::Json,
132
153
  jsonb: Fields::Json,
133
154
  primary_key: Fields::String,
155
+ select: Fields::Select,
134
156
  string: Fields::String,
135
157
  text: Fields::Text,
136
158
  time: Fields::Time,
@@ -176,7 +198,7 @@ module Madmin
176
198
  has_one: Fields::HasOne,
177
199
  rich_text: Fields::RichText,
178
200
  nested_has_many: Fields::NestedHasMany
179
- }.fetch(type)
201
+ }[type]
180
202
  end
181
203
 
182
204
  def infer_type(name)
@@ -228,6 +250,16 @@ module Madmin
228
250
  store_accessors = model.stored_attributes.values
229
251
  store_accessors.flatten
230
252
  end
253
+
254
+ def menu(options)
255
+ @menu_options = options
256
+ end
257
+
258
+ def menu_options
259
+ return false if @menu_options == false
260
+ @menu_options ||= {}
261
+ @menu_options.with_defaults(label: friendly_name.pluralize, url: index_path)
262
+ end
231
263
  end
232
264
  end
233
265
  end
data/lib/madmin/search.rb CHANGED
@@ -35,7 +35,7 @@ module Madmin
35
35
  end
36
36
 
37
37
  def searchable_fields(attr)
38
- [attr[:name]]
38
+ [attr.name]
39
39
  end
40
40
 
41
41
  def query_values
@@ -1,3 +1,3 @@
1
1
  module Madmin
2
- VERSION = "1.2.11"
2
+ VERSION = "2.0.0"
3
3
  end
data/lib/madmin.rb CHANGED
@@ -5,6 +5,7 @@ require "pagy"
5
5
  module Madmin
6
6
  autoload :Field, "madmin/field"
7
7
  autoload :GeneratorHelpers, "madmin/generator_helpers"
8
+ autoload :Menu, "madmin/menu"
8
9
  autoload :Resource, "madmin/resource"
9
10
  autoload :ResourceBuilder, "madmin/resource_builder"
10
11
  autoload :Search, "madmin/search"
@@ -14,6 +15,7 @@ module Madmin
14
15
  autoload :Attachments, "madmin/fields/attachments"
15
16
  autoload :BelongsTo, "madmin/fields/belongs_to"
16
17
  autoload :Boolean, "madmin/fields/boolean"
18
+ autoload :Currency, "madmin/fields/currency"
17
19
  autoload :Date, "madmin/fields/date"
18
20
  autoload :DateTime, "madmin/fields/date_time"
19
21
  autoload :Decimal, "madmin/fields/decimal"
@@ -28,14 +30,32 @@ module Madmin
28
30
  autoload :Password, "madmin/fields/password"
29
31
  autoload :Polymorphic, "madmin/fields/polymorphic"
30
32
  autoload :RichText, "madmin/fields/rich_text"
33
+ autoload :Select, "madmin/fields/select"
31
34
  autoload :String, "madmin/fields/string"
32
35
  autoload :Text, "madmin/fields/text"
33
36
  autoload :Time, "madmin/fields/time"
34
37
  end
35
38
 
39
+ mattr_accessor :importmap, default: Importmap::Map.new
40
+ mattr_accessor :menu, default: Menu.new
41
+ mattr_accessor :site_name
42
+
36
43
  class << self
37
44
  def resource_for(object)
38
- "#{object.class.name}Resource".constantize
45
+ if object.is_a? ::ActiveStorage::Attached
46
+ "ActiveStorage::AttachmentResource".constantize
47
+ else
48
+ begin
49
+ "#{object.class.name}Resource".constantize
50
+ rescue
51
+ # For STI models, see if there's a superclass resource available
52
+ if (column = object.class.inheritance_column) && object.class.column_names.include?(column)
53
+ "#{object.class.superclass.base_class.name}Resource".constantize
54
+ else
55
+ raise
56
+ end
57
+ end
58
+ end
39
59
  end
40
60
 
41
61
  def resource_by_name(name)
@@ -48,6 +68,7 @@ module Madmin
48
68
 
49
69
  def reset_resources!
50
70
  @resources = nil
71
+ menu.reset
51
72
  end
52
73
 
53
74
  def resource_names
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: madmin
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.11
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Oliver
8
8
  - Andrea Fomera
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2024-06-12 00:00:00.000000000 Z
12
+ date: 2024-11-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -17,14 +17,14 @@ dependencies:
17
17
  requirements:
18
18
  - - ">="
19
19
  - !ruby/object:Gem::Version
20
- version: 6.0.3
20
+ version: 7.0.0
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
25
  - - ">="
26
26
  - !ruby/object:Gem::Version
27
- version: 6.0.3
27
+ version: 7.0.0
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: pagy
30
30
  requirement: !ruby/object:Gem::Requirement
@@ -39,6 +39,34 @@ dependencies:
39
39
  - - ">="
40
40
  - !ruby/object:Gem::Version
41
41
  version: '3.5'
42
+ - !ruby/object:Gem::Dependency
43
+ name: importmap-rails
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: propshaft
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
42
70
  description: It's an admin, obviously.
43
71
  email:
44
72
  - excid3@gmail.com
@@ -50,9 +78,15 @@ files:
50
78
  - MIT-LICENSE
51
79
  - README.md
52
80
  - Rakefile
53
- - app/assets/config/manifest.js
54
- - app/assets/stylesheets/actiontext.scss
55
- - app/assets/stylesheets/application.css
81
+ - app/assets/config/madmin_manifest.js
82
+ - app/assets/stylesheets/madmin/actiontext.css
83
+ - app/assets/stylesheets/madmin/application.css
84
+ - app/assets/stylesheets/madmin/buttons.css
85
+ - app/assets/stylesheets/madmin/forms.css
86
+ - app/assets/stylesheets/madmin/pagination.css
87
+ - app/assets/stylesheets/madmin/reset.css
88
+ - app/assets/stylesheets/madmin/sidebar.css
89
+ - app/assets/stylesheets/madmin/tables.css
56
90
  - app/controllers/madmin/application_controller.rb
57
91
  - app/controllers/madmin/base_controller.rb
58
92
  - app/controllers/madmin/dashboard_controller.rb
@@ -60,10 +94,14 @@ files:
60
94
  - app/helpers/madmin/application_helper.rb
61
95
  - app/helpers/madmin/nav_helper.rb
62
96
  - app/helpers/madmin/sort_helper.rb
97
+ - app/javascript/madmin/application.js
98
+ - app/javascript/madmin/controllers/application.js
99
+ - app/javascript/madmin/controllers/index.js
100
+ - app/javascript/madmin/controllers/nested_form_controller.js
101
+ - app/javascript/madmin/controllers/select_controller.js
63
102
  - app/views/layouts/madmin/application.html.erb
64
103
  - app/views/madmin/application/_form.html.erb
65
104
  - app/views/madmin/application/_javascript.html.erb
66
- - app/views/madmin/application/_menu_resources.html.erb
67
105
  - app/views/madmin/application/_navigation.html.erb
68
106
  - app/views/madmin/application/edit.html.erb
69
107
  - app/views/madmin/application/index.html.erb
@@ -82,6 +120,9 @@ files:
82
120
  - app/views/madmin/fields/boolean/_form.html.erb
83
121
  - app/views/madmin/fields/boolean/_index.html.erb
84
122
  - app/views/madmin/fields/boolean/_show.html.erb
123
+ - app/views/madmin/fields/currency/_form.html.erb
124
+ - app/views/madmin/fields/currency/_index.html.erb
125
+ - app/views/madmin/fields/currency/_show.html.erb
85
126
  - app/views/madmin/fields/date/_form.html.erb
86
127
  - app/views/madmin/fields/date/_index.html.erb
87
128
  - app/views/madmin/fields/date/_show.html.erb
@@ -125,6 +166,9 @@ files:
125
166
  - app/views/madmin/fields/rich_text/_form.html.erb
126
167
  - app/views/madmin/fields/rich_text/_index.html.erb
127
168
  - app/views/madmin/fields/rich_text/_show.html.erb
169
+ - app/views/madmin/fields/select/_form.html.erb
170
+ - app/views/madmin/fields/select/_index.html.erb
171
+ - app/views/madmin/fields/select/_show.html.erb
128
172
  - app/views/madmin/fields/string/_form.html.erb
129
173
  - app/views/madmin/fields/string/_index.html.erb
130
174
  - app/views/madmin/fields/string/_show.html.erb
@@ -135,6 +179,7 @@ files:
135
179
  - app/views/madmin/fields/time/_index.html.erb
136
180
  - app/views/madmin/fields/time/_show.html.erb
137
181
  - app/views/madmin/shared/_label.html.erb
182
+ - config/importmap.rb
138
183
  - lib/generators/madmin/field/field_generator.rb
139
184
  - lib/generators/madmin/field/templates/_form.html.erb
140
185
  - lib/generators/madmin/field/templates/_index.html.erb
@@ -162,6 +207,7 @@ files:
162
207
  - lib/madmin/fields/attachments.rb
163
208
  - lib/madmin/fields/belongs_to.rb
164
209
  - lib/madmin/fields/boolean.rb
210
+ - lib/madmin/fields/currency.rb
165
211
  - lib/madmin/fields/date.rb
166
212
  - lib/madmin/fields/date_time.rb
167
213
  - lib/madmin/fields/decimal.rb
@@ -176,10 +222,12 @@ files:
176
222
  - lib/madmin/fields/password.rb
177
223
  - lib/madmin/fields/polymorphic.rb
178
224
  - lib/madmin/fields/rich_text.rb
225
+ - lib/madmin/fields/select.rb
179
226
  - lib/madmin/fields/string.rb
180
227
  - lib/madmin/fields/text.rb
181
228
  - lib/madmin/fields/time.rb
182
229
  - lib/madmin/generator_helpers.rb
230
+ - lib/madmin/menu.rb
183
231
  - lib/madmin/namespace.rb
184
232
  - lib/madmin/resource.rb
185
233
  - lib/madmin/resource_builder.rb
@@ -191,7 +239,7 @@ homepage: https://github.com/excid3/madmin
191
239
  licenses:
192
240
  - MIT
193
241
  metadata: {}
194
- post_install_message:
242
+ post_install_message:
195
243
  rdoc_options: []
196
244
  require_paths:
197
245
  - lib
@@ -199,15 +247,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
199
247
  requirements:
200
248
  - - ">="
201
249
  - !ruby/object:Gem::Version
202
- version: 2.5.0
250
+ version: 3.2.0
203
251
  required_rubygems_version: !ruby/object:Gem::Requirement
204
252
  requirements:
205
253
  - - ">="
206
254
  - !ruby/object:Gem::Version
207
255
  version: '0'
208
256
  requirements: []
209
- rubygems_version: 3.5.9
210
- signing_key:
257
+ rubygems_version: 3.5.23
258
+ signing_key:
211
259
  specification_version: 4
212
260
  summary: A modern admin for Ruby on Rails apps
213
261
  test_files: []
@@ -1,2 +0,0 @@
1
- //= link_tree ../images
2
- //= link_directory ../stylesheets .css
@@ -1,36 +0,0 @@
1
- //
2
- // Provides a drop-in pointer for the default Trix stylesheet that will format the toolbar and
3
- // the trix-editor content (whether displayed or under editing). Feel free to incorporate this
4
- // inclusion directly in any other asset bundle and remove this file.
5
- //
6
- //= require trix/dist/trix
7
-
8
- // We need to override trix.css’s image gallery styles to accommodate the
9
- // <action-text-attachment> element we wrap around attachments. Otherwise,
10
- // images in galleries will be squished by the max-width: 33%; rule.
11
- .trix-content {
12
- .attachment-gallery {
13
- > action-text-attachment,
14
- > .attachment {
15
- flex: 1 0 33%;
16
- padding: 0 0.5em;
17
- max-width: 33%;
18
- }
19
-
20
- &.attachment-gallery--2,
21
- &.attachment-gallery--4 {
22
- > action-text-attachment,
23
- > .attachment {
24
- flex-basis: 50%;
25
- max-width: 50%;
26
- }
27
- }
28
- }
29
-
30
- action-text-attachment {
31
- .attachment {
32
- padding: 0 !important;
33
- max-width: 100% !important;
34
- }
35
- }
36
- }
@@ -1,15 +0,0 @@
1
- /*
2
- * This is a manifest file that'll be compiled into application.css, which will include all the files
3
- * listed below.
4
- *
5
- * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's
6
- * vendor/assets/stylesheets directory can be referenced here using a relative path.
7
- *
8
- * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
- * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
- * files in this directory. Styles in this file should be added after the last require_* statement.
11
- * It is generally better to create a new file per style scope.
12
- *
13
- *= require_tree .
14
- *= require_self
15
- */
@@ -1,7 +0,0 @@
1
- <% Madmin.resources.each do |resource| %>
2
- <%= nav_link_to resource.friendly_name.pluralize, resource.index_path, class: "block p-2 rounded hover:bg-gray-100", starts_with: resource.index_path, active_class: "font-bold text-black" %>
3
- <% end %>
4
-
5
- <div class="mt-auto">
6
- <%= link_to "View Madmin on GitHub", "https://github.com/excid3/madmin", target: :_blank, class: "block p-2 rounded text-gray-500 hover:bg-gray-100" %>
7
- </div>