admino 0.0.10 → 0.0.11
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/README.md +26 -1
- data/lib/admino/query/configuration.rb +24 -5
- data/lib/admino/query/filter_group.rb +18 -4
- data/lib/admino/query/search_field.rb +9 -8
- data/lib/admino/version.rb +1 -1
- data/spec/admino/query/base_spec.rb +10 -2
- data/spec/admino/query/filter_group_spec.rb +38 -7
- data/spec/admino/query/search_field_spec.rb +10 -0
- data/spec/spec_helper.rb +4 -2
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b0d55f8a3f155b631729a250ce1ff8eafdf443aa
|
4
|
+
data.tar.gz: f02070346455841d8466fdb67cd3f40d65ffe96c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bf0d27b8b835de7f2e10fe16cadbc3301e9771f76a40ccee7ef4e4234259210a0d8589cdac9fa1783edc964cbe0d14aab6d30bb34a746b657bb3f9f3c7d84115
|
7
|
+
data.tar.gz: 85b3cab3ac2fd27d265ac11d547ae85383e273d66f59879d23e89e09c8fc66d068d99e36dea1d20601eafc44ad487666988d9f8eca6cbc12917bd867d4179d8f
|
data/README.md
CHANGED
@@ -26,6 +26,10 @@ If a particular controller or view needs something different from the standard C
|
|
26
26
|
|
27
27
|
So what about Admino? Well, it complements the above-mentioned gems, giving you the the missing ~10%: a fast way to generate administrative index views.
|
28
28
|
|
29
|
+
## Demo
|
30
|
+
|
31
|
+
To better illustrate how to create a 100%-custom, super-DRY administrative interface using Admino and the aforementioned gems, we prepared a [repo with a sample Rails project](https://github.com/cantierecreativo/admino-example) you can take a look. The app is browsable at [http://admino-example.herokuapp.com](http://admino-example.herokuapp.com), and features a Bootstrap 3 theme.
|
32
|
+
|
29
33
|
## Installation
|
30
34
|
|
31
35
|
Add this line to your application's Gemfile:
|
@@ -86,6 +90,7 @@ class TasksQuery < Admino::Query::Base
|
|
86
90
|
search_field :title_matches
|
87
91
|
end
|
88
92
|
```
|
93
|
+
|
89
94
|
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.
|
90
95
|
|
91
96
|
```ruby
|
@@ -102,6 +107,15 @@ TaskQuery.new.scope.count # => 2
|
|
102
107
|
TaskQuery.new(query: { title_matches: 'ASAP' }).scope.count # => 1
|
103
108
|
```
|
104
109
|
|
110
|
+
You can provide a default value with the `default` option:
|
111
|
+
|
112
|
+
```ruby
|
113
|
+
class TasksQuery < Admino::Query::Base
|
114
|
+
# ...
|
115
|
+
search_field :title_matches, default: 'TODO'
|
116
|
+
end
|
117
|
+
```
|
118
|
+
|
105
119
|
#### `filter_by`
|
106
120
|
|
107
121
|
```ruby
|
@@ -129,6 +143,17 @@ TaskQuery.new(query: { status: 'pending' }).scope.count # => 1
|
|
129
143
|
TaskQuery.new(query: { status: 'foobar' }).scope.count # => 3
|
130
144
|
```
|
131
145
|
|
146
|
+
You can include a "reset" scope with the `include_empty_scope` option, and provide a default scope with the `default` option:
|
147
|
+
|
148
|
+
```ruby
|
149
|
+
class TasksQuery < Admino::Query::Base
|
150
|
+
# ...
|
151
|
+
filter_by :time, [:last_month, :last_week],
|
152
|
+
include_empty_scope: true,
|
153
|
+
default: :last_week
|
154
|
+
end
|
155
|
+
```
|
156
|
+
|
132
157
|
#### `sorting`
|
133
158
|
|
134
159
|
```ruby
|
@@ -485,7 +510,7 @@ class CustomTablePresenter < Admino::Table::Presenter
|
|
485
510
|
{ class: 'table-class' }
|
486
511
|
end
|
487
512
|
|
488
|
-
def tbody_tr_html_options(
|
513
|
+
def tbody_tr_html_options(resource, index)
|
489
514
|
{ class: 'tr-class' }
|
490
515
|
end
|
491
516
|
|
@@ -3,16 +3,26 @@ module Admino
|
|
3
3
|
class Configuration
|
4
4
|
class SearchField
|
5
5
|
attr_reader :name
|
6
|
-
attr_reader :
|
6
|
+
attr_reader :options
|
7
7
|
|
8
8
|
def initialize(name, options = {})
|
9
9
|
options.symbolize_keys!
|
10
|
-
options.assert_valid_keys(
|
10
|
+
options.assert_valid_keys(
|
11
|
+
:coerce,
|
12
|
+
:default
|
13
|
+
)
|
11
14
|
|
12
15
|
@name = name.to_sym
|
16
|
+
@options = options
|
17
|
+
end
|
18
|
+
|
19
|
+
def default_value
|
20
|
+
options[:default]
|
21
|
+
end
|
13
22
|
|
14
|
-
|
15
|
-
|
23
|
+
def coerce_to
|
24
|
+
if options[:coerce]
|
25
|
+
options[:coerce].to_sym
|
16
26
|
end
|
17
27
|
end
|
18
28
|
end
|
@@ -24,7 +34,10 @@ module Admino
|
|
24
34
|
|
25
35
|
def initialize(name, scopes, options = {})
|
26
36
|
options.symbolize_keys!
|
27
|
-
options.assert_valid_keys(
|
37
|
+
options.assert_valid_keys(
|
38
|
+
:include_empty_scope,
|
39
|
+
:default
|
40
|
+
)
|
28
41
|
|
29
42
|
@name = name.to_sym
|
30
43
|
@scopes = scopes.map(&:to_sym)
|
@@ -34,6 +47,12 @@ module Admino
|
|
34
47
|
def include_empty_scope?
|
35
48
|
@options.fetch(:include_empty_scope) { false }
|
36
49
|
end
|
50
|
+
|
51
|
+
def default_scope
|
52
|
+
if options[:default]
|
53
|
+
options[:default].to_sym
|
54
|
+
end
|
55
|
+
end
|
37
56
|
end
|
38
57
|
|
39
58
|
class Sorting
|
@@ -23,8 +23,8 @@ module Admino
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def active_scope
|
26
|
-
if value && scopes.include?(value
|
27
|
-
value
|
26
|
+
if value && scopes.include?(value)
|
27
|
+
value
|
28
28
|
else
|
29
29
|
nil
|
30
30
|
end
|
@@ -35,8 +35,22 @@ module Admino
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def value
|
38
|
-
|
39
|
-
|
38
|
+
value = params.fetch(:query, {}).fetch(param_name, default_value)
|
39
|
+
if value
|
40
|
+
value.to_sym
|
41
|
+
else
|
42
|
+
nil
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def default_value
|
47
|
+
if config.default_scope
|
48
|
+
config.default_scope
|
49
|
+
elsif config.include_empty_scope?
|
50
|
+
:empty
|
51
|
+
else
|
52
|
+
nil
|
53
|
+
end
|
40
54
|
end
|
41
55
|
|
42
56
|
def param_name
|
@@ -23,16 +23,17 @@ module Admino
|
|
23
23
|
|
24
24
|
def value
|
25
25
|
value = params.fetch(:query, {}).fetch(param_name, nil)
|
26
|
+
|
26
27
|
if config.coerce_to
|
27
|
-
begin
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
else
|
34
|
-
value
|
28
|
+
value = begin
|
29
|
+
coercer = Coercible::Coercer.new
|
30
|
+
coercer[value.class].send(config.coerce_to, value)
|
31
|
+
rescue Coercible::UnsupportedCoercion
|
32
|
+
nil
|
33
|
+
end
|
35
34
|
end
|
35
|
+
|
36
|
+
value || config.default_value
|
36
37
|
end
|
37
38
|
|
38
39
|
def present?
|
data/lib/admino/version.rb
CHANGED
@@ -107,15 +107,19 @@ module Admino
|
|
107
107
|
end
|
108
108
|
end
|
109
109
|
|
110
|
-
context 'with a set of search_fields and
|
110
|
+
context 'with a set of search_fields, filter_groups and sortings' do
|
111
111
|
let(:search_field_config) { config.add_search_field(:search_field) }
|
112
112
|
let(:filter_group_config) { config.add_filter_group(:filter_group, [:one, :two]) }
|
113
|
+
let(:sorting_config) { config.add_sorting_scopes([:title, :year]) }
|
114
|
+
|
113
115
|
let(:scope_chained_with_search_field) { double('scope 1') }
|
114
|
-
let(:
|
116
|
+
let(:scope_chained_with_group_filter) { double('scope 2') }
|
117
|
+
let(:final_chain) { double('scope 3') }
|
115
118
|
|
116
119
|
before do
|
117
120
|
search_field_config
|
118
121
|
filter_group_config
|
122
|
+
sorting_config
|
119
123
|
query
|
120
124
|
|
121
125
|
query.search_field_by_name(:search_field).
|
@@ -126,6 +130,10 @@ module Admino
|
|
126
130
|
query.filter_group_by_name(:filter_group).
|
127
131
|
stub(:augment_scope).
|
128
132
|
with(scope_chained_with_search_field).
|
133
|
+
and_return(scope_chained_with_group_filter)
|
134
|
+
|
135
|
+
query.sorting.stub(:augment_scope).
|
136
|
+
with(scope_chained_with_group_filter).
|
129
137
|
and_return(final_chain)
|
130
138
|
end
|
131
139
|
|
@@ -4,7 +4,10 @@ module Admino
|
|
4
4
|
module Query
|
5
5
|
describe FilterGroup do
|
6
6
|
subject(:filter_group) { FilterGroup.new(config, params) }
|
7
|
-
let(:config)
|
7
|
+
let(:config) do
|
8
|
+
Configuration::FilterGroup.new(:foo, [:bar, :other], options)
|
9
|
+
end
|
10
|
+
let(:options) { {} }
|
8
11
|
let(:params) { {} }
|
9
12
|
|
10
13
|
describe '#active_scope' do
|
@@ -16,7 +19,34 @@ module Admino
|
|
16
19
|
end
|
17
20
|
|
18
21
|
context 'if include_empty_scope is true' do
|
19
|
-
let(:
|
22
|
+
let(:options) { { include_empty_scope: true } }
|
23
|
+
|
24
|
+
it 'returns the :empty scope' do
|
25
|
+
expect(filter_group.active_scope).to eq :empty
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'if default scope is set' do
|
29
|
+
let(:config) do
|
30
|
+
Configuration::FilterGroup.new(
|
31
|
+
:foo,
|
32
|
+
[:bar],
|
33
|
+
include_empty_scope: true,
|
34
|
+
default: :bar
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'returns it' do
|
39
|
+
expect(filter_group.active_scope).to eq :bar
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'with "empty" param' do
|
46
|
+
let(:params) { { 'query' => { 'foo' => 'empty' } } }
|
47
|
+
|
48
|
+
context 'if include_empty_scope is true' do
|
49
|
+
let(:options) { { include_empty_scope: true, default: :bar } }
|
20
50
|
|
21
51
|
it 'returns the :empty scope' do
|
22
52
|
expect(filter_group.active_scope).to eq :empty
|
@@ -32,7 +62,7 @@ module Admino
|
|
32
62
|
end
|
33
63
|
|
34
64
|
context 'if include_empty_scope is true' do
|
35
|
-
let(:
|
65
|
+
let(:options) { { include_empty_scope: true, default: :bar } }
|
36
66
|
|
37
67
|
it 'returns nil' do
|
38
68
|
expect(filter_group.active_scope).to be_nil
|
@@ -67,7 +97,7 @@ module Admino
|
|
67
97
|
end
|
68
98
|
|
69
99
|
context 'if include_empty_scope is true' do
|
70
|
-
let(:
|
100
|
+
let(:options) { { include_empty_scope: true } }
|
71
101
|
|
72
102
|
it 'returns the original scope' do
|
73
103
|
expect(result).to eq scope
|
@@ -88,12 +118,13 @@ module Admino
|
|
88
118
|
subject { filter_group.scopes }
|
89
119
|
|
90
120
|
context 'if include_empty_scope is true' do
|
91
|
-
let(:
|
92
|
-
|
121
|
+
let(:options) { { include_empty_scope: true } }
|
122
|
+
|
123
|
+
it { should eq [:empty, :bar, :other] }
|
93
124
|
end
|
94
125
|
|
95
126
|
context 'else' do
|
96
|
-
it { should eq [:bar] }
|
127
|
+
it { should eq [:bar, :other] }
|
97
128
|
end
|
98
129
|
end
|
99
130
|
end
|
@@ -20,6 +20,16 @@ module Admino
|
|
20
20
|
it 'returns nil' do
|
21
21
|
expect(search_field.value).to be_nil
|
22
22
|
end
|
23
|
+
|
24
|
+
context 'with a default value' do
|
25
|
+
let(:config) {
|
26
|
+
Configuration::SearchField.new(:foo, default: 'foo')
|
27
|
+
}
|
28
|
+
|
29
|
+
it 'returns it' do
|
30
|
+
expect(search_field.value).to eq 'foo'
|
31
|
+
end
|
32
|
+
end
|
23
33
|
end
|
24
34
|
|
25
35
|
context 'with coertion' do
|
data/spec/spec_helper.rb
CHANGED
@@ -32,10 +32,12 @@ class ScopeMock
|
|
32
32
|
end
|
33
33
|
|
34
34
|
class TestQuery < Admino::Query::Base
|
35
|
-
search_field :foo
|
35
|
+
search_field :foo, default: 'bar'
|
36
36
|
search_field :starting_from, coerce: :to_date
|
37
37
|
|
38
|
-
filter_by :bar, [:one, :two],
|
38
|
+
filter_by :bar, [:one, :two],
|
39
|
+
include_empty_scope: true,
|
40
|
+
default: :two
|
39
41
|
|
40
42
|
sorting :by_title, :by_date,
|
41
43
|
default_scope: :by_title,
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: admino
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stefano Verna
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-05-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: showcase
|
@@ -249,3 +249,4 @@ test_files:
|
|
249
249
|
- spec/admino/table/resource_row_spec.rb
|
250
250
|
- spec/admino/table/row_spec.rb
|
251
251
|
- spec/spec_helper.rb
|
252
|
+
has_rdoc:
|