admino 0.0.5 → 0.0.6
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +82 -52
- data/lib/admino/query/filter_group.rb +4 -4
- data/lib/admino/query/filter_group_presenter.rb +7 -3
- data/lib/admino/table/head_row.rb +24 -12
- data/lib/admino/table/presenter.rb +27 -11
- data/lib/admino/table/resource_row.rb +70 -56
- data/lib/admino/table/row.rb +4 -13
- data/lib/admino/version.rb +1 -1
- data/spec/admino/query/filter_group_presenter_spec.rb +9 -3
- data/spec/admino/query/filter_group_spec.rb +4 -4
- data/spec/admino/query/sorting_presenter_spec.rb +11 -7
- data/spec/admino/table/row_spec.rb +8 -8
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cb6f069c49996e9bf994e63b48c08fc778387606
|
4
|
+
data.tar.gz: 5a189da715fb212272cb14396cc1351ef3b6765b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 76abf92afbb96a5d7afcda73150b01aa7f12c6173dbfe1f3ff038f35827727baac685c41b7d6afdd5e7a9f63222671ff335d842840bf2bb7beb40387e49f60a2
|
7
|
+
data.tar.gz: 47cfae8cb1f1703424e58d7cbe0ba62353e7d9494fd6fbc1403101ce1dd3bc234443dff57b79979eba5fffe54c0f657bcd26a096db3492ffa9f5c12cc39b2211
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -47,7 +47,7 @@ class TasksQuery < Admino::Query::Base
|
|
47
47
|
end
|
48
48
|
```
|
49
49
|
|
50
|
-
Each query object gets initialized with a hash of params, and features a `#scope` method that returns the filtered/sorted result set. As you may have guessed, query objects can be great companions to index
|
50
|
+
Each query object gets initialized with a hash of params, and features a `#scope` method that returns the filtered/sorted result set. As you may have guessed, query objects can be great companions to index actions:
|
51
51
|
|
52
52
|
```ruby
|
53
53
|
class TasksController < ApplicationController
|
@@ -86,8 +86,7 @@ class TasksQuery < Admino::Query::Base
|
|
86
86
|
search_field :title_matches
|
87
87
|
end
|
88
88
|
```
|
89
|
-
The `#scope` method will check the presence of the `params[:query][:title_matches]` key. If it finds it, it will augment the query with a
|
90
|
-
named scope called `:title_matches`, expected to be found within the `Task` model, that needs to accept an argument.
|
89
|
+
The `#scope` method will check the presence of the `params[:query][:title_matches]` key. If it finds it, it will augment the query with a named scope called `:title_matches`, expected to be found within the `Task` model. The scope needs to accept an argument.
|
91
90
|
|
92
91
|
```ruby
|
93
92
|
class Task < ActiveRecord::Base
|
@@ -112,7 +111,7 @@ class TasksQuery < Admino::Query::Base
|
|
112
111
|
end
|
113
112
|
```
|
114
113
|
|
115
|
-
Just like a search field, with a declared filter group the `#scope` method will check the presence of a `params[:query][:status]` key. If it finds it (and its value corresponds to one of the declared scopes) it will augment the query the scope itself:
|
114
|
+
Just like a search field, with a declared filter group the `#scope` method will check the presence of a `params[:query][:status]` key. If it finds it (and its value corresponds to one of the declared scopes) it will augment the query with the scope itself:
|
116
115
|
|
117
116
|
```ruby
|
118
117
|
class Task < ActiveRecord::Base
|
@@ -250,32 +249,21 @@ The great thing is that:
|
|
250
249
|
|
251
250
|
The presenter also offers a `#simple_form` method to make it work with [Simple Form](https://github.com/plataformatec/simple_form) out of the box.
|
252
251
|
|
253
|
-
###
|
252
|
+
### Output customization
|
254
253
|
|
255
|
-
|
254
|
+
The `#scope_link` methods are very flexible, allowing you to change almost every aspect of the generated links:
|
256
255
|
|
257
|
-
```
|
258
|
-
|
259
|
-
query:
|
260
|
-
attributes:
|
261
|
-
tasks_query:
|
262
|
-
title_matches: 'Title contains'
|
263
|
-
filter_groups:
|
264
|
-
tasks_query:
|
265
|
-
status:
|
266
|
-
name: 'Filter by status'
|
267
|
-
scopes:
|
268
|
-
completed: 'Completed'
|
269
|
-
pending: 'Pending'
|
270
|
-
sorting_scopes:
|
271
|
-
task_query:
|
272
|
-
by_due_date: 'By due date'
|
273
|
-
by_title: 'By title'
|
274
|
-
```
|
256
|
+
```erb
|
257
|
+
<% status_filter = query.filter_group_by_name(:status) %>
|
275
258
|
|
276
|
-
|
259
|
+
<%= status_filter.scope_link :completed,
|
260
|
+
'Custom title',
|
261
|
+
active_class: 'active',
|
262
|
+
class: 'custom-class'
|
263
|
+
%>
|
264
|
+
```
|
277
265
|
|
278
|
-
|
266
|
+
Please refer to the tests for the details.
|
279
267
|
|
280
268
|
### Overwriting the starting scope
|
281
269
|
|
@@ -290,16 +278,26 @@ end
|
|
290
278
|
|
291
279
|
### Coertions
|
292
280
|
|
293
|
-
|
281
|
+
Suppose the presence of a model scope that requires a non-textual argument (ie. a date):
|
282
|
+
|
283
|
+
```ruby
|
284
|
+
class Task < ActiveRecord::Base
|
285
|
+
scope :due_date_from, ->(date) { where('due_date >= ?', date) }
|
286
|
+
end
|
287
|
+
```
|
288
|
+
|
289
|
+
Admino can perform some automatic coertions to the textual parameter it gets, and pass the coerced value to the scope:
|
294
290
|
|
295
291
|
```ruby
|
296
292
|
class TasksQuery < Admino::Query::Base
|
297
|
-
|
298
|
-
field :due_date_from, coerce: :to_date
|
299
|
-
field :due_date_to, coerce: :to_date
|
293
|
+
search_field :due_date_from, coerce: :to_date
|
300
294
|
end
|
295
|
+
|
296
|
+
query = TaskQuery.new(query: { due_date_from: '2014-03-01' })
|
297
|
+
query.search_field_by_name(:due_date_from).value # => #<Date Sat, 01 Mar 2014>
|
301
298
|
```
|
302
|
-
|
299
|
+
|
300
|
+
If a specific coercion cannot be performed with the provided input, the scope won't be chained. The following coertions are available:
|
303
301
|
|
304
302
|
* `:to_boolean`
|
305
303
|
* `:to_constant`
|
@@ -311,13 +309,11 @@ The following coertions are available:
|
|
311
309
|
* `:to_symbol`
|
312
310
|
* `:to_time`
|
313
311
|
|
314
|
-
If a specific coercion cannot be performed with the provided input, the scope won't be chained.
|
315
|
-
|
316
312
|
Please see the [`Coercible::Coercer::String`](https://github.com/solnic/coercible/blob/master/lib/coercible/coercer/string.rb) class for details.
|
317
313
|
|
318
314
|
### Default sorting
|
319
315
|
|
320
|
-
If you need to setup a default sorting, you can pass some optional arguments to
|
316
|
+
If you need to setup a default sorting, you can pass some optional arguments to the `sorting` declaration:
|
321
317
|
|
322
318
|
```ruby
|
323
319
|
class TasksQuery < Admino::Query::Base
|
@@ -328,6 +324,29 @@ class TasksQuery < Admino::Query::Base
|
|
328
324
|
end
|
329
325
|
```
|
330
326
|
|
327
|
+
### I18n
|
328
|
+
|
329
|
+
To localize the search form labels, as well as the group filter names and scope links, please refer to the following YAML file:
|
330
|
+
|
331
|
+
```yaml
|
332
|
+
en:
|
333
|
+
query:
|
334
|
+
attributes:
|
335
|
+
tasks_query:
|
336
|
+
title_matches: 'Title contains'
|
337
|
+
filter_groups:
|
338
|
+
tasks_query:
|
339
|
+
status:
|
340
|
+
name: 'Filter by status'
|
341
|
+
scopes:
|
342
|
+
completed: 'Completed'
|
343
|
+
pending: 'Pending'
|
344
|
+
sorting_scopes:
|
345
|
+
task_query:
|
346
|
+
by_due_date: 'By due date'
|
347
|
+
by_title: 'By title'
|
348
|
+
```
|
349
|
+
|
331
350
|
## Admino::Table::Presenter
|
332
351
|
|
333
352
|
Admino offers a [Showcase collection presenter](https://github.com/stefanoverna/showcase) that makes it really easy to generate HTML tables from a set of records:
|
@@ -348,14 +367,14 @@ Admino offers a [Showcase collection presenter](https://github.com/stefanoverna/
|
|
348
367
|
<tr>
|
349
368
|
<th role='title'>Title</th>
|
350
369
|
<th role='completed'>Completed</th>
|
351
|
-
<th role='
|
370
|
+
<th role='due-date'>Due date</th>
|
352
371
|
</tr>
|
353
372
|
<thead>
|
354
373
|
<tbody>
|
355
374
|
<tr id='task_1' class='is-even'>
|
356
375
|
<td role='title'>Call mum ASAP</td>
|
357
376
|
<td role='completed'>✓</td>
|
358
|
-
<td role='
|
377
|
+
<td role='due-date'>2013-02-04</td>
|
359
378
|
</tr>
|
360
379
|
<tr id='task_2' class='is-odd'>
|
361
380
|
<!-- ... -->
|
@@ -366,7 +385,7 @@ Admino offers a [Showcase collection presenter](https://github.com/stefanoverna/
|
|
366
385
|
|
367
386
|
### Record actions
|
368
387
|
|
369
|
-
Often
|
388
|
+
Often tables need to offer some kind of action associated with the records. The presenter implements the following DSL to support that:
|
370
389
|
|
371
390
|
```erb
|
372
391
|
<%= Admino::Table::Presenter.new(@tasks, Task, self).to_html do |row, record| %>
|
@@ -402,7 +421,15 @@ Often table rows needs to offer some kind of action associated with the record.
|
|
402
421
|
|
403
422
|
### Sortable columns
|
404
423
|
|
405
|
-
|
424
|
+
If you want to make the table headers sortable, then please create an Admino query object class to define the available sorting scopes.
|
425
|
+
|
426
|
+
```ruby
|
427
|
+
class TaskQuery < Admino::Query::Base
|
428
|
+
sorting :by_title, :by_due_date
|
429
|
+
end
|
430
|
+
```
|
431
|
+
|
432
|
+
You can then pass the query object as a parameter to the table presenter initializer, and associate table columns to specific sorting scopes of the query object using the `sorting` directive:
|
406
433
|
|
407
434
|
```erb
|
408
435
|
<% query = present(@query) %>
|
@@ -420,10 +447,10 @@ This generates links that allow the visitor to sort the result set in ascending
|
|
420
447
|
<thead>
|
421
448
|
<tr>
|
422
449
|
<th role='title'>
|
423
|
-
<a href=
|
450
|
+
<a href='/admin/tasks?sorting=by_title&sort_order=desc' class='is-asc'>Title</a>
|
424
451
|
</th>
|
425
|
-
<th role='
|
426
|
-
<a href=
|
452
|
+
<th role='due-date'>
|
453
|
+
<a href='/admin/tasks?sorting=by_due_date&sort_order=asc'>Due date</a>
|
427
454
|
</th>
|
428
455
|
</tr>
|
429
456
|
<thead>
|
@@ -433,7 +460,7 @@ This generates links that allow the visitor to sort the result set in ascending
|
|
433
460
|
|
434
461
|
### Customizing the output
|
435
462
|
|
436
|
-
The `#column` and `#action` methods are very flexible, allowing
|
463
|
+
The `#column` and `#action` methods are very flexible, allowing you to change almost every aspect of the generated table cells:
|
437
464
|
|
438
465
|
```erb
|
439
466
|
<%= Admino::Table::Presenter.new(@tasks, Task, self).to_html(class: 'table-class') do |row, record| %>
|
@@ -447,7 +474,7 @@ The `#column` and `#action` methods are very flexible, allowing youto change alm
|
|
447
474
|
<% end %>
|
448
475
|
```
|
449
476
|
|
450
|
-
If you need more power, you can also
|
477
|
+
If you need more power, you can also subclass `Admino::Table::Presenter`. For each HTML element, there's a set of methods you can override to customize it's appeareance.
|
451
478
|
Table cells are generated through two collaborator classes: `Admino::Table::HeadRow` and `Admino::Table::ResourceRow`. You can easily replace them with a subclass if you want. To grasp the idea here's an example:
|
452
479
|
|
453
480
|
```ruby
|
@@ -500,17 +527,11 @@ end
|
|
500
527
|
|
501
528
|
Please refer to the tests for all the details.
|
502
529
|
|
503
|
-
### Inherited resources
|
530
|
+
### Inherited resources (and similar)
|
504
531
|
|
505
|
-
If
|
532
|
+
If your controller actions are generated through [Inherited Resources](https://github.com/josevalim/inherited_resources), then you can always get the URL pointing to the show action with the `resource_path` helper method. Similar helpers [are available for the other REST actions too](https://github.com/josevalim/inherited_resources#url-helpers) (new, edit, destroy).
|
506
533
|
|
507
|
-
|
508
|
-
<%= CustomTablePresenter.new(@tasks, Task, self).to_html do |row, record| %>
|
509
|
-
<%# ... %>
|
510
|
-
<%= row.actions :show, :edit, :destroy %>
|
511
|
-
<% end %>
|
512
|
-
```
|
513
|
-
For instance, using [Inherited Resources](https://github.com/josevalim/inherited_resources) to generate controller actions, you can use its [helper methods](https://github.com/josevalim/inherited_resources#url-helpers) to build a custom subclass of `Admino::Table::Presenter`:
|
534
|
+
More in general, if you are able to programmatically generate/obtain the URLs of your row actions, you can subclass `Admino::Table::Presenter` and declare them:
|
514
535
|
|
515
536
|
```ruby
|
516
537
|
class CustomTablePresenter < Admino::Table::Presenter
|
@@ -540,6 +561,15 @@ class CustomTablePresenter < Admino::Table::Presenter
|
|
540
561
|
end
|
541
562
|
```
|
542
563
|
|
564
|
+
This will enable you to generate row actions even faster, simply declaring them as arguments to the `#actions` DSL method:
|
565
|
+
|
566
|
+
```erb
|
567
|
+
<%= CustomTablePresenter.new(@tasks, Task, self).to_html do |row, record| %>
|
568
|
+
<%# ... %>
|
569
|
+
<%= row.actions :show, :edit, :destroy %>
|
570
|
+
<% end %>
|
571
|
+
```
|
572
|
+
|
543
573
|
### I18n
|
544
574
|
|
545
575
|
Column titles are generated using the model [`#human_attribute_name`](http://apidock.com/rails/ActiveRecord/Base/human_attribute_name/class) method, so if you already translated the model attribute names, you're good to go. To translate actions, please refer to the following YAML file:
|
@@ -23,8 +23,8 @@ module Admino
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def active_scope
|
26
|
-
if
|
27
|
-
|
26
|
+
if value && scopes.include?(value.to_sym)
|
27
|
+
value.to_sym
|
28
28
|
else
|
29
29
|
nil
|
30
30
|
end
|
@@ -34,8 +34,8 @@ module Admino
|
|
34
34
|
active_scope == scope
|
35
35
|
end
|
36
36
|
|
37
|
-
def
|
38
|
-
params.fetch(param_name, nil)
|
37
|
+
def value
|
38
|
+
params.fetch(:query, {}).fetch(param_name, nil)
|
39
39
|
end
|
40
40
|
|
41
41
|
def param_name
|
@@ -28,12 +28,16 @@ module Admino
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def scope_params(scope)
|
31
|
-
params = ActiveSupport::HashWithIndifferentAccess.new(
|
31
|
+
params = ActiveSupport::HashWithIndifferentAccess.new(
|
32
|
+
h.request.query_parameters
|
33
|
+
)
|
34
|
+
|
35
|
+
params[:query] ||= {}
|
32
36
|
|
33
37
|
if is_scope_active?(scope)
|
34
|
-
params.delete(param_name)
|
38
|
+
params[:query].delete(param_name)
|
35
39
|
else
|
36
|
-
params.merge!(param_name => scope.to_s)
|
40
|
+
params[:query].merge!(param_name => scope.to_s)
|
37
41
|
end
|
38
42
|
|
39
43
|
params
|
@@ -30,23 +30,18 @@ module Admino
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def column(*args, &block)
|
33
|
-
|
33
|
+
attribute_name, label, html_options = parse_column_args(args)
|
34
34
|
|
35
|
-
|
36
|
-
label = params[:label]
|
37
|
-
options = params[:html_options]
|
35
|
+
label ||= column_label(attribute_name)
|
38
36
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
default_options = column_html_options(attribute_name)
|
44
|
-
html_options = Showcase::Helpers::HtmlOptions.new(default_options)
|
45
|
-
html_options.merge_attrs!(options)
|
46
|
-
html_options = html_options.to_h
|
37
|
+
html_options = complete_column_html_options(
|
38
|
+
attribute_name,
|
39
|
+
html_options
|
40
|
+
)
|
47
41
|
|
48
42
|
sorting_scope = html_options.delete(:sorting)
|
49
43
|
sorting_html_options = html_options.delete(:sorting_html_options) { {} }
|
44
|
+
|
50
45
|
if sorting_scope
|
51
46
|
raise ArgumentError, 'query object is required' unless query
|
52
47
|
label = query.sorting.scope_link(sorting_scope, label, sorting_html_options)
|
@@ -61,6 +56,23 @@ module Admino
|
|
61
56
|
|
62
57
|
private
|
63
58
|
|
59
|
+
def column_label(attribute_name)
|
60
|
+
if attribute_name
|
61
|
+
resource_klass.human_attribute_name(attribute_name.to_s)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def complete_column_html_options(attribute_name, final_html_options)
|
66
|
+
if attribute_name.nil?
|
67
|
+
return final_html_options
|
68
|
+
end
|
69
|
+
|
70
|
+
default_options = column_html_options(attribute_name)
|
71
|
+
html_options = Showcase::Helpers::HtmlOptions.new(default_options)
|
72
|
+
html_options.merge_attrs!(final_html_options)
|
73
|
+
html_options = html_options.to_h
|
74
|
+
end
|
75
|
+
|
64
76
|
def column_html_options(attribute_name)
|
65
77
|
{ role: attribute_name.to_s.gsub(/_/, '-') }
|
66
78
|
end
|
@@ -43,26 +43,42 @@ module Admino
|
|
43
43
|
table_tag(options) do
|
44
44
|
thead_tag do
|
45
45
|
thead_tr_tag do
|
46
|
-
|
47
|
-
h.capture(row, nil, &block) if block_given?
|
48
|
-
row.to_html
|
46
|
+
th_tags(&block)
|
49
47
|
end
|
50
48
|
end <<
|
51
49
|
tbody_tag do
|
52
|
-
|
53
|
-
html_options = base_tbody_tr_html_options(resource, index)
|
54
|
-
tbody_tr_tag(resource, index, html_options) do
|
55
|
-
row = resource_row(resource, view_context)
|
56
|
-
h.capture(row, resource, &block) if block_given?
|
57
|
-
row.to_html
|
58
|
-
end
|
59
|
-
end.join.html_safe
|
50
|
+
tbody_tr_tags(&block)
|
60
51
|
end
|
61
52
|
end
|
62
53
|
end
|
63
54
|
|
64
55
|
private
|
65
56
|
|
57
|
+
def tbody_tr_tags(&block)
|
58
|
+
collection.each_with_index.map do |resource, index|
|
59
|
+
html_options = base_tbody_tr_html_options(resource, index)
|
60
|
+
tbody_tr_tag(resource, index, html_options) do
|
61
|
+
td_tags(resource, &block)
|
62
|
+
end
|
63
|
+
end.join.html_safe
|
64
|
+
end
|
65
|
+
|
66
|
+
def th_tags(&block)
|
67
|
+
row = head_row(collection_klass, query, view_context)
|
68
|
+
if block_given?
|
69
|
+
h.capture(row, nil, &block)
|
70
|
+
end
|
71
|
+
row.to_html
|
72
|
+
end
|
73
|
+
|
74
|
+
def td_tags(resource, &block)
|
75
|
+
row = resource_row(resource, view_context)
|
76
|
+
if block_given?
|
77
|
+
h.capture(row, resource, &block)
|
78
|
+
end
|
79
|
+
row.to_html
|
80
|
+
end
|
81
|
+
|
66
82
|
def collection
|
67
83
|
object
|
68
84
|
end
|
@@ -15,11 +15,12 @@ module Admino
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def column(*args, &block)
|
18
|
-
|
18
|
+
attribute_name, label, html_options = parse_column_args(args)
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
html_options = complete_column_html_options(
|
21
|
+
attribute_name,
|
22
|
+
html_options
|
23
|
+
)
|
23
24
|
|
24
25
|
if block_given?
|
25
26
|
content = h.capture(resource, &block)
|
@@ -29,11 +30,7 @@ module Admino
|
|
29
30
|
raise ArgumentError, 'attribute name or block required'
|
30
31
|
end
|
31
32
|
|
32
|
-
|
33
|
-
html_options = Showcase::Helpers::HtmlOptions.new(default_options)
|
34
|
-
html_options.merge_attrs!(options)
|
35
|
-
|
36
|
-
@columns << h.content_tag(:td, content, html_options.to_h)
|
33
|
+
@columns << h.content_tag(:td, content, html_options)
|
37
34
|
end
|
38
35
|
|
39
36
|
def actions(*actions, &block)
|
@@ -47,76 +44,93 @@ module Admino
|
|
47
44
|
end
|
48
45
|
|
49
46
|
def action(*args, &block)
|
50
|
-
params = parse_action_args(args)
|
51
|
-
|
52
|
-
action_name = params[:action_name]
|
53
|
-
label = params[:label]
|
54
|
-
url = params[:url]
|
55
|
-
options = params[:html_options]
|
56
|
-
|
57
47
|
if block_given?
|
58
48
|
@actions << h.capture(resource, &block)
|
59
|
-
|
60
|
-
|
49
|
+
else
|
50
|
+
action_name, url, label, html_options = parse_action_args(args)
|
61
51
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
52
|
+
label ||= action_label(action_name)
|
53
|
+
url ||= action_url(action_name)
|
54
|
+
html_options = complete_action_html_options(
|
55
|
+
action_name,
|
56
|
+
html_options
|
57
|
+
)
|
58
|
+
|
59
|
+
@actions << h.link_to(label, url, html_options)
|
60
|
+
end
|
61
|
+
end
|
66
62
|
|
67
|
-
|
63
|
+
def to_html
|
64
|
+
buffer = @columns
|
68
65
|
|
69
|
-
|
70
|
-
|
71
|
-
|
66
|
+
if @actions.any?
|
67
|
+
html_options = column_html_options(:actions)
|
68
|
+
buffer << h.content_tag(:td, html_options) do
|
69
|
+
@actions.join(" ").html_safe
|
72
70
|
end
|
73
|
-
|
74
|
-
url = send(action_url_method)
|
75
71
|
end
|
76
72
|
|
77
|
-
|
78
|
-
|
79
|
-
end
|
80
|
-
|
81
|
-
html_options = Showcase::Helpers::HtmlOptions.new(base_options)
|
73
|
+
buffer.html_safe
|
74
|
+
end
|
82
75
|
|
83
|
-
|
76
|
+
private
|
84
77
|
|
85
|
-
|
86
|
-
|
87
|
-
|
78
|
+
def action_url(action_name)
|
79
|
+
if action_name.nil?
|
80
|
+
raise ArgumentError,
|
81
|
+
'no URL provided, action name required'
|
88
82
|
end
|
89
83
|
|
90
|
-
|
84
|
+
action_url_method = "#{action_name}_action_url"
|
91
85
|
|
92
|
-
if
|
93
|
-
|
94
|
-
|
95
|
-
scope: 'table.actions',
|
96
|
-
default: [
|
97
|
-
:"#{action_name}",
|
98
|
-
action_name.to_s.titleize
|
99
|
-
]
|
100
|
-
)
|
86
|
+
if !respond_to?(action_url_method, true)
|
87
|
+
raise ArgumentError,
|
88
|
+
"no URL provided, ##{action_url_method} method required"
|
101
89
|
end
|
102
90
|
|
103
|
-
|
91
|
+
url = send(action_url_method)
|
104
92
|
end
|
105
93
|
|
106
|
-
def
|
107
|
-
|
94
|
+
def complete_action_html_options(action_name, final_html_options)
|
95
|
+
if action_name
|
96
|
+
default_options = column_html_options(action_name)
|
97
|
+
html_options = Showcase::Helpers::HtmlOptions.new(default_options)
|
108
98
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
@actions.join(" ").html_safe
|
99
|
+
action_html_options_method = "#{action_name}_action_html_options"
|
100
|
+
if respond_to?(action_html_options_method, true)
|
101
|
+
html_options.merge_attrs!(send(action_html_options_method))
|
113
102
|
end
|
103
|
+
|
104
|
+
html_options.merge_attrs!(final_html_options)
|
105
|
+
html_options.to_h
|
106
|
+
else
|
107
|
+
final_html_options
|
114
108
|
end
|
109
|
+
end
|
115
110
|
|
116
|
-
|
111
|
+
def complete_column_html_options(attribute_name, final_html_options)
|
112
|
+
if attribute_name
|
113
|
+
default_options = column_html_options(attribute_name)
|
114
|
+
html_options = Showcase::Helpers::HtmlOptions.new(default_options)
|
115
|
+
html_options.merge_attrs!(final_html_options)
|
116
|
+
html_options.to_h
|
117
|
+
else
|
118
|
+
final_html_options
|
119
|
+
end
|
117
120
|
end
|
118
121
|
|
119
|
-
|
122
|
+
def action_label(action_name)
|
123
|
+
return nil unless action_name
|
124
|
+
|
125
|
+
I18n.t(
|
126
|
+
:"#{resource.class.model_name.i18n_key}.#{action_name}",
|
127
|
+
scope: 'table.actions',
|
128
|
+
default: [
|
129
|
+
:"#{action_name}",
|
130
|
+
action_name.to_s.titleize
|
131
|
+
]
|
132
|
+
)
|
133
|
+
end
|
120
134
|
|
121
135
|
def action_html_options(action_name)
|
122
136
|
{ role: action_name.to_s.gsub(/_/, '-') }
|
data/lib/admino/table/row.rb
CHANGED
@@ -10,7 +10,7 @@ module Admino
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def parse_column_args(args)
|
13
|
-
|
13
|
+
html_options = args.extract_options!
|
14
14
|
|
15
15
|
attribute_name = if args.first.is_a?(Symbol)
|
16
16
|
args.shift
|
@@ -24,15 +24,11 @@ module Admino
|
|
24
24
|
nil
|
25
25
|
end
|
26
26
|
|
27
|
-
|
28
|
-
attribute_name: attribute_name,
|
29
|
-
label: label,
|
30
|
-
html_options: options
|
31
|
-
}
|
27
|
+
[attribute_name, label, html_options]
|
32
28
|
end
|
33
29
|
|
34
30
|
def parse_action_args(args)
|
35
|
-
|
31
|
+
html_options = args.extract_options!
|
36
32
|
|
37
33
|
action_name = if args.first.is_a?(Symbol)
|
38
34
|
args.shift
|
@@ -48,12 +44,7 @@ module Admino
|
|
48
44
|
|
49
45
|
label = args.shift
|
50
46
|
|
51
|
-
|
52
|
-
action_name: action_name,
|
53
|
-
url: url,
|
54
|
-
label: label,
|
55
|
-
html_options: options
|
56
|
-
}
|
47
|
+
[action_name, url, label, html_options]
|
57
48
|
end
|
58
49
|
|
59
50
|
def to_html
|
data/lib/admino/version.rb
CHANGED
@@ -16,7 +16,7 @@ module Admino
|
|
16
16
|
let(:request_object) do
|
17
17
|
double(
|
18
18
|
'ActionDispatch::Request',
|
19
|
-
query_parameters: { 'filter_group' => 'bar' },
|
19
|
+
query_parameters: { 'query' => { 'field' => 'value', 'filter_group' => 'bar' } },
|
20
20
|
path: '/'
|
21
21
|
)
|
22
22
|
end
|
@@ -86,6 +86,8 @@ module Admino
|
|
86
86
|
end
|
87
87
|
|
88
88
|
describe '#scope_params' do
|
89
|
+
let(:scope_active) { false }
|
90
|
+
|
89
91
|
before do
|
90
92
|
filter_group.stub(:is_scope_active?).with(:foo).and_return(scope_active)
|
91
93
|
end
|
@@ -94,7 +96,7 @@ module Admino
|
|
94
96
|
let(:scope_active) { true }
|
95
97
|
|
96
98
|
it 'deletes the filter_group param' do
|
97
|
-
expect(presenter.scope_params(:foo)).not_to have_key 'filter_group'
|
99
|
+
expect(presenter.scope_params(:foo)[:query]).not_to have_key 'filter_group'
|
98
100
|
end
|
99
101
|
end
|
100
102
|
|
@@ -102,9 +104,13 @@ module Admino
|
|
102
104
|
let(:scope_active) { false }
|
103
105
|
|
104
106
|
it 'is set as filter group value' do
|
105
|
-
expect(presenter.scope_params(:foo)[:filter_group]).to eq 'foo'
|
107
|
+
expect(presenter.scope_params(:foo)[:query][:filter_group]).to eq 'foo'
|
106
108
|
end
|
107
109
|
end
|
110
|
+
|
111
|
+
it 'preserves the other params' do
|
112
|
+
expect(presenter.scope_params(:foo)[:query][:field]).to eq 'value'
|
113
|
+
end
|
108
114
|
end
|
109
115
|
|
110
116
|
describe '#name' do
|
@@ -17,7 +17,7 @@ module Admino
|
|
17
17
|
end
|
18
18
|
|
19
19
|
context 'with an invalid value' do
|
20
|
-
let(:params) { { 'foo' => 'qux' } }
|
20
|
+
let(:params) { { 'query' => { 'foo' => 'qux' } } }
|
21
21
|
|
22
22
|
it 'returns nil' do
|
23
23
|
expect(filter_group.active_scope).to be_nil
|
@@ -25,7 +25,7 @@ module Admino
|
|
25
25
|
end
|
26
26
|
|
27
27
|
context 'with a valid value' do
|
28
|
-
let(:params) { { 'foo' => 'bar' } }
|
28
|
+
let(:params) { { 'query' => { 'foo' => 'bar' } } }
|
29
29
|
|
30
30
|
it 'returns the scope name' do
|
31
31
|
expect(filter_group.active_scope).to eq :bar
|
@@ -38,7 +38,7 @@ module Admino
|
|
38
38
|
let(:scope) { ScopeMock.new('original') }
|
39
39
|
|
40
40
|
context 'if the search_field has a value' do
|
41
|
-
let(:params) { { 'foo' => 'bar' } }
|
41
|
+
let(:params) { { 'query' => { 'foo' => 'bar' } } }
|
42
42
|
|
43
43
|
it 'returns the original scope chained with the filter_group scope' do
|
44
44
|
expect(result.chain).to eq [:bar, []]
|
@@ -53,7 +53,7 @@ module Admino
|
|
53
53
|
end
|
54
54
|
|
55
55
|
describe '#is_scope_active?' do
|
56
|
-
let(:params) { { 'foo' => 'bar' } }
|
56
|
+
let(:params) { { 'query' => { 'foo' => 'bar' } } }
|
57
57
|
|
58
58
|
it 'returns true if the provided scope is the one currently active' do
|
59
59
|
expect(filter_group.is_scope_active?(:bar)).to be_true
|
@@ -15,7 +15,7 @@ module Admino
|
|
15
15
|
let(:request_object) do
|
16
16
|
double(
|
17
17
|
'ActionDispatch::Request',
|
18
|
-
query_parameters: { 'sorting' => 'by_date' },
|
18
|
+
query_parameters: { 'sorting' => 'by_date', 'other' => 'value' },
|
19
19
|
path: '/'
|
20
20
|
)
|
21
21
|
end
|
@@ -103,8 +103,12 @@ module Admino
|
|
103
103
|
sorting.stub(:is_scope_active?).with(:by_title).and_return(false)
|
104
104
|
end
|
105
105
|
|
106
|
+
it 'preserves other params' do
|
107
|
+
expect(subject[:other]).to eq 'value'
|
108
|
+
end
|
109
|
+
|
106
110
|
it 'sets the sorting param as the scope' do
|
107
|
-
subject[:sorting]
|
111
|
+
expect(subject[:sorting]).to eq 'by_title'
|
108
112
|
end
|
109
113
|
|
110
114
|
context 'scope is active' do
|
@@ -118,7 +122,7 @@ module Admino
|
|
118
122
|
end
|
119
123
|
|
120
124
|
it 'sets the sorting order to descending' do
|
121
|
-
subject[:sort_order]
|
125
|
+
expect(subject[:sort_order]).to eq 'desc'
|
122
126
|
end
|
123
127
|
end
|
124
128
|
|
@@ -128,7 +132,7 @@ module Admino
|
|
128
132
|
end
|
129
133
|
|
130
134
|
it 'sets the sorting order to ascending' do
|
131
|
-
subject[:sort_order]
|
135
|
+
expect(subject[:sort_order]).to eq 'asc'
|
132
136
|
end
|
133
137
|
end
|
134
138
|
end
|
@@ -142,7 +146,7 @@ module Admino
|
|
142
146
|
end
|
143
147
|
|
144
148
|
it 'sets the sorting order to ascending' do
|
145
|
-
subject[:sort_order]
|
149
|
+
expect(subject[:sort_order]).to eq 'asc'
|
146
150
|
end
|
147
151
|
end
|
148
152
|
|
@@ -152,7 +156,7 @@ module Admino
|
|
152
156
|
end
|
153
157
|
|
154
158
|
it 'sets the sorting order to descending' do
|
155
|
-
subject[:sort_order]
|
159
|
+
expect(subject[:sort_order]).to eq 'desc'
|
156
160
|
end
|
157
161
|
end
|
158
162
|
end
|
@@ -163,7 +167,7 @@ module Admino
|
|
163
167
|
end
|
164
168
|
|
165
169
|
it 'sets the sorting order to ascending' do
|
166
|
-
subject[:sort_order]
|
170
|
+
expect(subject[:sort_order]).to eq 'asc'
|
167
171
|
end
|
168
172
|
end
|
169
173
|
end
|
@@ -21,22 +21,22 @@ module Admino
|
|
21
21
|
|
22
22
|
context 'with a symbol param' do
|
23
23
|
let(:arguments) { [:title] }
|
24
|
-
it { should eq
|
24
|
+
it { should eq [:title, nil, {}] }
|
25
25
|
end
|
26
26
|
|
27
27
|
context 'with a string param' do
|
28
28
|
let(:arguments) { ['Title'] }
|
29
|
-
it { should eq
|
29
|
+
it { should eq [nil, 'Title', {}] }
|
30
30
|
end
|
31
31
|
|
32
32
|
context 'with a string and a symbol param' do
|
33
33
|
let(:arguments) { [:title, 'Title'] }
|
34
|
-
it { should eq
|
34
|
+
it { should eq [:title, 'Title', {}] }
|
35
35
|
end
|
36
36
|
|
37
37
|
context 'with options' do
|
38
38
|
let(:arguments) { [{ foo: 'bar' }] }
|
39
|
-
it { should eq
|
39
|
+
it { should eq [nil, nil, { foo: 'bar' }] }
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
@@ -47,22 +47,22 @@ module Admino
|
|
47
47
|
|
48
48
|
context 'with a symbol param' do
|
49
49
|
let(:arguments) { [:show] }
|
50
|
-
it { should eq
|
50
|
+
it { should eq [:show, nil, nil, {}] }
|
51
51
|
end
|
52
52
|
|
53
53
|
context 'with a one string param' do
|
54
54
|
let(:arguments) { ['/'] }
|
55
|
-
it { should eq
|
55
|
+
it { should eq [nil, '/', nil, {}] }
|
56
56
|
end
|
57
57
|
|
58
58
|
context 'with a two string params' do
|
59
59
|
let(:arguments) { ['/', 'Details'] }
|
60
|
-
it { should eq
|
60
|
+
it { should eq [nil, '/', 'Details', {}] }
|
61
61
|
end
|
62
62
|
|
63
63
|
context 'with options' do
|
64
64
|
let(:arguments) { [{ foo: 'bar' }] }
|
65
|
-
it { should eq
|
65
|
+
it { should eq [nil, nil, nil, { foo: 'bar' }] }
|
66
66
|
end
|
67
67
|
end
|
68
68
|
end
|