rails_admin 3.0.0.rc3 → 3.1.0.beta

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 (165) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -0
  3. data/README.md +1 -7
  4. data/Rakefile +2 -0
  5. data/app/controllers/rails_admin/application_controller.rb +2 -0
  6. data/app/controllers/rails_admin/main_controller.rb +7 -13
  7. data/app/helpers/rails_admin/application_helper.rb +9 -5
  8. data/app/helpers/rails_admin/form_builder.rb +10 -0
  9. data/app/helpers/rails_admin/main_helper.rb +2 -0
  10. data/app/views/layouts/rails_admin/_head.html.erb +17 -5
  11. data/app/views/layouts/rails_admin/_secondary_navigation.html.erb +4 -2
  12. data/app/views/layouts/rails_admin/application.html.erb +2 -2
  13. data/app/views/rails_admin/main/_form_filtering_multiselect.html.erb +2 -2
  14. data/app/views/rails_admin/main/_form_filtering_select.html.erb +1 -1
  15. data/app/views/rails_admin/main/history.html.erb +1 -1
  16. data/app/views/rails_admin/main/index.html.erb +1 -1
  17. data/app/views/rails_admin/main/show.html.erb +11 -9
  18. data/config/initializers/active_record_extensions.rb +25 -0
  19. data/config/initializers/mongoid_extensions.rb +2 -0
  20. data/config/routes.rb +2 -0
  21. data/lib/generators/rails_admin/importmap_formatter.rb +28 -0
  22. data/lib/generators/rails_admin/install_generator.rb +68 -9
  23. data/lib/generators/rails_admin/templates/rails_admin.js +1 -0
  24. data/lib/generators/rails_admin/templates/rails_admin.scss.erb +1 -0
  25. data/lib/generators/rails_admin/templates/rails_admin.webpacker.js +2 -0
  26. data/lib/generators/rails_admin/utils.rb +2 -0
  27. data/lib/rails_admin/abstract_model.rb +9 -2
  28. data/lib/rails_admin/adapters/active_record/association.rb +10 -0
  29. data/lib/rails_admin/adapters/active_record/object_extension.rb +2 -0
  30. data/lib/rails_admin/adapters/active_record/property.rb +2 -0
  31. data/lib/rails_admin/adapters/active_record.rb +25 -2
  32. data/lib/rails_admin/adapters/composite_primary_keys/association.rb +45 -0
  33. data/lib/rails_admin/adapters/composite_primary_keys.rb +40 -0
  34. data/lib/rails_admin/adapters/mongoid/association.rb +14 -4
  35. data/lib/rails_admin/adapters/mongoid/bson.rb +2 -0
  36. data/lib/rails_admin/adapters/mongoid/extension.rb +2 -0
  37. data/lib/rails_admin/adapters/mongoid/object_extension.rb +2 -0
  38. data/lib/rails_admin/adapters/mongoid/property.rb +2 -0
  39. data/lib/rails_admin/adapters/mongoid.rb +3 -1
  40. data/lib/rails_admin/config/actions/base.rb +7 -0
  41. data/lib/rails_admin/config/actions/bulk_delete.rb +2 -0
  42. data/lib/rails_admin/config/actions/dashboard.rb +2 -0
  43. data/lib/rails_admin/config/actions/delete.rb +2 -0
  44. data/lib/rails_admin/config/actions/edit.rb +2 -0
  45. data/lib/rails_admin/config/actions/export.rb +2 -0
  46. data/lib/rails_admin/config/actions/history_index.rb +2 -0
  47. data/lib/rails_admin/config/actions/history_show.rb +2 -0
  48. data/lib/rails_admin/config/actions/index.rb +2 -0
  49. data/lib/rails_admin/config/actions/new.rb +2 -0
  50. data/lib/rails_admin/config/actions/show.rb +2 -0
  51. data/lib/rails_admin/config/actions/show_in_app.rb +6 -0
  52. data/lib/rails_admin/config/actions.rb +2 -0
  53. data/lib/rails_admin/config/configurable.rb +2 -0
  54. data/lib/rails_admin/config/fields/association.rb +2 -0
  55. data/lib/rails_admin/config/fields/base.rb +24 -8
  56. data/lib/rails_admin/config/fields/factories/action_text.rb +2 -0
  57. data/lib/rails_admin/config/fields/factories/active_storage.rb +2 -0
  58. data/lib/rails_admin/config/fields/factories/association.rb +6 -5
  59. data/lib/rails_admin/config/fields/factories/carrierwave.rb +2 -0
  60. data/lib/rails_admin/config/fields/factories/devise.rb +2 -0
  61. data/lib/rails_admin/config/fields/factories/dragonfly.rb +2 -0
  62. data/lib/rails_admin/config/fields/factories/enum.rb +2 -0
  63. data/lib/rails_admin/config/fields/factories/paperclip.rb +2 -0
  64. data/lib/rails_admin/config/fields/factories/password.rb +2 -0
  65. data/lib/rails_admin/config/fields/factories/shrine.rb +2 -0
  66. data/lib/rails_admin/config/fields/group.rb +2 -0
  67. data/lib/rails_admin/config/fields/types/action_text.rb +2 -0
  68. data/lib/rails_admin/config/fields/types/active_record_enum.rb +2 -0
  69. data/lib/rails_admin/config/fields/types/active_storage.rb +2 -0
  70. data/lib/rails_admin/config/fields/types/all.rb +3 -0
  71. data/lib/rails_admin/config/fields/types/belongs_to_association.rb +3 -5
  72. data/lib/rails_admin/config/fields/types/boolean.rb +3 -1
  73. data/lib/rails_admin/config/fields/types/bson_object_id.rb +2 -0
  74. data/lib/rails_admin/config/fields/types/carrierwave.rb +2 -0
  75. data/lib/rails_admin/config/fields/types/citext.rb +2 -0
  76. data/lib/rails_admin/config/fields/types/ck_editor.rb +2 -0
  77. data/lib/rails_admin/config/fields/types/code_mirror.rb +2 -0
  78. data/lib/rails_admin/config/fields/types/color.rb +2 -0
  79. data/lib/rails_admin/config/fields/types/composite_keys_belongs_to_association.rb +31 -0
  80. data/lib/rails_admin/config/fields/types/date.rb +2 -0
  81. data/lib/rails_admin/config/fields/types/datetime.rb +2 -0
  82. data/lib/rails_admin/config/fields/types/decimal.rb +2 -0
  83. data/lib/rails_admin/config/fields/types/dragonfly.rb +2 -0
  84. data/lib/rails_admin/config/fields/types/enum.rb +2 -0
  85. data/lib/rails_admin/config/fields/types/file_upload.rb +2 -0
  86. data/lib/rails_admin/config/fields/types/float.rb +2 -0
  87. data/lib/rails_admin/config/fields/types/froala.rb +2 -0
  88. data/lib/rails_admin/config/fields/types/has_and_belongs_to_many_association.rb +2 -0
  89. data/lib/rails_admin/config/fields/types/has_many_association.rb +2 -0
  90. data/lib/rails_admin/config/fields/types/has_one_association.rb +3 -1
  91. data/lib/rails_admin/config/fields/types/hidden.rb +2 -0
  92. data/lib/rails_admin/config/fields/types/inet.rb +2 -0
  93. data/lib/rails_admin/config/fields/types/integer.rb +2 -0
  94. data/lib/rails_admin/config/fields/types/json.rb +2 -0
  95. data/lib/rails_admin/config/fields/types/multiple_active_storage.rb +10 -0
  96. data/lib/rails_admin/config/fields/types/multiple_carrierwave.rb +2 -0
  97. data/lib/rails_admin/config/fields/types/multiple_file_upload.rb +2 -0
  98. data/lib/rails_admin/config/fields/types/numeric.rb +2 -0
  99. data/lib/rails_admin/config/fields/types/paperclip.rb +2 -0
  100. data/lib/rails_admin/config/fields/types/password.rb +2 -0
  101. data/lib/rails_admin/config/fields/types/polymorphic_association.rb +2 -0
  102. data/lib/rails_admin/config/fields/types/serialized.rb +2 -0
  103. data/lib/rails_admin/config/fields/types/shrine.rb +2 -0
  104. data/lib/rails_admin/config/fields/types/simple_mde.rb +2 -0
  105. data/lib/rails_admin/config/fields/types/string.rb +2 -0
  106. data/lib/rails_admin/config/fields/types/string_like.rb +2 -0
  107. data/lib/rails_admin/config/fields/types/text.rb +2 -0
  108. data/lib/rails_admin/config/fields/types/time.rb +2 -0
  109. data/lib/rails_admin/config/fields/types/timestamp.rb +2 -0
  110. data/lib/rails_admin/config/fields/types/uuid.rb +2 -0
  111. data/lib/rails_admin/config/fields/types/wysihtml5.rb +2 -0
  112. data/lib/rails_admin/config/fields/types.rb +2 -0
  113. data/lib/rails_admin/config/fields.rb +3 -1
  114. data/lib/rails_admin/config/groupable.rb +2 -0
  115. data/lib/rails_admin/config/has_description.rb +2 -0
  116. data/lib/rails_admin/config/has_fields.rb +3 -1
  117. data/lib/rails_admin/config/has_groups.rb +2 -0
  118. data/lib/rails_admin/config/hideable.rb +2 -0
  119. data/lib/rails_admin/config/inspectable.rb +2 -0
  120. data/lib/rails_admin/config/model.rb +2 -0
  121. data/lib/rails_admin/config/proxyable/proxy.rb +2 -0
  122. data/lib/rails_admin/config/proxyable.rb +2 -0
  123. data/lib/rails_admin/config/sections/base.rb +2 -0
  124. data/lib/rails_admin/config/sections/create.rb +2 -0
  125. data/lib/rails_admin/config/sections/edit.rb +2 -0
  126. data/lib/rails_admin/config/sections/export.rb +2 -0
  127. data/lib/rails_admin/config/sections/list.rb +2 -0
  128. data/lib/rails_admin/config/sections/modal.rb +2 -0
  129. data/lib/rails_admin/config/sections/nested.rb +2 -0
  130. data/lib/rails_admin/config/sections/show.rb +2 -0
  131. data/lib/rails_admin/config/sections/update.rb +2 -0
  132. data/lib/rails_admin/config/sections.rb +2 -0
  133. data/lib/rails_admin/config.rb +7 -1
  134. data/lib/rails_admin/engine.rb +30 -16
  135. data/lib/rails_admin/extension.rb +2 -0
  136. data/lib/rails_admin/extensions/cancancan/authorization_adapter.rb +2 -0
  137. data/lib/rails_admin/extensions/cancancan.rb +2 -0
  138. data/lib/rails_admin/extensions/controller_extension.rb +2 -0
  139. data/lib/rails_admin/extensions/paper_trail/auditing_adapter.rb +3 -1
  140. data/lib/rails_admin/extensions/paper_trail.rb +2 -0
  141. data/lib/rails_admin/extensions/pundit/authorization_adapter.rb +3 -1
  142. data/lib/rails_admin/extensions/pundit.rb +2 -0
  143. data/lib/rails_admin/support/csv_converter.rb +2 -1
  144. data/lib/rails_admin/support/datetime.rb +3 -1
  145. data/lib/rails_admin/support/esmodule_preprocessor.rb +4 -0
  146. data/lib/rails_admin/support/hash_helper.rb +2 -0
  147. data/lib/rails_admin/version.rb +37 -2
  148. data/lib/rails_admin.rb +3 -1
  149. data/lib/tasks/rails_admin.rake +2 -0
  150. data/package.json +1 -1
  151. data/src/rails_admin/base.js +13 -1
  152. data/src/rails_admin/filtering-multiselect.js +5 -10
  153. data/src/rails_admin/filtering-select.js +2 -2
  154. data/src/rails_admin/nested-form-hooks.js +1 -1
  155. data/src/rails_admin/remote-form.js +4 -5
  156. data/src/rails_admin/styles/base/theming.scss +10 -0
  157. data/src/rails_admin/styles/base.scss +5 -5
  158. data/src/rails_admin/ui.js +11 -2
  159. data/src/rails_admin/widgets.js +2 -2
  160. data/vendor/assets/javascripts/rails_admin/flatpickr-with-locales.js +958 -395
  161. data/vendor/assets/javascripts/rails_admin/jquery3.js +118 -109
  162. metadata +9 -5
  163. data/lib/generators/rails_admin/templates/rails_admin.js.erb +0 -2
  164. data/lib/generators/rails_admin/templates/rails_admin.scss +0 -1
  165. data/lib/generators/rails_admin/templates/webpack.config.js +0 -29
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5ed0d71c0798b98c4a0afdff5fa2ed48ffd05d1e0124d52ccdb371012d117479
4
- data.tar.gz: ed51dc928885ae4c57e9f02a9e40cf7689731570a78efc7d1bdfbe3afbd7e298
3
+ metadata.gz: 2594ac2920ab0902ebfd266356904760c4cdfe6160dbc0e7a8924a3351e1835a
4
+ data.tar.gz: 252ab9a0d237488762f8a9b7a2c8c91af3dd0e048e598570722c818da78c075b
5
5
  SHA512:
6
- metadata.gz: ff6f4ff15d8722cb44f4bbfeb8375c6c68c24be7cfadaa1e0b2dcf323f43321bc40296c60cdbcd2a9ecc28685261ca5ef00b046481394044d3f6f3970e6ddf86
7
- data.tar.gz: a23d415f1987f61dd8d5bf7dcac7d2d7307e602a0afe3d16c94d8a639ad952135154cc31728bd1f41e181e0f1a829d39afb8898c6fc1a301a75fa64649b117d7
6
+ metadata.gz: 5ee9f27798eace802666b89d15cd92fcdf120ba44e317a87f15c5be0971d869fd6a897bbf24d0aab0dcb74859cb3dc450c098ad1af9eae4c51a4919dcd019da7
7
+ data.tar.gz: 7b649a4777d4647b6154f5a35560330200d5203390c5b79771cf0cc95e7ba1aa9eab8d6414f680226f3ccc2e5cbbfb5325f4a8654f5191514214c5880cd8ed59
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
5
  gem 'appraisal', '>= 2.0'
data/README.md CHANGED
@@ -14,12 +14,6 @@
14
14
 
15
15
  RailsAdmin is a Rails engine that provides an easy-to-use interface for managing your data.
16
16
 
17
- ## Announcements
18
-
19
- ### [Action required] Security issue
20
-
21
- **RailsAdmin 2.0.1, 2.0.0 and up to 1.4.2 have been reported to have XSS vulnerability.** We strongly recommend that you upgrade RailsAdmin to 2.0.2 (and higher) or 1.4.3 as soon as possible, if you are on those versions. See [d72090ec](https://github.com/railsadminteam/rails_admin/commit/d72090ec6a07c3b9b7b48ab50f3d405f91ff4375) for the detail.
22
-
23
17
  ## Getting started
24
18
 
25
19
  - Check out [the docs][docs].
@@ -45,7 +39,7 @@ RailsAdmin is a Rails engine that provides an easy-to-use interface for managing
45
39
 
46
40
  ## Installation
47
41
 
48
- 1. On your gemfile: `gem 'rails_admin', ['>= 3.0.0.rc3', '< 4']`
42
+ 1. On your gemfile: `gem 'rails_admin', '~> 3.0'`
49
43
  2. Run `bundle install`
50
44
  3. Run `rails g rails_admin:install`
51
45
  4. Provide a namespace for the routes when asked
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Add your own tasks in files placed in lib/tasks ending in .rake,
2
4
  # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rails_admin/abstract_model'
2
4
 
3
5
  module RailsAdmin
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailsAdmin
2
4
  class MainController < RailsAdmin::ApplicationController
3
5
  include ActionView::Helpers::TextHelper
@@ -58,23 +60,15 @@ module RailsAdmin
58
60
  end
59
61
 
60
62
  def get_sort_hash(model_config)
61
- abstract_model = model_config.abstract_model
62
63
  field = model_config.list.fields.detect { |f| f.name.to_s == params[:sort] }
64
+ # If no sort param, default to the `sort_by` specified in the list config
65
+ field ||= model_config.list.possible_fields.detect { |f| f.name == model_config.list.sort_by.try(:to_sym) }
63
66
 
64
67
  column =
65
68
  if field.nil? || field.sortable == false # use default sort, asked field does not exist or is not sortable
66
- field = model_config.list.possible_fields.detect { |f| f.name == model_config.list.sort_by.to_sym }
67
- "#{abstract_model.table_name}.#{model_config.list.sort_by}"
68
- elsif field.sortable == true # use the given field
69
- "#{abstract_model.table_name}.#{field.name}"
70
- elsif (field.sortable.is_a?(String) || field.sortable.is_a?(Symbol)) && field.sortable.to_s.include?('.') # just provide sortable, don't do anything smart
71
- field.sortable
72
- elsif field.sortable.is_a?(Hash) # just join sortable hash, don't do anything smart
73
- "#{field.sortable.keys.first}.#{field.sortable.values.first}"
74
- elsif field.association? # use column on target table
75
- "#{field.associated_model_config.abstract_model.table_name}.#{field.sortable}"
76
- else # use described column in the field conf.
77
- "#{abstract_model.table_name}.#{field.sortable}"
69
+ model_config.list.sort_by
70
+ else
71
+ field.sort_column
78
72
  end
79
73
 
80
74
  params[:sort_reverse] ||= 'false'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailsAdmin
2
4
  module ApplicationHelper
3
5
  def authorized?(action_name, abstract_model = nil, object = nil)
@@ -29,7 +31,7 @@ module RailsAdmin
29
31
 
30
32
  if authorized
31
33
  edit_url = rails_admin.url_for(
32
- action_name: edit_action.action_name,
34
+ action: edit_action.action_name,
33
35
  model_name: abstract_model.to_param,
34
36
  controller: 'rails_admin/main',
35
37
  id: _current_user.id,
@@ -118,10 +120,12 @@ module RailsAdmin
118
120
  abstract_model = node.abstract_model
119
121
  model_param = abstract_model.to_param
120
122
  url = rails_admin.url_for(action: :index, controller: 'rails_admin/main', model_name: model_param)
121
- level_class = " nav-level-#{level}" if level > 0
122
123
  nav_icon = node.navigation_icon ? %(<i class="#{node.navigation_icon}"></i>).html_safe : ''
124
+ css_classes = ['nav-link']
125
+ css_classes.push("nav-level-#{level}") if level > 0
126
+ css_classes.push('active') if defined?(@action) && current_action?(@action, model_param)
123
127
  li = content_tag :li, data: {model: model_param} do
124
- link_to nav_icon + node.label_plural, url, class: "nav-link#{level_class}"
128
+ link_to nav_icon + " " + node.label_plural, url, class: css_classes.join(' ')
125
129
  end
126
130
  child_nodes = parent_groups[abstract_model.model_name]
127
131
  child_nodes ? li + navigation(parent_groups, child_nodes, level + 1) : li
@@ -169,7 +173,7 @@ module RailsAdmin
169
173
  else
170
174
  'javascript:void(0)'
171
175
  end
172
- content_tag(:a, label, {href: href, target: action.link_target, class: ['nav-link', current_action?(action) && 'active', !action.enabled? && 'disabled'].compact})
176
+ content_tag(:a, label, {href: href, target: action.link_target, class: ['nav-link', current_action?(action) && 'active', !action.enabled? && 'disabled'].compact}.merge(action.turbo? ? {} : {data: {turbo: 'false'}}))
173
177
  else
174
178
  content_tag(:span, label)
175
179
  end
@@ -206,7 +210,7 @@ module RailsAdmin
206
210
  yield
207
211
  rescue LoadError => e
208
212
  if /sassc/.match?(e.message)
209
- e = e.exception <<-MSG.gsub(/^\s{10}/, '')
213
+ e = e.exception <<~MSG
210
214
  #{e.message}
211
215
  RailsAdmin requires the gem sassc-rails, make sure to put `gem 'sassc-rails'` to Gemfile.
212
216
  MSG
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'nested_form/builder_mixin'
2
4
 
3
5
  module RailsAdmin
@@ -105,6 +107,14 @@ module RailsAdmin
105
107
  (@dom_name ||= {})[field.name] ||= %(#{@object_name}#{options[:index] && "[#{options[:index]}]"}[#{field.method_name}]#{field.is_a?(Config::Fields::Association) && field.multiple? ? '[]' : ''})
106
108
  end
107
109
 
110
+ def hidden_field(method, options = {})
111
+ if method == :id
112
+ super method, {value: object.id.to_s}
113
+ else
114
+ super
115
+ end
116
+ end
117
+
108
118
  protected
109
119
 
110
120
  def generator_action(action, nested)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailsAdmin
2
4
  module MainHelper
3
5
  def rails_admin_form_for(*args, &block)
@@ -5,13 +5,25 @@
5
5
  <%= csrf_meta_tag %>
6
6
  <% case RailsAdmin::config.asset_source
7
7
  when :webpacker %>
8
- <%= stylesheet_pack_tag "rails_admin" %>
9
- <%= javascript_pack_tag "rails_admin", async: true %>
10
- <% when :webpack, :sprockets %>
8
+ <%= stylesheet_pack_tag "rails_admin", data: {'turbo-track': 'reload'} %>
9
+ <%= javascript_pack_tag "rails_admin", async: true, data: {'turbo-track': 'reload'} %>
10
+ <% when :sprockets %>
11
11
  <% handle_asset_dependency_error do %>
12
- <%= stylesheet_link_tag "rails_admin/application.css", media: :all %>
13
- <%= javascript_include_tag "rails_admin/application.js", async: true %>
12
+ <%= stylesheet_link_tag "rails_admin/application.css", media: :all, data: {'turbo-track': 'reload'} %>
13
+ <%= javascript_include_tag "rails_admin/application.js", async: true, data: {'turbo-track': 'reload'} %>
14
14
  <% end %>
15
+ <% when :webpack %>
16
+ <%= stylesheet_link_tag "rails_admin.css", media: :all, data: {'turbo-track': 'reload'} %>
17
+ <%= javascript_include_tag "rails_admin.js", async: true, data: {'turbo-track': 'reload'} %>
18
+ <% when :importmap %>
19
+ <%= stylesheet_link_tag "rails_admin.css", media: :all, data: {'turbo-track': 'reload'} %>
20
+ <%= javascript_inline_importmap_tag(RailsAdmin::Engine.importmap.to_json(resolver: self)) %>
21
+ <%= javascript_importmap_module_preload_tags(RailsAdmin::Engine.importmap) %>
22
+ <%= javascript_importmap_shim_nonce_configuration_tag %>
23
+ <%= javascript_importmap_shim_tag %>
24
+ <%= # Preload jQuery and make it global, unless jQuery UI fails to initialize
25
+ tag.script "import jQuery from 'jquery'; window.jQuery = jQuery;".html_safe, type: "module" %>
26
+ <%= javascript_import_module_tag 'rails_admin' %>
15
27
  <% else
16
28
  raise "Unknown asset_source: #{RailsAdmin::config.asset_source}"
17
29
  end %>
@@ -1,7 +1,7 @@
1
1
  <ul class="navbar-nav ms-auto root_links">
2
2
  <% actions(:root).select(&:show_in_navigation).each do |action| %>
3
3
  <li class="nav-item <%= action.action_name %>_root_link">
4
- <%= link_to wording_for(:menu, action), { action: action.action_name, controller: 'rails_admin/main' }, class: ['nav-link'] %>
4
+ <%= link_to wording_for(:menu, action), { action: action.action_name, controller: 'rails_admin/main' }, {class: ['nav-link']}.merge(action.turbo? ? {} : {data: {turbo: 'false'}}) %>
5
5
  </li>
6
6
  <% end %>
7
7
  <% if main_app_root_path = (main_app.root_path rescue false) %>
@@ -17,7 +17,9 @@
17
17
  <% end %>
18
18
  <% if logout_path.present? %>
19
19
  <li class="nav-item">
20
- <%= link_to t('admin.misc.log_out'), logout_path, method: logout_method, class: 'nav-link label label-danger' %>
20
+ <%= link_to logout_path, method: logout_method, class: 'nav-link', data: {turbo: 'false'} do %>
21
+ <span class="badge bg-danger"><%= t('admin.misc.log_out') %></span>
22
+ <% end %>
21
23
  </li>
22
24
  <% end %>
23
25
  <% end %>
@@ -5,7 +5,7 @@
5
5
  </head>
6
6
  <body class="rails_admin">
7
7
  <div data-i18n-options="<%= I18n.t("admin.js").to_json %>" id="admin-js"></div>
8
- <nav class="navbar navbar-expand-md fixed-top navbar-dark bg-primary border-bottom">
8
+ <nav class="navbar navbar-expand-md fixed-top <%= RailsAdmin::Config.navbar_css_classes.join(' ') %>">
9
9
  <%= render "layouts/rails_admin/navigation" %>
10
10
  </nav>
11
11
  <div class="container-fluid">
@@ -14,7 +14,7 @@
14
14
  <%= render "layouts/rails_admin/sidebar_navigation" %>
15
15
  </div>
16
16
  <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2">
17
- <div class="container">
17
+ <div class="container-fluid">
18
18
  <%= render template: 'layouts/rails_admin/content' %>
19
19
  </div>
20
20
  </div>
@@ -3,7 +3,7 @@
3
3
  source_abstract_model = RailsAdmin.config(form.object.class).abstract_model
4
4
 
5
5
  selected = form.object.send(field.name)
6
- selected_ids = selected.map{|s| s.send(field.associated_primary_key)}
6
+ selected_ids = selected.map{|s| s.send(field.associated_primary_key).to_s}
7
7
 
8
8
  current_action = params[:action].in?(['create', 'new']) ? 'create' : 'update'
9
9
 
@@ -13,7 +13,7 @@
13
13
  selected.map { |o| [o.send(field.associated_object_label_method), o.send(field.associated_primary_key)] }
14
14
  else
15
15
  i = 0
16
- controller.list_entries(config, :index, field.associated_collection_scope, false).map { |o| [o.send(field.associated_object_label_method), o.send(field.associated_primary_key)] }.sort_by {|a| [selected_ids.index(a[1]) || selected_ids.size, i+=1] }
16
+ controller.list_entries(config, :index, field.associated_collection_scope, false).map { |o| [o.send(field.associated_object_label_method), o.send(field.associated_primary_key).to_s] }.sort_by {|a| [selected_ids.index(a[1]) || selected_ids.size, i+=1] }
17
17
  end
18
18
 
19
19
  js_data = {
@@ -8,7 +8,7 @@
8
8
 
9
9
  xhr = !field.associated_collection_cache_all
10
10
 
11
- collection = xhr ? [[field.formatted_value, field.selected_id]] : controller.list_entries(config, :index, field.associated_collection_scope, false).map { |o| [o.send(field.associated_object_label_method), o.send(field.associated_primary_key)] }
11
+ collection = xhr ? [[field.formatted_value, field.selected_id]] : controller.list_entries(config, :index, field.associated_collection_scope, false).map { |o| [o.send(field.associated_object_label_method), o.send(field.associated_primary_key).to_s] }
12
12
 
13
13
  js_data = {
14
14
  xhr: xhr,
@@ -32,7 +32,7 @@
32
32
  <% selected = (sort == property_name) %>
33
33
  <% sort_direction = (sort_reverse ? "headerSortUp" : "headerSortDown" if selected) %>
34
34
  <% sort_location = send(path_method, params.except("sort_reverse").merge(model_name: @abstract_model.to_param, sort: property_name).merge(selected && sort_reverse != "true" ? {sort_reverse: "true"} : {})) %>
35
- <th class="header <%= column[:css_class] %> <%= sort_direction if selected %>">
35
+ <th class="header <%= column[:css_class] %> <%= sort_direction if selected %>" data-href="<%= sort_location %>">
36
36
  <%= column[:link_text] %>
37
37
  </th>
38
38
  <% end %>
@@ -140,7 +140,7 @@
140
140
  <tr class="<%= @abstract_model.param_key %>_row <%= @model_config.list.with(object: object).row_css_class %>">
141
141
  <% if checkboxes %>
142
142
  <td class="sticky">
143
- <%= check_box_tag "bulk_ids[]", object.id, false %>
143
+ <%= check_box_tag "bulk_ids[]", object.id.to_s, false %>
144
144
  </td>
145
145
  <% end %>
146
146
  <% properties.map{ |property| property.bind(:object, object) }.each do |property| %>
@@ -10,16 +10,18 @@
10
10
  <%= fieldset.help %>
11
11
  </p>
12
12
  <% end %>
13
- <dl>
13
+ <div class="list-group">
14
14
  <% fields.each_with_index do |field, index| %>
15
- <dt>
16
- <span class="<%= field.type_css_class %> <%= field.css_class %> label label-info">
17
- <%= field.label %>
18
- </span>
19
- </dt>
20
- <dd class="well">
21
- <%= field.pretty_value %>
22
- </dd>
15
+ <div class="list-group-item border-0 <%= field.type_css_class %> <%= field.css_class %>">
16
+ <div class="card">
17
+ <h5 class="card-header bg-light">
18
+ <%= field.label %>
19
+ </h5>
20
+ <div class="card-body">
21
+ <%= field.pretty_value %>
22
+ </div>
23
+ </div>
24
+ </div>
23
25
  <% end %>
24
26
  </dl>
25
27
  </div>
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ActiveSupport.on_load(:active_record) do
2
4
  module ActiveRecord
3
5
  class Base
@@ -20,4 +22,27 @@ ActiveSupport.on_load(:active_record) do
20
22
  end
21
23
  end
22
24
  end
25
+
26
+ if defined?(CompositePrimaryKeys)
27
+ # Apply patch until the fix is released:
28
+ # https://github.com/composite-primary-keys/composite_primary_keys/pull/572
29
+ CompositePrimaryKeys::CompositeKeys.class_eval do
30
+ alias_method :to_param, :to_s
31
+ end
32
+
33
+ CompositePrimaryKeys::CollectionAssociation.prepend(Module.new do
34
+ def ids_writer(ids)
35
+ if reflection.association_primary_key.is_a? Array
36
+ ids = CompositePrimaryKeys.normalize(Array(ids).reject(&:blank?), reflection.association_primary_key.size)
37
+ reflection.association_primary_key.each_with_index do |primary_key, i|
38
+ pk_type = klass.type_for_attribute(primary_key)
39
+ ids.each do |id|
40
+ id[i] = pk_type.cast(id[i]) if id.is_a? Array
41
+ end
42
+ end
43
+ end
44
+ super ids
45
+ end
46
+ end)
47
+ end
23
48
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  if defined?(::Mongoid::Document)
2
4
  require 'rails_admin/adapters/mongoid/extension'
3
5
  Mongoid::Document.include RailsAdmin::Adapters::Mongoid::Extension
data/config/routes.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  RailsAdmin::Engine.routes.draw do
2
4
  controller 'main' do
3
5
  RailsAdmin::Config::Actions.all(:root).each { |action| match "/#{action.route_fragment}", action: action.action_name, as: action.action_name, via: action.http_methods }
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'importmap/packager'
4
+
5
+ module RailsAdmin
6
+ class ImportmapFormatter
7
+ attr_reader :packager
8
+
9
+ def initialize(path = 'confing/importmap.rails_admin.rb')
10
+ @packager = Importmap::Packager.new(path)
11
+ end
12
+
13
+ def format
14
+ imports = packager.import("rails_admin@#{RailsAdmin::Version.js}")
15
+
16
+ # Use ESM compatible version to work around https://github.com/cljsjs/packages/issues/1579
17
+ imports['@popperjs/core'].gsub!('lib/index.js', 'dist/esm/popper.js')
18
+
19
+ # Tidy up jQuery UI dependencies
20
+ jquery_uis = imports.keys.filter { |key, _| key =~ /jquery-ui/ }
21
+ imports['jquery-ui/'] = imports[jquery_uis.first].gsub(%r{(@[^/@]+)/[^@]+$}, '\1/')
22
+ imports.reject! { |key, _| jquery_uis.include? key }
23
+
24
+ pins = ['pin "rails_admin", preload: true', packager.pin_for('rails_admin/src/rails_admin/base', imports.delete('rails_admin'))]
25
+ (pins + imports.map { |package, url| packager.pin_for(package, url) }).join("\n")
26
+ end
27
+ end
28
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rails/generators'
2
4
  require 'rails_admin/version'
3
5
  require File.expand_path('utils', __dir__)
@@ -8,7 +10,7 @@ module RailsAdmin
8
10
  include Generators::Utils::InstanceMethods
9
11
 
10
12
  argument :_namespace, type: :string, required: false, desc: 'RailsAdmin url namespace'
11
- class_option :asset, type: :string, required: false, default: nil, desc: 'Asset delivery method [options: webpacker, sprockets]'
13
+ class_option :asset, type: :string, required: false, default: nil, desc: 'Asset delivery method [options: webpacker, webpack, sprockets, importmap]'
12
14
  desc 'RailsAdmin installation generator'
13
15
 
14
16
  def install
@@ -27,10 +29,14 @@ module RailsAdmin
27
29
  case asset
28
30
  when 'webpack'
29
31
  configure_for_webpack
32
+ when 'importmap'
33
+ configure_for_importmap
30
34
  when 'webpacker'
31
35
  configure_for_webpacker5
32
36
  when 'sprockets'
33
37
  configure_for_sprockets
38
+ else
39
+ raise "Unknown asset source: #{asset}"
34
40
  end
35
41
  end
36
42
 
@@ -41,6 +47,10 @@ module RailsAdmin
41
47
 
42
48
  if defined?(Webpacker)
43
49
  'webpacker'
50
+ elsif Rails.root.join('webpack.config.js').exist?
51
+ 'webpack'
52
+ elsif Rails.root.join('config/importmap.rb').exist?
53
+ 'importmap'
44
54
  else
45
55
  'sprockets'
46
56
  end
@@ -52,17 +62,66 @@ module RailsAdmin
52
62
 
53
63
  def configure_for_webpacker5
54
64
  run "yarn add rails_admin@#{RailsAdmin::Version.js}"
55
- @scss_relative_dir = '../stylesheets/'
56
- template 'rails_admin.js.erb', 'app/javascript/packs/rails_admin.js'
57
- template 'rails_admin.scss', 'app/javascript/stylesheets/rails_admin.scss'
65
+ template 'rails_admin.webpacker.js', 'app/javascript/packs/rails_admin.js'
66
+ template 'rails_admin.scss.erb', 'app/javascript/stylesheets/rails_admin.scss'
58
67
  end
59
68
 
60
69
  def configure_for_webpack
61
- run "yarn add rails_admin@#{RailsAdmin::Version.js} css-loader mini-css-extract-plugin sass sass-loader"
62
- @scss_relative_dir = './'
63
- template 'rails_admin.js.erb', 'app/javascript/rails_admin.js'
64
- template 'rails_admin.scss', 'app/javascript/rails_admin.scss'
65
- template 'webpack.config.js', 'webpack.config.js'
70
+ run "yarn add rails_admin@#{RailsAdmin::Version.js}"
71
+ template 'rails_admin.js', 'app/javascript/rails_admin.js'
72
+ webpack_config = File.join(destination_root, 'webpack.config.js')
73
+ marker = %r{application: ["']./app/javascript/application.js["']}
74
+ if File.exist?(webpack_config) && File.read(webpack_config) =~ marker
75
+ insert_into_file 'webpack.config.js', %(,\n rails_admin: "./app/javascript/rails_admin.js"), after: marker
76
+ else
77
+ say 'Add `rails_admin: "./app/javascript/rails_admin.js"` to the entry section in your webpack.config.js.', :red
78
+ end
79
+ setup_css({'build' => 'webpack --config webpack.config.js'})
80
+ end
81
+
82
+ def configure_for_importmap
83
+ run "yarn add rails_admin@#{RailsAdmin::Version.js}"
84
+ template 'rails_admin.js', 'app/javascript/rails_admin.js'
85
+ require_relative 'importmap_formatter'
86
+ add_file 'config/importmap.rails_admin.rb', ImportmapFormatter.new.format
87
+ setup_css
88
+ end
89
+
90
+ def setup_css(additional_script_entries = {})
91
+ gem 'cssbundling-rails'
92
+ rake 'css:install:sass'
93
+
94
+ @fa_font_path = '.'
95
+ template 'rails_admin.scss.erb', 'app/assets/stylesheets/rails_admin.scss'
96
+ asset_config = %{Rails.application.config.assets.paths << Rails.root.join("node_modules/@fortawesome/fontawesome-free/webfonts")\n}
97
+ if File.exist? File.join(destination_root, 'config/initializers/assets.rb')
98
+ append_to_file 'config/initializers/assets.rb', asset_config
99
+ else
100
+ add_file 'config/initializers/assets.rb', asset_config
101
+ end
102
+ add_scripts(additional_script_entries.merge({'build:css' => 'sass ./app/assets/stylesheets/rails_admin.scss:./app/assets/builds/rails_admin.css --no-source-map --load-path=node_modules'}))
103
+ end
104
+
105
+ def add_scripts(entries)
106
+ display 'Add scripts to package.json'
107
+ package = begin
108
+ JSON.parse(File.read(File.join(destination_root, 'package.json')))
109
+ rescue Errno::ENOENT, JSON::ParserError
110
+ {}
111
+ end
112
+ if package['scripts'] && (package['scripts'].keys & entries.keys).any?
113
+ say <<-MESSAGE.gsub(/^ {10}/, ''), :red
114
+ You need to merge "scripts": #{JSON.pretty_generate(entries)} into the existing scripts in your package.json .
115
+ Taking 'build:css' as an example, if you're already have application.sass.css for the sass build, the resulting script would look like:
116
+ sass ./app/assets/stylesheets/application.sass.scss:./app/assets/builds/application.css ./app/assets/stylesheets/rails_admin.scss:./app/assets/builds/rails_admin.css --no-source-map --load-path=node_modules
117
+ MESSAGE
118
+ else
119
+ package['scripts'] ||= {}
120
+ entries.each do |entry, build_script|
121
+ package['scripts'][entry] = build_script
122
+ end
123
+ add_file 'package.json', JSON.pretty_generate(package)
124
+ end
66
125
  end
67
126
  end
68
127
  end
@@ -0,0 +1 @@
1
+ import "rails_admin/src/rails_admin/base";
@@ -0,0 +1 @@
1
+ <%= instance_variable_defined?(:@fa_font_path) ? %{$fa-font-path: "#{@fa_font_path}";\n} : '' %>@import "rails_admin/src/rails_admin/styles/base";
@@ -0,0 +1,2 @@
1
+ import "rails_admin/src/rails_admin/base";
2
+ import "../stylesheets/rails_admin.scss";
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailsAdmin
2
4
  module Generators
3
5
  module Utils
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rails_admin/support/datetime'
2
4
 
3
5
  module RailsAdmin
@@ -99,8 +101,13 @@ module RailsAdmin
99
101
 
100
102
  def initialize_active_record
101
103
  @adapter = :active_record
102
- require 'rails_admin/adapters/active_record'
103
- extend Adapters::ActiveRecord
104
+ if defined?(::CompositePrimaryKeys)
105
+ require 'rails_admin/adapters/composite_primary_keys'
106
+ extend Adapters::CompositePrimaryKeys
107
+ else
108
+ require 'rails_admin/adapters/active_record'
109
+ extend Adapters::ActiveRecord
110
+ end
104
111
  end
105
112
 
106
113
  def initialize_mongoid
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailsAdmin
2
4
  module Adapters
3
5
  module ActiveRecord
@@ -21,6 +23,14 @@ module RailsAdmin
21
23
  association.macro
22
24
  end
23
25
 
26
+ def field_type
27
+ if polymorphic?
28
+ :polymorphic_association
29
+ else
30
+ :"#{association.macro}_association"
31
+ end
32
+ end
33
+
24
34
  def klass
25
35
  if options[:polymorphic]
26
36
  polymorphic_parents(:active_record, model.name.to_s, name) || []
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailsAdmin
2
4
  module Adapters
3
5
  module ActiveRecord
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module RailsAdmin
2
4
  module Adapters
3
5
  module ActiveRecord
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_record'
2
4
  require 'rails_admin/adapters/active_record/association'
3
5
  require 'rails_admin/adapters/active_record/object_extension'
@@ -31,11 +33,11 @@ module RailsAdmin
31
33
  scope ||= scoped
32
34
  scope = scope.includes(options[:include]) if options[:include]
33
35
  scope = scope.limit(options[:limit]) if options[:limit]
34
- scope = scope.where(primary_key => options[:bulk_ids]) if options[:bulk_ids]
36
+ scope = bulk_scope(scope, options) if options[:bulk_ids]
35
37
  scope = query_scope(scope, options[:query]) if options[:query]
36
38
  scope = filter_scope(scope, options[:filters]) if options[:filters]
37
39
  scope = scope.send(Kaminari.config.page_method_name, options[:page]).per(options[:per]) if options[:page] && options[:per]
38
- scope = scope.reorder("#{options[:sort]} #{options[:sort_reverse] ? 'asc' : 'desc'}") if options[:sort]
40
+ scope = sort_scope(scope, options) if options[:sort]
39
41
  scope
40
42
  end
41
43
 
@@ -105,6 +107,27 @@ module RailsAdmin
105
107
  true
106
108
  end
107
109
 
110
+ private
111
+
112
+ def bulk_scope(scope, options)
113
+ scope.where(primary_key => options[:bulk_ids])
114
+ end
115
+
116
+ def sort_scope(scope, options)
117
+ direction = options[:sort_reverse] ? :asc : :desc
118
+ case options[:sort]
119
+ when String, Symbol
120
+ scope.reorder("#{options[:sort]} #{direction}")
121
+ when Array
122
+ scope.reorder(options[:sort].zip(Array.new(options[:sort].size) { direction }).to_h)
123
+ when Hash
124
+ scope.reorder(options[:sort].map { |table_name, column| "#{table_name}.#{column}" }.
125
+ zip(Array.new(options[:sort].size) { direction }).to_h)
126
+ else
127
+ raise ArgumentError.new("Unsupported sort value: #{options[:sort]}")
128
+ end
129
+ end
130
+
108
131
  class WhereBuilder
109
132
  def initialize(scope)
110
133
  @statements = []