jav_madmin 2.6.7 → 3.3.2

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 (87) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +89 -4
  3. data/app/assets/stylesheets/madmin/actiontext.css +31 -0
  4. data/app/assets/stylesheets/madmin/base.css +22 -11
  5. data/app/assets/stylesheets/madmin/buttons.css +9 -9
  6. data/app/assets/stylesheets/madmin/forms.css +271 -11
  7. data/app/assets/stylesheets/madmin/pagination.css +25 -21
  8. data/app/assets/stylesheets/madmin/reset.css +1 -1
  9. data/app/assets/stylesheets/madmin/sidebar.css +6 -6
  10. data/app/assets/stylesheets/madmin/tables.css +2 -1
  11. data/app/controllers/madmin/base_controller.rb +1 -5
  12. data/app/controllers/madmin/resource_controller.rb +53 -19
  13. data/app/helpers/madmin/application_helper.rb +33 -2
  14. data/app/helpers/madmin/filters_helper.rb +26 -0
  15. data/app/helpers/madmin/sort_helper.rb +1 -1
  16. data/app/javascript/madmin/application.js +4 -0
  17. data/app/javascript/madmin/controllers/application.js +0 -3
  18. data/app/javascript/madmin/controllers/filters_controller.js +35 -0
  19. data/app/javascript/madmin/controllers/nested_form_controller.js +5 -0
  20. data/app/javascript/madmin/controllers/select_controller.js +269 -22
  21. data/app/views/layouts/madmin/application.html.erb +1 -0
  22. data/app/views/madmin/application/_active_filters.html.erb +15 -0
  23. data/app/views/madmin/application/_filter.html.erb +13 -0
  24. data/app/views/madmin/application/_filters.html.erb +30 -0
  25. data/app/views/madmin/application/_javascript.html.erb +0 -2
  26. data/app/views/madmin/application/_pagination.html.erb +33 -0
  27. data/app/views/madmin/application/_per_page.html.erb +10 -0
  28. data/app/views/madmin/application/edit.html.erb +1 -1
  29. data/app/views/madmin/application/index.html.erb +9 -12
  30. data/app/views/madmin/application/new.html.erb +1 -1
  31. data/app/views/madmin/application/show.html.erb +2 -2
  32. data/app/views/madmin/fields/array/_form.html.erb +1 -0
  33. data/app/views/madmin/fields/array/_index.html.erb +1 -0
  34. data/app/views/madmin/fields/array/_show.html.erb +1 -0
  35. data/app/views/madmin/fields/attachment/_form.html.erb +1 -5
  36. data/app/views/madmin/fields/attachment/_show.html.erb +3 -1
  37. data/app/views/madmin/fields/attachments/_form.html.erb +1 -1
  38. data/app/views/madmin/fields/belongs_to/_form.html.erb +1 -1
  39. data/app/views/madmin/fields/belongs_to/_index.html.erb +5 -2
  40. data/app/views/madmin/fields/belongs_to/_show.html.erb +1 -1
  41. data/app/views/madmin/fields/enum/_form.html.erb +1 -1
  42. data/app/views/madmin/fields/file/_form.html.erb +1 -1
  43. data/app/views/madmin/fields/has_many/_form.html.erb +1 -1
  44. data/app/views/madmin/fields/has_many/_show.html.erb +3 -11
  45. data/app/views/madmin/fields/has_one/_index.html.erb +5 -1
  46. data/app/views/madmin/fields/has_one/_show.html.erb +1 -1
  47. data/app/views/madmin/fields/json/_form.html.erb +1 -1
  48. data/app/views/madmin/fields/json/_show.html.erb +1 -1
  49. data/app/views/madmin/fields/nested_has_many/_show.html.erb +3 -11
  50. data/app/views/madmin/fields/nested_has_one/_form.html.erb +18 -0
  51. data/app/views/madmin/fields/polymorphic/_form.html.erb +1 -2
  52. data/app/views/madmin/fields/polymorphic/_index.html.erb +5 -1
  53. data/app/views/madmin/fields/polymorphic/_show.html.erb +1 -1
  54. data/app/views/madmin/fields/select/_form.html.erb +1 -1
  55. data/config/importmap.rb +0 -3
  56. data/config/locales/el.yml +47 -0
  57. data/config/locales/en.yml +47 -0
  58. data/config/locales/fr.yml +47 -0
  59. data/config/locales/ko.yml +48 -0
  60. data/lib/generators/madmin/resource/templates/resource.rb.tt +3 -0
  61. data/lib/madmin/field.rb +26 -0
  62. data/lib/madmin/fields/array.rb +16 -0
  63. data/lib/madmin/fields/attachment.rb +7 -0
  64. data/lib/madmin/fields/belongs_to.rb +2 -1
  65. data/lib/madmin/fields/boolean.rb +1 -0
  66. data/lib/madmin/fields/currency.rb +7 -0
  67. data/lib/madmin/fields/date.rb +1 -0
  68. data/lib/madmin/fields/date_time.rb +1 -0
  69. data/lib/madmin/fields/decimal.rb +1 -0
  70. data/lib/madmin/fields/float.rb +1 -0
  71. data/lib/madmin/fields/has_many.rb +8 -23
  72. data/lib/madmin/fields/integer.rb +1 -0
  73. data/lib/madmin/fields/json.rb +21 -0
  74. data/lib/madmin/fields/nested_has_many.rb +2 -2
  75. data/lib/madmin/fields/nested_has_one.rb +48 -0
  76. data/lib/madmin/fields/polymorphic.rb +5 -0
  77. data/lib/madmin/fields/string.rb +2 -0
  78. data/lib/madmin/fields/text.rb +2 -0
  79. data/lib/madmin/filter.rb +113 -0
  80. data/lib/madmin/menu.rb +2 -1
  81. data/lib/madmin/page.rb +89 -0
  82. data/lib/madmin/pagination.rb +50 -0
  83. data/lib/madmin/resource.rb +86 -19
  84. data/lib/madmin/search.rb +5 -7
  85. data/lib/madmin/version.rb +1 -1
  86. data/lib/madmin.rb +45 -3
  87. metadata +17 -15
@@ -0,0 +1,50 @@
1
+ module Madmin
2
+ # Paginates ActiveRecord relations using only the relation API (count, order,
3
+ # offset, limit) so the SQL is generated by whichever database adapter is in use.
4
+ module Pagination
5
+ private
6
+
7
+ # Returns [Madmin::Page, records]
8
+ def paginate(collection, page: 1, per_page: Madmin.per_page, param: :page)
9
+ page = Madmin::Page.new(count: count_for(collection), page: page, per_page: per_page, param: param)
10
+ [page, with_tiebreaker(collection).offset(page.offset).limit(page.per_page)]
11
+ end
12
+
13
+ def count_for(collection)
14
+ # count(:all) keeps custom selects valid, and ordering is irrelevant to a count
15
+ count = collection.unscope(:order).count(:all)
16
+
17
+ # Grouped relations return a Hash of counts per group
18
+ count.is_a?(Hash) ? count.size : count
19
+ end
20
+
21
+ # Appends the primary key to the ordering so rows with equal sort values keep
22
+ # a stable position across pages. It follows the direction of the existing
23
+ # ordering so indexes on the sort column can still be used.
24
+ def with_tiebreaker(collection)
25
+ return collection if collection.group_values.any? || collection.distinct_value
26
+
27
+ primary_keys = Array(collection.klass.primary_key).map(&:to_s)
28
+ return collection if primary_keys.empty?
29
+
30
+ orders = collection.order_values
31
+ return collection if orders.any? { |order| orders_by?(order, primary_keys) }
32
+
33
+ direction = descending?(orders.last) ? :desc : :asc
34
+ table = collection.klass.arel_table
35
+ collection.order(primary_keys.map { |key| table[key].public_send(direction) })
36
+ end
37
+
38
+ def orders_by?(order, column_names)
39
+ order.is_a?(Arel::Nodes::Ordering) && order.expr.respond_to?(:name) && column_names.include?(order.expr.name.to_s)
40
+ end
41
+
42
+ def descending?(order)
43
+ case order
44
+ when Arel::Nodes::Descending then true
45
+ when String then order.match?(/\bdesc\s*\z/i)
46
+ else false
47
+ end
48
+ end
49
+ end
50
+ end
@@ -81,10 +81,22 @@ module Madmin
81
81
  )
82
82
  end
83
83
 
84
- # Returns singular name
85
- # For example: "Forum::Post" -> "Post"
86
- def friendly_name(count: 1)
87
- model.model_name.human(count: count, default: model_name.titleize.pluralize(count, I18n.locale))
84
+ # For example: "Forum::Post" -> "Forum / Post"
85
+ #
86
+ # Uses the model's translation (`activerecord.models.forum/post`) when there is one
87
+ def friendly_name
88
+ translated_name || model_name.split("::").map { |part| part.underscore.humanize }.join(" / ").titlecase
89
+ end
90
+
91
+ # Returns plural name
92
+ # For example: "Forum::Post" -> "Forum / Posts"
93
+ def friendly_plural_name
94
+ singular = translated_name
95
+ return friendly_name.pluralize unless singular
96
+
97
+ # A translation without `one` / `other` forms is the same for every count
98
+ return translated_name(count: 2) if plural_translation? || !locale_inflections?
99
+ singular.pluralize(I18n.locale)
88
100
  end
89
101
 
90
102
  # Support for isolated namespaces
@@ -97,20 +109,29 @@ module Madmin
97
109
  @route_namespace = (namespace ? namespace.name.underscore.to_sym : nil)
98
110
  end
99
111
 
100
- def index_path(options = nil)
101
- build_polymorphic_path([:madmin, route_namespace, model], options)
112
+ def index_path(options = {})
113
+ route_path([:madmin, route_namespace, model], options)
114
+ end
115
+
116
+ def new_path
117
+ route_path([:madmin, route_namespace, model], action: :new)
102
118
  end
103
119
 
104
- def new_path(options = nil)
105
- build_polymorphic_path([:madmin, route_namespace, model], options, action: :new)
120
+ def show_path(record)
121
+ route_path([:madmin, route_namespace, becomes(record)])
106
122
  end
107
123
 
108
- def show_path(record, options = nil)
109
- build_polymorphic_path([:madmin, route_namespace, becomes(record)], options)
124
+ def edit_path(record)
125
+ route_path([:madmin, route_namespace, becomes(record)], action: :edit)
110
126
  end
111
127
 
112
- def edit_path(record, options = nil)
113
- build_polymorphic_path([:madmin, route_namespace, becomes(record)], options, action: :edit)
128
+ # Whether a route is drawn for the given action on this resource's controller
129
+ # For example: PostResource.route?(:destroy)
130
+ def route?(action)
131
+ controller = "madmin/#{model.model_name.collection}"
132
+ Rails.application.routes.routes.any? do |route|
133
+ route.defaults[:controller] == controller && route.defaults[:action] == action.to_s
134
+ end
114
135
  end
115
136
 
116
137
  def becomes(record)
@@ -129,6 +150,14 @@ module Madmin
129
150
  "#{record.model_name.human} ##{record.id}"
130
151
  end
131
152
 
153
+ # Override for wording that needs more than the display name. Return nil to skip the confirmation.
154
+ def delete_confirmation(record)
155
+ I18n.t("madmin.resources.#{model.model_name.i18n_key}.confirmations.delete",
156
+ default: :"madmin.confirmations.delete",
157
+ resource: friendly_name,
158
+ name: display_name(record))
159
+ end
160
+
132
161
  def friendly_model?
133
162
  model.respond_to? :friendly
134
163
  end
@@ -149,6 +178,10 @@ module Madmin
149
178
  attributes.values.select { |a| a.field.searchable? }
150
179
  end
151
180
 
181
+ def filterable_attributes
182
+ attributes.values.select { |a| a.field&.filter_type }
183
+ end
184
+
152
185
  def member_action(collection: false, &block)
153
186
  member_actions << MemberAction.new(collection: collection, &block)
154
187
  end
@@ -164,6 +197,7 @@ module Madmin
164
197
 
165
198
  def field_for_type(type)
166
199
  {
200
+ array: Fields::Array,
167
201
  binary: Fields::String,
168
202
  blob: Fields::Text,
169
203
  boolean: Fields::Boolean,
@@ -223,7 +257,8 @@ module Madmin
223
257
  has_many: Fields::HasMany,
224
258
  has_one: Fields::HasOne,
225
259
  rich_text: Fields::RichText,
226
- nested_has_many: Fields::NestedHasMany
260
+ nested_has_many: Fields::NestedHasMany,
261
+ nested_has_one: Fields::NestedHasOne
227
262
  }[type]
228
263
  end
229
264
 
@@ -234,6 +269,8 @@ module Madmin
234
269
  column_type = model.attribute_types[name_string]
235
270
  if column_type.is_a? ::ActiveRecord::Enum::EnumType
236
271
  :enum
272
+ elsif model.columns_hash[name_string].try(:array?)
273
+ :array
237
274
  else
238
275
  column_type.type || :string
239
276
  end
@@ -272,6 +309,26 @@ module Madmin
272
309
  @url_helpers ||= Rails.application.routes.url_helpers
273
310
  end
274
311
 
312
+ # Raises MissingRoute with instructions instead of a NoMethodError for
313
+ # the undefined route helper when the resource's routes aren't drawn
314
+ def route_path(components, options = {})
315
+ url_helpers.polymorphic_path(components, options)
316
+ rescue NoMethodError => error
317
+ raise unless error.name.to_s.end_with?("_path")
318
+
319
+ *namespaces, resources = model.model_name.collection.split("/")
320
+ routes = namespaces.reverse.inject("resources :#{resources}") do |body, namespace|
321
+ "namespace :#{namespace} do\n#{body.indent(2)}\nend"
322
+ end
323
+
324
+ raise MissingRoute, [
325
+ "`#{error.name}` is not defined, so #{name} has no route for this page.",
326
+ "Add the route inside `namespace :madmin` in your routes:",
327
+ routes.indent(4),
328
+ "To hide the resource from the menu instead, add `menu false` to #{name}."
329
+ ].join("\n\n")
330
+ end
331
+
275
332
  def model_store_accessors
276
333
  return [] unless model.respond_to?(:stored_attributes)
277
334
 
@@ -286,18 +343,28 @@ module Madmin
286
343
  def menu_options
287
344
  return false if @menu_options == false
288
345
  @menu_options ||= {}
289
- @menu_options.with_defaults(label: model.model_name.i18n_key, url: index_path)
346
+ # The default label follows the locale, so the menu tracks the item by resource instead
347
+ @menu_options.with_defaults(key: @menu_options[:label] || name, label: friendly_plural_name, url: index_path)
290
348
  end
291
349
 
292
350
  private
293
351
 
294
- def locale_options
295
- Madmin.multi_locales ? {locale: I18n.locale} : {}
352
+ def translated_name(count: 1)
353
+ model.model_name.human(count: count, default: "").presence
354
+ end
355
+
356
+ # Whether the model's translation spells out its own `one` / `other` forms
357
+ def plural_translation?
358
+ model.lookup_ancestors.each do |klass|
359
+ translation = I18n.t(klass.model_name.i18n_key, scope: [klass.i18n_scope, :models], default: "")
360
+ return translation.is_a?(Hash) if translation.present?
361
+ end
362
+ false
296
363
  end
297
364
 
298
- def build_polymorphic_path(path_array, options, extra_opts = {})
299
- opts = (options || {}).merge(extra_opts).merge(locale_options)
300
- url_helpers.polymorphic_path(path_array, opts)
365
+ # Locales without inflection rules of their own (most non-English ones) are left unpluralized
366
+ def locale_inflections?
367
+ ActiveSupport::Inflector::Inflections.instance(I18n.locale).plurals.any?
301
368
  end
302
369
  end
303
370
 
data/lib/madmin/search.rb CHANGED
@@ -2,20 +2,18 @@
2
2
 
3
3
  module Madmin
4
4
  class Search
5
- attr_reader :query
5
+ attr_reader :query, :filters
6
6
 
7
- def initialize(scoped_resource, resource, term)
7
+ def initialize(scoped_resource, resource, term, filters = [])
8
8
  @resource = resource
9
9
  @scoped_resource = scoped_resource
10
10
  @query = term
11
+ @filters = filters
11
12
  end
12
13
 
13
14
  def run
14
- if query.blank?
15
- @scoped_resource.all
16
- else
17
- search_results(@scoped_resource)
18
- end
15
+ results = query.blank? ? @scoped_resource.all : search_results(@scoped_resource)
16
+ filters.reduce(results) { |scope, filter| filter.apply(scope) }
19
17
  end
20
18
 
21
19
  private
@@ -1,3 +1,3 @@
1
1
  module Madmin
2
- VERSION = "2.6.7"
2
+ VERSION = "3.3.2"
3
3
  end
data/lib/madmin.rb CHANGED
@@ -2,18 +2,21 @@ require "madmin/engine"
2
2
  require "importmap-rails"
3
3
  require "stimulus-rails"
4
4
  require "turbo-rails"
5
- require "pagy"
6
5
 
7
6
  module Madmin
8
7
  autoload :Field, "madmin/field"
8
+ autoload :Filter, "madmin/filter"
9
9
  autoload :GeneratorHelpers, "madmin/generator_helpers"
10
10
  autoload :MemberAction, "madmin/member_action"
11
11
  autoload :Menu, "madmin/menu"
12
+ autoload :Page, "madmin/page"
13
+ autoload :Pagination, "madmin/pagination"
12
14
  autoload :Resource, "madmin/resource"
13
15
  autoload :ResourceBuilder, "madmin/resource_builder"
14
16
  autoload :Search, "madmin/search"
15
17
 
16
18
  module Fields
19
+ autoload :Array, "madmin/fields/array"
17
20
  autoload :Attachment, "madmin/fields/attachment"
18
21
  autoload :Attachments, "madmin/fields/attachments"
19
22
  autoload :BelongsTo, "madmin/fields/belongs_to"
@@ -30,6 +33,7 @@ module Madmin
30
33
  autoload :Integer, "madmin/fields/integer"
31
34
  autoload :Json, "madmin/fields/json"
32
35
  autoload :NestedHasMany, "madmin/fields/nested_has_many"
36
+ autoload :NestedHasOne, "madmin/fields/nested_has_one"
33
37
  autoload :Password, "madmin/fields/password"
34
38
  autoload :Polymorphic, "madmin/fields/polymorphic"
35
39
  autoload :RichText, "madmin/fields/rich_text"
@@ -41,14 +45,17 @@ module Madmin
41
45
 
42
46
  mattr_accessor :importmap, default: Importmap::Map.new
43
47
  mattr_accessor :menu, default: Menu.new
48
+ mattr_accessor :per_page, default: 20
44
49
  mattr_accessor :site_name
45
50
  mattr_accessor :stylesheets, default: []
46
51
  mattr_accessor :resource_locations, default: []
47
- mattr_accessor :multi_locales, default: false, instance_accessor: false
48
52
 
49
53
  class MissingResource < StandardError
50
54
  end
51
55
 
56
+ class MissingRoute < StandardError
57
+ end
58
+
52
59
  class << self
53
60
  # Returns a Madmin::Resource class for the given object
54
61
  def resource_for(object)
@@ -59,6 +66,12 @@ module Madmin
59
66
  elsif (resource_name = sti_resource_name_for(object)) && Object.const_defined?(resource_name)
60
67
  resource_name.constantize
61
68
 
69
+ # A resource named differently from its model (`ArticleResource` for
70
+ # `Blog::Post`) still says which model it is for with `model`. Honor that
71
+ # declaration before giving up, so association cells can link to it.
72
+ elsif (resource = resource_declaring(object.class))
73
+ resource
74
+
62
75
  else
63
76
  raise MissingResource, <<~MESSAGE
64
77
  `#{object.class.name}Resource` is missing.
@@ -70,6 +83,28 @@ module Madmin
70
83
  end
71
84
  end
72
85
 
86
+ # The one resource whose `model` is +klass+ or, failing that, its nearest
87
+ # superclass, or nil. Two resources declaring the same model with neither
88
+ # matching its name is ambiguous, and guessing would silently link to the
89
+ # wrong admin page, so that raises.
90
+ def resource_declaring(klass)
91
+ declared = klass.ancestors.grep(Class).find { |ancestor| resources_by_model.key?(ancestor) }
92
+ return unless declared
93
+
94
+ candidates = resources_by_model[declared]
95
+ return candidates.first if candidates.one?
96
+
97
+ raise MissingResource, <<~MESSAGE
98
+ `#{declared.name}Resource` is missing, and #{candidates.map(&:name).join(", ")} all declare `model #{declared.name}`.
99
+
100
+ Madmin can't tell which one to use. Name one of them `#{declared.name}Resource`.
101
+ MESSAGE
102
+ end
103
+
104
+ def resources_by_model
105
+ @resources_by_model ||= resources.group_by(&:model)
106
+ end
107
+
73
108
  def resource_name_for(object)
74
109
  if object.is_a? ::ActiveStorage::Attached
75
110
  "ActiveStorage::AttachmentResource"
@@ -86,13 +121,19 @@ module Madmin
86
121
  end
87
122
  end
88
123
 
124
+ # Returns the Madmin::Resource class for a model or model name, falling
125
+ # back to the resource that declares the model when none is named after it
89
126
  def resource_by_name(name)
90
127
  "#{name}Resource".constantize
91
128
  rescue NameError
129
+ model = name.is_a?(Class) ? name : name.to_s.safe_constantize
130
+ resource = resource_declaring(model) if model
131
+ return resource if resource
132
+
92
133
  raise MissingResource, <<~MESSAGE
93
134
  #{name}Resource is missing. Create it by running:
94
135
 
95
- bin/rails generate madmin:resource #{resource_name.split("Resource").first}
136
+ bin/rails generate madmin:resource #{name}
96
137
  MESSAGE
97
138
  end
98
139
 
@@ -102,6 +143,7 @@ module Madmin
102
143
 
103
144
  def reset_resources!
104
145
  @resources = nil
146
+ @resources_by_model = nil
105
147
  menu.reset
106
148
  end
107
149
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jav_madmin
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.6.7
4
+ version: 3.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Oliver
@@ -25,20 +25,6 @@ dependencies:
25
25
  - - ">="
26
26
  - !ruby/object:Gem::Version
27
27
  version: 7.0.0
28
- - !ruby/object:Gem::Dependency
29
- name: pagy
30
- requirement: !ruby/object:Gem::Requirement
31
- requirements:
32
- - - ">="
33
- - !ruby/object:Gem::Version
34
- version: '3.5'
35
- type: :runtime
36
- prerelease: false
37
- version_requirements: !ruby/object:Gem::Requirement
38
- requirements:
39
- - - ">="
40
- - !ruby/object:Gem::Version
41
- version: '3.5'
42
28
  - !ruby/object:Gem::Dependency
43
29
  name: importmap-rails
44
30
  requirement: !ruby/object:Gem::Requirement
@@ -109,25 +95,35 @@ files:
109
95
  - app/controllers/madmin/dashboard_controller.rb
110
96
  - app/controllers/madmin/resource_controller.rb
111
97
  - app/helpers/madmin/application_helper.rb
98
+ - app/helpers/madmin/filters_helper.rb
112
99
  - app/helpers/madmin/nav_helper.rb
113
100
  - app/helpers/madmin/sort_helper.rb
114
101
  - app/javascript/madmin/application.js
115
102
  - app/javascript/madmin/controllers/application.js
103
+ - app/javascript/madmin/controllers/filters_controller.js
116
104
  - app/javascript/madmin/controllers/index.js
117
105
  - app/javascript/madmin/controllers/mobile_nav_controller.js
118
106
  - app/javascript/madmin/controllers/nested_form_controller.js
119
107
  - app/javascript/madmin/controllers/select_controller.js
120
108
  - app/views/layouts/madmin/application.html.erb
109
+ - app/views/madmin/application/_active_filters.html.erb
110
+ - app/views/madmin/application/_filter.html.erb
111
+ - app/views/madmin/application/_filters.html.erb
121
112
  - app/views/madmin/application/_flash.html.erb
122
113
  - app/views/madmin/application/_form.html.erb
123
114
  - app/views/madmin/application/_javascript.html.erb
124
115
  - app/views/madmin/application/_missing_resource.html.erb
125
116
  - app/views/madmin/application/_navigation.html.erb
117
+ - app/views/madmin/application/_pagination.html.erb
118
+ - app/views/madmin/application/_per_page.html.erb
126
119
  - app/views/madmin/application/edit.html.erb
127
120
  - app/views/madmin/application/index.html.erb
128
121
  - app/views/madmin/application/new.html.erb
129
122
  - app/views/madmin/application/show.html.erb
130
123
  - app/views/madmin/dashboard/show.html.erb
124
+ - app/views/madmin/fields/array/_form.html.erb
125
+ - app/views/madmin/fields/array/_index.html.erb
126
+ - app/views/madmin/fields/array/_show.html.erb
131
127
  - app/views/madmin/fields/attachment/_form.html.erb
132
128
  - app/views/madmin/fields/attachment/_index.html.erb
133
129
  - app/views/madmin/fields/attachment/_show.html.erb
@@ -177,6 +173,7 @@ files:
177
173
  - app/views/madmin/fields/nested_has_many/_form.html.erb
178
174
  - app/views/madmin/fields/nested_has_many/_index.html.erb
179
175
  - app/views/madmin/fields/nested_has_many/_show.html.erb
176
+ - app/views/madmin/fields/nested_has_one/_form.html.erb
180
177
  - app/views/madmin/fields/password/_form.html.erb
181
178
  - app/views/madmin/fields/password/_index.html.erb
182
179
  - app/views/madmin/fields/password/_show.html.erb
@@ -227,6 +224,7 @@ files:
227
224
  - lib/madmin.rb
228
225
  - lib/madmin/engine.rb
229
226
  - lib/madmin/field.rb
227
+ - lib/madmin/fields/array.rb
230
228
  - lib/madmin/fields/attachment.rb
231
229
  - lib/madmin/fields/attachments.rb
232
230
  - lib/madmin/fields/belongs_to.rb
@@ -243,6 +241,7 @@ files:
243
241
  - lib/madmin/fields/integer.rb
244
242
  - lib/madmin/fields/json.rb
245
243
  - lib/madmin/fields/nested_has_many.rb
244
+ - lib/madmin/fields/nested_has_one.rb
246
245
  - lib/madmin/fields/password.rb
247
246
  - lib/madmin/fields/polymorphic.rb
248
247
  - lib/madmin/fields/rich_text.rb
@@ -250,10 +249,13 @@ files:
250
249
  - lib/madmin/fields/string.rb
251
250
  - lib/madmin/fields/text.rb
252
251
  - lib/madmin/fields/time.rb
252
+ - lib/madmin/filter.rb
253
253
  - lib/madmin/generator_helpers.rb
254
254
  - lib/madmin/member_action.rb
255
255
  - lib/madmin/menu.rb
256
256
  - lib/madmin/namespace.rb
257
+ - lib/madmin/page.rb
258
+ - lib/madmin/pagination.rb
257
259
  - lib/madmin/resource.rb
258
260
  - lib/madmin/resource_builder.rb
259
261
  - lib/madmin/search.rb