rails_admin 1.0.0.rc → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of rails_admin might be problematic. Click here for more details.

Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -2
  3. data/README.md +1 -14
  4. data/app/assets/javascripts/rails_admin/ra.filtering-multiselect.js +15 -10
  5. data/app/assets/javascripts/rails_admin/ra.filtering-select.js +205 -110
  6. data/app/assets/javascripts/rails_admin/ra.remote-form.js +1 -4
  7. data/app/controllers/rails_admin/application_controller.rb +5 -5
  8. data/app/controllers/rails_admin/main_controller.rb +2 -2
  9. data/app/helpers/rails_admin/application_helper.rb +2 -2
  10. data/app/helpers/rails_admin/form_builder.rb +9 -2
  11. data/app/helpers/rails_admin/main_helper.rb +1 -1
  12. data/app/views/layouts/rails_admin/application.html.haml +1 -0
  13. data/app/views/rails_admin/main/_delete_notice.html.haml +14 -9
  14. data/app/views/rails_admin/main/index.html.haml +2 -2
  15. data/config/initializers/active_record_extensions.rb +2 -2
  16. data/config/locales/rails_admin.en.yml +1 -0
  17. data/lib/rails_admin/abstract_model.rb +6 -7
  18. data/lib/rails_admin/adapters/active_record.rb +30 -11
  19. data/lib/rails_admin/adapters/mongoid.rb +2 -2
  20. data/lib/rails_admin/adapters/mongoid/association.rb +2 -2
  21. data/lib/rails_admin/adapters/mongoid/extension.rb +1 -1
  22. data/lib/rails_admin/adapters/mongoid/property.rb +1 -1
  23. data/lib/rails_admin/bootstrap-sass.rb +1 -3
  24. data/lib/rails_admin/bootstrap-sass/compass_functions.rb +1 -1
  25. data/lib/rails_admin/config.rb +12 -8
  26. data/lib/rails_admin/config/actions.rb +1 -1
  27. data/lib/rails_admin/config/actions/base.rb +3 -4
  28. data/lib/rails_admin/config/actions/bulk_delete.rb +1 -3
  29. data/lib/rails_admin/config/actions/index.rb +3 -5
  30. data/lib/rails_admin/config/configurable.rb +4 -6
  31. data/lib/rails_admin/config/fields/association.rb +1 -1
  32. data/lib/rails_admin/config/fields/base.rb +15 -26
  33. data/lib/rails_admin/config/fields/factories/carrierwave.rb +1 -1
  34. data/lib/rails_admin/config/fields/types.rb +1 -1
  35. data/lib/rails_admin/config/fields/types/active_record_enum.rb +17 -2
  36. data/lib/rails_admin/config/fields/types/file_upload.rb +1 -1
  37. data/lib/rails_admin/config/fields/types/has_many_association.rb +1 -1
  38. data/lib/rails_admin/config/fields/types/polymorphic_association.rb +1 -1
  39. data/lib/rails_admin/config/fields/types/string.rb +6 -5
  40. data/lib/rails_admin/config/fields/types/text.rb +3 -3
  41. data/lib/rails_admin/config/hideable.rb +1 -1
  42. data/lib/rails_admin/config/inspectable.rb +39 -0
  43. data/lib/rails_admin/config/model.rb +4 -17
  44. data/lib/rails_admin/config/sections/base.rb +4 -17
  45. data/lib/rails_admin/engine.rb +3 -2
  46. data/lib/rails_admin/extension.rb +4 -4
  47. data/lib/rails_admin/extensions/paper_trail/auditing_adapter.rb +10 -2
  48. data/lib/rails_admin/extensions/pundit/authorization_adapter.rb +11 -1
  49. data/lib/rails_admin/support/datetime.rb +1 -1
  50. data/lib/rails_admin/version.rb +1 -1
  51. metadata +7 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ad179cb9f029df989c979439f2e5debb9b2a8f23
4
- data.tar.gz: 2a148ec6c217c0dc67369cb0164bed57db97b953
3
+ metadata.gz: b5f7c910bef240049b818e4189a241c41e68e180
4
+ data.tar.gz: ea59f46605ddef6defbe19c6846d3d9ee6419166
5
5
  SHA512:
6
- metadata.gz: c5c61a2c10d83cdbc00fb163974026eba3a940bd998e674a2e0a256b41f7a9aec821e6aca93a3904bc801d6ee240022bc736b04764bea11953f64ef705ed1d7e
7
- data.tar.gz: aa9a9cfb2e7eda6f0fd9b3bc2fe16430eb83120499da7e87f0361a93a3b3734e458ec6ac0a0bd553bb6d25fa7f4829f3e717ad15d6cf195efd4771e3b62b0738
6
+ metadata.gz: c9c9d4bc637f60e21978c7ce73f693987de692177f79a61ab27757cd75b3ee531575d5bff729361d57c2fad35e82eb48763b5dc4a0c8615394569af7a2a5da5f
7
+ data.tar.gz: 9f16f21be6393621ee9e3b3de88fa3c4c11e75d2d972b88fe411acc04625568adba1c580ede46ae97c012b637b1d75730b49515d3e0379ea8949806e78f851b2
data/Gemfile CHANGED
@@ -2,7 +2,6 @@ source 'https://rubygems.org'
2
2
 
3
3
  gem 'appraisal', '>= 2.0'
4
4
  gem 'devise'
5
- gem 'remotipart', github: 'mshibuya/remotipart'
6
5
 
7
6
  group :active_record do
8
7
  platforms :jruby do
@@ -43,7 +42,7 @@ group :test do
43
42
  gem 'pundit'
44
43
  gem 'rack-cache', require: 'rack/cache'
45
44
  gem 'rspec-rails', '>= 2.14'
46
- gem 'rubocop', '~> 0.31.0'
45
+ gem 'rubocop', '~> 0.41.2'
47
46
  gem 'simplecov', '>= 0.9', require: false
48
47
  gem 'timecop', '>= 0.5'
49
48
 
data/README.md CHANGED
@@ -33,20 +33,7 @@ RailsAdmin is a Rails engine that provides an easy-to-use interface for managing
33
33
 
34
34
  ## Installation
35
35
 
36
- 1. On your gemfile:
37
- - For Rails 5 project:
38
-
39
- ```
40
- gem 'remotipart', github: 'mshibuya/remotipart'
41
- gem 'rails_admin', '>= 1.0.0.rc'
42
- ```
43
-
44
- - For Rails 4 project:
45
-
46
- ```
47
- gem 'rails_admin'
48
- ```
49
-
36
+ 1. On your gemfile: `gem 'rails_admin', '~> 1.0'`
50
37
  2. Run `bundle install`
51
38
  3. Run `rails g rails_admin:install`
52
39
  4. Provide a namespace for the routes when asked
@@ -175,22 +175,25 @@
175
175
  _queryFilter: function(val) {
176
176
  var widget = this;
177
177
  widget._query(val, function(matches) {
178
- var i;
178
+
179
179
  var filtered = [];
180
- for (i in matches) {
181
- if (matches.hasOwnProperty(i) && !widget.selected(matches[i].id)) {
180
+ var i;
181
+
182
+ for (i = 0; i < matches.length; i++) {
183
+ if (!widget.selected(matches[i].id)) {
182
184
  filtered.push(i);
183
185
  }
184
186
  }
185
187
  if (filtered.length > 0) {
186
- widget.collection.html('');
187
- for (i in filtered) {
188
- widget.collection.append(
189
- $('<option></option>').attr('value', matches[filtered[i]].id).attr('title', matches[filtered[i]].label).text(matches[filtered[i]].label)
190
- );
188
+ widget.collection[0].innerHTML = '';
189
+ var filteredContainer = [];
190
+ for (i = 0; i < filtered.length; i++) {
191
+ var newOptions = '<option value="'+matches[filtered[i]].id+'" title="'+matches[filtered[i]].label+'">'+matches[filtered[i]].label+'</option>';
192
+ filteredContainer.push(newOptions);
191
193
  }
194
+ widget.collection[0].innerHTML = filteredContainer.join("");
192
195
  } else {
193
- widget.collection.html(widget.noObjectsPlaceholder);
196
+ widget.collection[0].innerHTML = widget.noObjectsPlaceholder;
194
197
  }
195
198
  });
196
199
  },
@@ -314,7 +317,9 @@
314
317
  },
315
318
 
316
319
  selected: function(value) {
317
- return this.element.find('option[value="' + value + '"]').attr("selected");
320
+ if (this.selection[0].querySelectorAll('option[value="' + value + '"]')[0]) {
321
+ return true;
322
+ }
318
323
  },
319
324
 
320
325
  destroy: function() {
@@ -14,7 +14,9 @@
14
14
  * jquery.ui.autocomplete.js
15
15
  */
16
16
  (function($) {
17
- $.widget("ra.filteringSelect", {
17
+ 'use strict';
18
+
19
+ $.widget('ra.filteringSelect', {
18
20
  options: {
19
21
  createQuery: function(query) {
20
22
  return { query: query };
@@ -26,135 +28,90 @@
26
28
  xhr: false
27
29
  },
28
30
 
31
+ button: null,
32
+ input: null,
33
+ select: null,
34
+
29
35
  _create: function() {
30
- var self = this,
31
- select = this.element.hide(),
32
- selected = select.children(":selected"),
33
- value = selected.val() ? selected.text() : "";
36
+ var filtering_select;
34
37
 
35
- if (this.options.xhr) {
36
- this.options.source = this.options.remote_source;
38
+ // When using the browser back and forward buttons, it is possible that
39
+ // the autocomplete field will be cached which causes duplicate fields
40
+ // to be generated.
41
+ if (this.element.is(':visible')) {
42
+ this.element.hide();
43
+ filtering_select = this._inputGroup(this.element.attr('id'));
44
+ this.input = this._inputField();
45
+ this.button = this._buttonField();
37
46
  } else {
38
- this.options.source = select.children("option").map(function() {
39
- return { label: $(this).text(), value: this.value };
40
- }).toArray();
47
+ filtering_select = this.element.siblings(
48
+ '[data-input-for="' + this.element.attr('id') + '"]'
49
+ );
50
+ this.input = filtering_select.children('input');
51
+ this.button = filtering_select.children('.input-group-btn');
41
52
  }
42
- var filtering_select = $('<div class="input-group filtering-select col-sm-2" style="float:left"></div>')
43
- var input = this.input = $('<input type="text">')
44
- .val(value)
45
- .addClass("form-control ra-filtering-select-input")
46
- .attr('style', select.attr('style'))
47
- .show()
48
- .autocomplete({
49
- delay: this.options.searchDelay,
50
- minLength: this.options.minLength,
51
- source: this._getSourceFunction(this.options.source),
52
- select: function(event, ui) {
53
- var option = $('<option></option>').attr('value', ui.item.id).attr('selected', 'selected').text(ui.item.value);
54
- select.html(option);
55
- select.trigger("change", ui.item.id);
56
- self._trigger("selected", event, {
57
- item: option
58
- });
59
- $(self.element.parents('.controls')[0]).find('.update').removeClass('disabled');
60
- },
61
- change: function(event, ui) {
62
- if (!ui.item) {
63
- var matcher = new RegExp("^" + $.ui.autocomplete.escapeRegex($(this).val()) + "$", "i"),
64
- valid = false;
65
- select.children("option").each(function() {
66
- if ($(this).text().match(matcher)) {
67
- this.selected = valid = true;
68
- return false;
69
- }
70
- });
71
- if (!valid || $(this).val() == '') {
72
- // remove invalid value, as it didn't match anything
73
- $(this).val(null);
74
- select.html($('<option value="" selected="selected"></option>'));
75
- input.data("ui-autocomplete").term = "";
76
- $(self.element.parents('.controls')[0]).find('.update').addClass('disabled');
77
- return false;
78
- }
79
-
80
- }
81
- }
82
- })
83
- .keyup(function() {
84
- /* Clear select options and trigger change if selected item is deleted */
85
- if ($(this).val().length == 0) {
86
- select.html($('<option value="" selected="selected"></option>'));
87
- select.trigger("change");
88
- }
89
- })
90
-
91
- if(select.attr('placeholder'))
92
- input.attr('placeholder', select.attr('placeholder'))
93
-
94
- input.data("ui-autocomplete")._renderItem = function(ul, item) {
95
- return $("<li></li>")
96
- .data("ui-autocomplete-item", item)
97
- .append( $( "<a></a>" ).html( item.html || item.id ) )
98
- .appendTo(ul);
99
- };
100
-
101
- var button = this.button = $('<span class="input-group-btn"><label class="btn btn-info dropdown-toggle" data-toggle="dropdown" aria-expanded="false" title="Show All Items" role="button"><span class="caret"></span><span class="ui-button-text">&nbsp;</span></label></span>')
102
- .click(function() {
103
- // close if already visible
104
- if (input.autocomplete("widget").is(":visible")) {
105
- input.autocomplete("close");
106
- return;
107
- }
108
-
109
- // pass empty string as value to search for, displaying all results
110
- input.autocomplete("search", "");
111
- input.focus();
112
- });
113
-
114
- filtering_select.append(input).append(button).insertAfter(select);
115
53
 
54
+ this._setOptionsSource();
55
+ this._initAutocomplete();
56
+ this._initKeyEvent();
57
+ this._overloadRenderItem();
58
+ this._autocompleteDropdownEvent(this.button);
116
59
 
60
+ return filtering_select.append(this.input)
61
+ .append(this.button)
62
+ .insertAfter(this.element);
117
63
  },
118
64
 
119
65
  _getResultSet: function(request, data, xhr) {
120
- var matcher = new RegExp($.ui.autocomplete.escapeRegex(request.term), "i");
121
- var highlighter = function(label, word){
122
- if(word.length > 0){
123
- return $.map(label.split(word), function(el, i){
124
- return $('<span></span>').text(el).html();
125
- }).join($('<strong></strong>').text(word)[0].outerHTML);
126
- }else{
127
- return $('<span></span>').text(label).html();
128
- }
66
+ var matcher = new RegExp($.ui.autocomplete.escapeRegex(request.term), 'i');
67
+
68
+ var spannedContent = function(content) {
69
+ return $('<span>').text(content).html();
129
70
  };
130
71
 
131
- return $.map(data, function(el, i) {
132
- // match regexp only for local requests, remote ones are already filtered, and label may not contain filtered term.
133
- if ((el.id || el.value) && (xhr || matcher.test(el.label))) {
134
- return {
135
- html: highlighter(el.label || el.id, request.term),
136
- value: el.label || el.id,
137
- id: el.id || el.value
138
- };
72
+ var highlighter = function(label, word) {
73
+ if(word.length) {
74
+ return $.map(
75
+ label.split(word),
76
+ function(el) {
77
+ return spannedContent(el);
78
+ })
79
+ .join($('<strong>')
80
+ .text(word)[0]
81
+ .outerHTML
82
+ );
83
+ } else {
84
+ return spannedContent(label);
139
85
  }
86
+ };
87
+
88
+ return $.map(
89
+ data,
90
+ function(el) {
91
+ var id = el.id || el.value;
92
+ var value = el.label || el.id;
93
+ // match regexp only for local requests, remote ones are already
94
+ // filtered, and label may not contain filtered term.
95
+ if (id && (xhr || matcher.test(el.label))) {
96
+ return {
97
+ html: highlighter(value, request.term),
98
+ value: value,
99
+ id: id
100
+ };
101
+ }
140
102
  });
141
103
  },
142
104
 
143
105
  _getSourceFunction: function(source) {
144
-
145
- var self = this,
146
- requestIndex = 0;
106
+ var self = this;
107
+ var requestIndex = 0;
147
108
 
148
109
  if ($.isArray(source)) {
149
-
150
110
  return function(request, response) {
151
111
  response(self._getResultSet(request, source, false));
152
112
  };
153
-
154
- } else if (typeof source === "string") {
155
-
113
+ } else if (typeof source === 'string') {
156
114
  return function(request, response) {
157
-
158
115
  if (this.xhr) {
159
116
  this.xhr.abort();
160
117
  }
@@ -162,7 +119,7 @@
162
119
  this.xhr = $.ajax({
163
120
  url: source,
164
121
  data: self.options.createQuery(request.term),
165
- dataType: "json",
122
+ dataType: 'json',
166
123
  autocompleteRequest: ++requestIndex,
167
124
  success: function(data, status) {
168
125
  if (this.autocompleteRequest === requestIndex) {
@@ -176,11 +133,149 @@
176
133
  }
177
134
  });
178
135
  };
136
+ } else {
137
+ return source;
138
+ }
139
+ },
179
140
 
141
+ _setOptionsSource: function() {
142
+ if (this.options.xhr) {
143
+ this.options.source = this.options.remote_source;
180
144
  } else {
145
+ this.options.source = this.element.children('option').map(function() {
146
+ return { label: $(this).text(), value: this.value };
147
+ }).toArray();
148
+ }
149
+ },
181
150
 
182
- return source;
151
+ _buttonField: function() {
152
+ return $(
153
+ '<span class="input-group-btn">' +
154
+ '<label class="btn btn-info dropdown-toggle" data-toggle="dropdown" aria-expanded="false" title="Show All Items" role="button">' +
155
+ '<span class="caret"></span>' +
156
+ '<span class="ui-button-text">&nbsp;</span>' +
157
+ '</label>' +
158
+ '</span>'
159
+ );
160
+ },
161
+
162
+ _autocompleteDropdownEvent: function(element) {
163
+ var self = this;
164
+
165
+ return element.click(function() {
166
+ // close if already visible
167
+ if (self.input.autocomplete('widget').is(':visible')) {
168
+ self.input.autocomplete('close');
169
+ return;
170
+ }
171
+
172
+ // pass empty string as value to search for, displaying all results
173
+ self.input.autocomplete('search', '');
174
+ self.input.focus();
175
+ });
176
+ },
177
+
178
+ _inputField: function() {
179
+ var input;
180
+ var selected = this.element.children(':selected');
181
+ var value = selected.val() ? selected.text() : '';
182
+
183
+ input = $('<input type="text">')
184
+ .val(value)
185
+ .addClass('form-control ra-filtering-select-input')
186
+ .attr('style', this.element.attr('style'))
187
+ .show();
188
+
189
+ if (this.element.attr('placeholder')) {
190
+ input.attr('placeholder', this.element.attr('placeholder'));
183
191
  }
192
+
193
+ return input;
194
+ },
195
+
196
+ _inputGroup: function(inputFor) {
197
+ return $('<div>')
198
+ .addClass('input-group filtering-select col-sm-2')
199
+ .attr('data-input-for', inputFor)
200
+ .css('float', 'left');
201
+ },
202
+
203
+ _initAutocomplete: function() {
204
+ var self = this;
205
+
206
+ return this.input.autocomplete({
207
+ delay: this.options.searchDelay,
208
+ minLength: this.options.minLength,
209
+ source: this._getSourceFunction(this.options.source),
210
+ select: function(event, ui) {
211
+ var option = $('<option>')
212
+ .attr('value', ui.item.id)
213
+ .attr('selected', 'selected')
214
+ .text(ui.item.value);
215
+ self.element.html(option)
216
+ .trigger('change', ui.item.id);
217
+ self._trigger('selected', event, {
218
+ item: option
219
+ });
220
+ $(self.element.parents('.controls')[0])
221
+ .find('.update')
222
+ .removeClass('disabled');
223
+ },
224
+ change: function(event, ui) {
225
+ if (ui.item) {
226
+ return;
227
+ }
228
+
229
+ var matcher = new RegExp('^' + $.ui.autocomplete.escapeRegex($(this).val()) + '$', 'i');
230
+ var valid = false;
231
+
232
+ self.element.children('option')
233
+ .each(function() {
234
+ if ($(this).text().match(matcher)) {
235
+ valid = true;
236
+ return false;
237
+ }
238
+ });
239
+
240
+ if (valid || $(this).val() !== '') {
241
+ return;
242
+ }
243
+
244
+ // remove invalid value, as it didn't match anything
245
+ $(this).val(null);
246
+ self.element.html($('<option value="" selected="selected"></option>'));
247
+ self.input.data('ui-autocomplete').term = '';
248
+ $(self.element.parents('.controls')[0])
249
+ .find('.update')
250
+ .addClass('disabled');
251
+ return false;
252
+ }
253
+ });
254
+ },
255
+
256
+ _initKeyEvent: function() {
257
+ var self = this;
258
+
259
+ return this.input.keyup(function() {
260
+ if ($(this).val().length) {
261
+ return;
262
+ }
263
+
264
+ /* Clear select options and trigger change if selected item is deleted */
265
+ return self.element
266
+ .html($('<option value="" selected="selected"></option>'))
267
+ .trigger('change');
268
+ });
269
+ },
270
+
271
+ _overloadRenderItem: function() {
272
+ this.input.data('ui-autocomplete')._renderItem = function(ul, item) {
273
+ return $('<li></li>')
274
+ .data('ui-autocomplete-item', item)
275
+ .append($('<a></a>')
276
+ .html(item.html || item.id))
277
+ .appendTo(ul);
278
+ };
184
279
  },
185
280
 
186
281
  destroy: function() {