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.
- checksums.yaml +4 -4
- data/Gemfile +1 -2
- data/README.md +1 -14
- data/app/assets/javascripts/rails_admin/ra.filtering-multiselect.js +15 -10
- data/app/assets/javascripts/rails_admin/ra.filtering-select.js +205 -110
- data/app/assets/javascripts/rails_admin/ra.remote-form.js +1 -4
- data/app/controllers/rails_admin/application_controller.rb +5 -5
- data/app/controllers/rails_admin/main_controller.rb +2 -2
- data/app/helpers/rails_admin/application_helper.rb +2 -2
- data/app/helpers/rails_admin/form_builder.rb +9 -2
- data/app/helpers/rails_admin/main_helper.rb +1 -1
- data/app/views/layouts/rails_admin/application.html.haml +1 -0
- data/app/views/rails_admin/main/_delete_notice.html.haml +14 -9
- data/app/views/rails_admin/main/index.html.haml +2 -2
- data/config/initializers/active_record_extensions.rb +2 -2
- data/config/locales/rails_admin.en.yml +1 -0
- data/lib/rails_admin/abstract_model.rb +6 -7
- data/lib/rails_admin/adapters/active_record.rb +30 -11
- data/lib/rails_admin/adapters/mongoid.rb +2 -2
- data/lib/rails_admin/adapters/mongoid/association.rb +2 -2
- data/lib/rails_admin/adapters/mongoid/extension.rb +1 -1
- data/lib/rails_admin/adapters/mongoid/property.rb +1 -1
- data/lib/rails_admin/bootstrap-sass.rb +1 -3
- data/lib/rails_admin/bootstrap-sass/compass_functions.rb +1 -1
- data/lib/rails_admin/config.rb +12 -8
- data/lib/rails_admin/config/actions.rb +1 -1
- data/lib/rails_admin/config/actions/base.rb +3 -4
- data/lib/rails_admin/config/actions/bulk_delete.rb +1 -3
- data/lib/rails_admin/config/actions/index.rb +3 -5
- data/lib/rails_admin/config/configurable.rb +4 -6
- data/lib/rails_admin/config/fields/association.rb +1 -1
- data/lib/rails_admin/config/fields/base.rb +15 -26
- data/lib/rails_admin/config/fields/factories/carrierwave.rb +1 -1
- data/lib/rails_admin/config/fields/types.rb +1 -1
- data/lib/rails_admin/config/fields/types/active_record_enum.rb +17 -2
- data/lib/rails_admin/config/fields/types/file_upload.rb +1 -1
- data/lib/rails_admin/config/fields/types/has_many_association.rb +1 -1
- data/lib/rails_admin/config/fields/types/polymorphic_association.rb +1 -1
- data/lib/rails_admin/config/fields/types/string.rb +6 -5
- data/lib/rails_admin/config/fields/types/text.rb +3 -3
- data/lib/rails_admin/config/hideable.rb +1 -1
- data/lib/rails_admin/config/inspectable.rb +39 -0
- data/lib/rails_admin/config/model.rb +4 -17
- data/lib/rails_admin/config/sections/base.rb +4 -17
- data/lib/rails_admin/engine.rb +3 -2
- data/lib/rails_admin/extension.rb +4 -4
- data/lib/rails_admin/extensions/paper_trail/auditing_adapter.rb +10 -2
- data/lib/rails_admin/extensions/pundit/authorization_adapter.rb +11 -1
- data/lib/rails_admin/support/datetime.rb +1 -1
- data/lib/rails_admin/version.rb +1 -1
- metadata +7 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b5f7c910bef240049b818e4189a241c41e68e180
|
4
|
+
data.tar.gz: ea59f46605ddef6defbe19c6846d3d9ee6419166
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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
|
-
|
178
|
+
|
179
179
|
var filtered = [];
|
180
|
-
|
181
|
-
|
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.
|
187
|
-
|
188
|
-
|
189
|
-
|
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.
|
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
|
-
|
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
|
-
|
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
|
31
|
-
select = this.element.hide(),
|
32
|
-
selected = select.children(":selected"),
|
33
|
-
value = selected.val() ? selected.text() : "";
|
36
|
+
var filtering_select;
|
34
37
|
|
35
|
-
|
36
|
-
|
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
|
-
|
39
|
-
|
40
|
-
|
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"> </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),
|
121
|
-
|
122
|
-
|
123
|
-
|
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
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
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
|
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:
|
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
|
-
|
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"> </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() {
|