admino 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.travis.yml +9 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +6 -0
- data/admino.gemspec +34 -0
- data/lib/admino.rb +9 -0
- data/lib/admino/query.rb +12 -0
- data/lib/admino/query/base.rb +94 -0
- data/lib/admino/query/base_presenter.rb +34 -0
- data/lib/admino/query/configuration.rb +54 -0
- data/lib/admino/query/dsl.rb +30 -0
- data/lib/admino/query/field.rb +52 -0
- data/lib/admino/query/group.rb +55 -0
- data/lib/admino/query/group_presenter.rb +67 -0
- data/lib/admino/table.rb +7 -0
- data/lib/admino/table/head_row.rb +59 -0
- data/lib/admino/table/presenter.rb +81 -0
- data/lib/admino/table/resource_row.rb +135 -0
- data/lib/admino/table/row.rb +65 -0
- data/lib/admino/version.rb +3 -0
- data/spec/admino/query/base_presenter_spec.rb +60 -0
- data/spec/admino/query/base_spec.rb +133 -0
- data/spec/admino/query/dsl_spec.rb +45 -0
- data/spec/admino/query/field_spec.rb +69 -0
- data/spec/admino/query/group_presenter_spec.rb +140 -0
- data/spec/admino/query/group_spec.rb +65 -0
- data/spec/admino/table/head_row_spec.rb +116 -0
- data/spec/admino/table/presenter_spec.rb +168 -0
- data/spec/admino/table/resource_row_spec.rb +206 -0
- data/spec/admino/table/row_spec.rb +71 -0
- data/spec/spec_helper.rb +82 -0
- metadata +244 -0
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Admino
|
4
|
+
module Query
|
5
|
+
describe BasePresenter do
|
6
|
+
subject(:presenter) { BasePresenter.new(query, view) }
|
7
|
+
let(:view) { RailsViewContext.new }
|
8
|
+
let(:query) do
|
9
|
+
TestQuery.new(query: { foo: 'value' })
|
10
|
+
end
|
11
|
+
let(:request_object) do
|
12
|
+
double(
|
13
|
+
'ActionDispatch::Request',
|
14
|
+
fullpath: '/?foo=bar'
|
15
|
+
)
|
16
|
+
end
|
17
|
+
|
18
|
+
before do
|
19
|
+
view.stub(:request).and_return(request_object)
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#form' do
|
23
|
+
let(:result) do
|
24
|
+
presenter.form do |form|
|
25
|
+
form.label(:foo) <<
|
26
|
+
form.text_field(:foo)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
before do
|
31
|
+
I18n.backend.store_translations(
|
32
|
+
:en,
|
33
|
+
query: { attributes: { test_query: { foo: 'NAME' } } }
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'renders a form pointing to the current URL' do
|
38
|
+
expect(result).to have_tag(:form, with: { action: '/?foo=bar' })
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'renders a form with method GET' do
|
42
|
+
expect(result).to have_tag(:form, with: { method: 'get' })
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'renders inputs with a query[] name prefix' do
|
46
|
+
expect(result).to have_tag(:input, with: { type: 'text', name: 'query[foo]' })
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'prefills inputs with query value' do
|
50
|
+
expect(result).to have_tag(:input, with: { type: 'text', value: 'value' })
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'it generates labels in the :query I18n space' do
|
54
|
+
expect(result).to have_tag(:label, text: 'NAME')
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Admino
|
4
|
+
module Query
|
5
|
+
describe Base do
|
6
|
+
subject(:query) { Base.new(params, config) }
|
7
|
+
let(:params) { {} }
|
8
|
+
let(:config) { nil }
|
9
|
+
|
10
|
+
it 'takes a request params' do
|
11
|
+
expect(query.params).to eq params
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'with an explicit config' do
|
15
|
+
let(:config) { Configuration.new }
|
16
|
+
|
17
|
+
it 'uses it' do
|
18
|
+
expect(query.config).to eq config
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'with a declared field' do
|
23
|
+
let(:config) { Configuration.new }
|
24
|
+
let(:field_config) { config.add_field(:field) }
|
25
|
+
|
26
|
+
before do
|
27
|
+
field_config
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'returns a configured Field' do
|
31
|
+
field = query.field_by_name(:field)
|
32
|
+
expect(field.config).to eq field_config
|
33
|
+
expect(field.params).to eq params
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'with a declared group' do
|
38
|
+
let(:config) { Configuration.new }
|
39
|
+
let(:group_config) { config.add_group(:group, [:one, :two]) }
|
40
|
+
|
41
|
+
before do
|
42
|
+
group_config
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'returns a configured Group' do
|
46
|
+
group = query.group_by_name(:group)
|
47
|
+
expect(group.config).to eq group_config
|
48
|
+
expect(group.params).to eq params
|
49
|
+
expect(group.i18n_key).to eq :group
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe '#scope' do
|
54
|
+
let(:config) { Configuration.new }
|
55
|
+
let(:result) { query.scope(starting_scope) }
|
56
|
+
let(:starting_scope) { ScopeMock.new('explicit') }
|
57
|
+
|
58
|
+
describe 'starting scope' do
|
59
|
+
context 'with an explicit scope' do
|
60
|
+
it 'uses it' do
|
61
|
+
expect(result.name).to eq 'explicit'
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'with no explicit scope, but a default one configured' do
|
66
|
+
let(:result) { query.scope }
|
67
|
+
|
68
|
+
before do
|
69
|
+
config.starting_scope_callable = Proc.new { |query|
|
70
|
+
ScopeMock.new('configured').foo(query)
|
71
|
+
}
|
72
|
+
end
|
73
|
+
|
74
|
+
before do
|
75
|
+
result
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'calls it with self and uses it' do
|
79
|
+
expect(result.name).to eq 'configured'
|
80
|
+
expect(result.chain).to eq [:foo, [query]]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context 'with no scope' do
|
85
|
+
let(:result) { query.scope }
|
86
|
+
|
87
|
+
it 'raises a ArgumentError' do
|
88
|
+
expect { result }.to raise_error(ArgumentError)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
context 'with a set of fields and groups' do
|
94
|
+
let(:field_config) { config.add_field(:field) }
|
95
|
+
let(:group_config) { config.add_group(:group, [:one, :two]) }
|
96
|
+
let(:scope_chained_with_field) { double('scope 1') }
|
97
|
+
let(:final_chain) { double('scope 2') }
|
98
|
+
|
99
|
+
before do
|
100
|
+
field_config
|
101
|
+
group_config
|
102
|
+
query
|
103
|
+
|
104
|
+
query.field_by_name(:field).
|
105
|
+
stub(:augment_scope).
|
106
|
+
with(starting_scope).
|
107
|
+
and_return(scope_chained_with_field)
|
108
|
+
|
109
|
+
query.group_by_name(:group).
|
110
|
+
stub(:augment_scope).
|
111
|
+
with(scope_chained_with_field).
|
112
|
+
and_return(final_chain)
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'chains them toghether' do
|
116
|
+
expect(result).to eq final_chain
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
context 'with a configured ending scope' do
|
121
|
+
before do
|
122
|
+
config.ending_scope_callable = Proc.new { |query| bar(query) }
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'calls it with self at the end of the chain' do
|
126
|
+
expect(result.chain).to eq [:bar, [query]]
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Admino
|
4
|
+
module Query
|
5
|
+
describe Dsl do
|
6
|
+
let(:config) { TestQuery.config }
|
7
|
+
let(:instance) { TestQuery.new }
|
8
|
+
|
9
|
+
it 'allows #field declaration' do
|
10
|
+
field = config.fields.last
|
11
|
+
expect(field.name).to eq :starting_from
|
12
|
+
expect(field.coerce_to).to eq :to_date
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'allows #group declaration' do
|
16
|
+
group = config.groups.first
|
17
|
+
expect(group.name).to eq :bar
|
18
|
+
expect(group.scopes).to eq [:one, :two]
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'allows #starting_scope block declaration' do
|
22
|
+
expect(config.starting_scope_callable.call).to eq 'start'
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'allows #ending_scope block declaration' do
|
26
|
+
expect(config.ending_scope_callable.call).to eq 'end'
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'with a field' do
|
30
|
+
let(:field) { double('Field', value: 'value') }
|
31
|
+
|
32
|
+
before do
|
33
|
+
instance.stub(:field_by_name).
|
34
|
+
with(:foo).
|
35
|
+
and_return(field)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'it generates a getter' do
|
39
|
+
expect(instance.foo).to eq 'value'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Admino
|
4
|
+
module Query
|
5
|
+
describe Field do
|
6
|
+
subject(:field) { Field.new(config, params) }
|
7
|
+
let(:config) { Configuration::Field.new(:foo) }
|
8
|
+
let(:params) { {} }
|
9
|
+
|
10
|
+
describe '#value' do
|
11
|
+
context 'with a value' do
|
12
|
+
let(:params) { { 'query' => { 'foo' => 'bar' } } }
|
13
|
+
|
14
|
+
it 'returns the param value for the field' do
|
15
|
+
expect(field.value).to eq 'bar'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'else' do
|
20
|
+
it 'returns nil' do
|
21
|
+
expect(field.value).to be_nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'with coertion' do
|
26
|
+
let(:config) {
|
27
|
+
Configuration::Field.new(:foo, coerce: :to_date)
|
28
|
+
}
|
29
|
+
|
30
|
+
context 'with a possible coertion' do
|
31
|
+
let(:params) { { 'query' => { 'foo' => '2014-10-05' } } }
|
32
|
+
|
33
|
+
it 'returns the coerced param value for the field' do
|
34
|
+
expect(field.value).to be_a Date
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'with a possible coertion' do
|
39
|
+
let(:params) { { 'query' => { 'foo' => '' } } }
|
40
|
+
|
41
|
+
it 'returns nil' do
|
42
|
+
expect(field.value).to be_nil
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe '#augment_scope' do
|
49
|
+
let(:result) { field.augment_scope(scope) }
|
50
|
+
let(:scope) { ScopeMock.new('original') }
|
51
|
+
|
52
|
+
context 'if the field has a value' do
|
53
|
+
let(:params) { { 'query' => { 'foo' => 'bar' } } }
|
54
|
+
|
55
|
+
it 'returns the original scope chained with the field scope' do
|
56
|
+
expect(result.chain).to eq [:foo, ['bar']]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'else' do
|
61
|
+
it 'returns the original scope' do
|
62
|
+
expect(result).to eq scope
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
@@ -0,0 +1,140 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Admino
|
4
|
+
module Query
|
5
|
+
describe GroupPresenter do
|
6
|
+
subject(:presenter) { GroupPresenter.new(group, view) }
|
7
|
+
let(:view) { RailsViewContext.new }
|
8
|
+
let(:group) do
|
9
|
+
double(
|
10
|
+
'Group',
|
11
|
+
query_i18n_key: :query_name,
|
12
|
+
i18n_key: :group,
|
13
|
+
param_name: :group
|
14
|
+
)
|
15
|
+
end
|
16
|
+
let(:request_object) do
|
17
|
+
double(
|
18
|
+
'ActionDispatch::Request',
|
19
|
+
query_parameters: { 'group' => 'bar' },
|
20
|
+
path: '/'
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
before do
|
25
|
+
view.stub(:request).and_return(request_object)
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#scope_link' do
|
29
|
+
before do
|
30
|
+
group.stub(:is_scope_active?).with(:foo).and_return(true)
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'active CSS class' do
|
34
|
+
it 'adds an is-active class' do
|
35
|
+
expect(presenter.scope_link(:foo)).to have_tag(:a, with: { class: 'is-active' })
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'if an :active_class option is specified' do
|
39
|
+
it 'adds it' do
|
40
|
+
expect(presenter.scope_link(:foo, active_class: 'active')).to have_tag(:a, with: { class: 'active' })
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'else' do
|
45
|
+
before do
|
46
|
+
group.stub(:is_scope_active?).with(:foo).and_return(false)
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'does not add it' do
|
50
|
+
expect(presenter.scope_link(:foo)).not_to have_tag(:a, with: { class: 'is-active' })
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'label' do
|
56
|
+
before do
|
57
|
+
presenter.stub(:scope_name).with(:foo).and_return('scope_name')
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'uses #scope_name method' do
|
61
|
+
expect(presenter.scope_link(:foo)).to have_tag(:a, text: 'scope_name')
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'if a second parameter is supplied' do
|
65
|
+
it 'uses it' do
|
66
|
+
expect(presenter.scope_link(:foo, 'test')).to have_tag(:a, text: 'test')
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'URL' do
|
72
|
+
before do
|
73
|
+
presenter.stub(:scope_path).with(:foo).and_return('URL')
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'uses #scope_path method' do
|
77
|
+
expect(presenter.scope_link(:foo)).to have_tag(:a, href: 'URL')
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe '#scope_params' do
|
83
|
+
context 'if scope is nil' do
|
84
|
+
it 'deletes the group param' do
|
85
|
+
expect(presenter.scope_params(nil)).not_to have_key 'group'
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context 'else' do
|
90
|
+
it 'deletes the group param' do
|
91
|
+
expect(presenter.scope_params(:bar)[:group]).to eq 'bar'
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe '#name' do
|
97
|
+
context do
|
98
|
+
before do
|
99
|
+
I18n.backend.store_translations(
|
100
|
+
:en,
|
101
|
+
query: { groups: { query_name: { group: { name: 'NAME' } } } }
|
102
|
+
)
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'returns a I18n translatable name for the group' do
|
106
|
+
expect(presenter.name).to eq 'NAME'
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
context 'if no translation is available' do
|
111
|
+
it 'falls back to a titleized version of the group name' do
|
112
|
+
expect(presenter.name).to eq 'Group'
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
describe '#scope_name' do
|
118
|
+
context do
|
119
|
+
before do
|
120
|
+
I18n.backend.store_translations(
|
121
|
+
:en,
|
122
|
+
query: { groups: { query_name: { group: { scopes: { bar: 'NAME' } } } } }
|
123
|
+
)
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'returns a I18n translatable name for the scope' do
|
127
|
+
expect(presenter.scope_name(:bar)).to eq 'NAME'
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context 'if no translation is available' do
|
132
|
+
it 'falls back to a titleized version of the scope name' do
|
133
|
+
expect(presenter.scope_name(:bar)).to eq 'Bar'
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|