activeadmin 0.1.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

Files changed (89) hide show
  1. data/.document +5 -0
  2. data/.gitignore +25 -0
  3. data/Gemfile +16 -0
  4. data/LICENSE +20 -0
  5. data/README.rdoc +201 -0
  6. data/Rakefile +71 -0
  7. data/active_admin.gemspec +22 -0
  8. data/lib/active_admin.rb +229 -0
  9. data/lib/active_admin/action_builder.rb +60 -0
  10. data/lib/active_admin/action_items.rb +48 -0
  11. data/lib/active_admin/asset_registration.rb +34 -0
  12. data/lib/active_admin/breadcrumbs.rb +26 -0
  13. data/lib/active_admin/dashboards.rb +50 -0
  14. data/lib/active_admin/dashboards/dashboard_controller.rb +40 -0
  15. data/lib/active_admin/dashboards/renderer.rb +45 -0
  16. data/lib/active_admin/dashboards/section.rb +43 -0
  17. data/lib/active_admin/dashboards/section_renderer.rb +28 -0
  18. data/lib/active_admin/filters.rb +189 -0
  19. data/lib/active_admin/form_builder.rb +91 -0
  20. data/lib/active_admin/helpers/optional_display.rb +34 -0
  21. data/lib/active_admin/menu.rb +42 -0
  22. data/lib/active_admin/menu_item.rb +67 -0
  23. data/lib/active_admin/namespace.rb +111 -0
  24. data/lib/active_admin/page_config.rb +15 -0
  25. data/lib/active_admin/pages.rb +11 -0
  26. data/lib/active_admin/pages/base.rb +92 -0
  27. data/lib/active_admin/pages/edit.rb +21 -0
  28. data/lib/active_admin/pages/index.rb +58 -0
  29. data/lib/active_admin/pages/index/blog.rb +65 -0
  30. data/lib/active_admin/pages/index/table.rb +48 -0
  31. data/lib/active_admin/pages/index/thumbnails.rb +40 -0
  32. data/lib/active_admin/pages/new.rb +21 -0
  33. data/lib/active_admin/pages/show.rb +54 -0
  34. data/lib/active_admin/renderer.rb +72 -0
  35. data/lib/active_admin/resource.rb +96 -0
  36. data/lib/active_admin/resource_controller.rb +325 -0
  37. data/lib/active_admin/sidebar.rb +78 -0
  38. data/lib/active_admin/table_builder.rb +162 -0
  39. data/lib/active_admin/tabs_renderer.rb +39 -0
  40. data/lib/active_admin/version.rb +3 -0
  41. data/lib/active_admin/view_helpers.rb +106 -0
  42. data/lib/active_admin/views/active_admin_dashboard/index.html.erb +1 -0
  43. data/lib/active_admin/views/active_admin_default/edit.html.erb +1 -0
  44. data/lib/active_admin/views/active_admin_default/index.csv.erb +2 -0
  45. data/lib/active_admin/views/active_admin_default/index.html.erb +1 -0
  46. data/lib/active_admin/views/active_admin_default/new.html.erb +1 -0
  47. data/lib/active_admin/views/active_admin_default/show.html.erb +1 -0
  48. data/lib/active_admin/views/layouts/active_admin.html.erb +40 -0
  49. data/lib/activeadmin.rb +1 -0
  50. data/lib/generators/active_admin/install/install_generator.rb +31 -0
  51. data/lib/generators/active_admin/install/templates/active_admin.css +325 -0
  52. data/lib/generators/active_admin/install/templates/active_admin.js +10 -0
  53. data/lib/generators/active_admin/install/templates/active_admin.rb +47 -0
  54. data/lib/generators/active_admin/install/templates/active_admin_vendor.js +382 -0
  55. data/lib/generators/active_admin/install/templates/dashboards.rb +36 -0
  56. data/lib/generators/active_admin/install/templates/images/orderable.gif +0 -0
  57. data/lib/generators/active_admin/resource/resource_generator.rb +16 -0
  58. data/lib/generators/active_admin/resource/templates/admin.rb +3 -0
  59. data/spec/integration/dashboard_spec.rb +44 -0
  60. data/spec/integration/index_as_blog_spec.rb +65 -0
  61. data/spec/integration/index_as_csv_spec.rb +40 -0
  62. data/spec/integration/index_as_table_spec.rb +160 -0
  63. data/spec/integration/index_as_thumbnails_spec.rb +43 -0
  64. data/spec/integration/layout_spec.rb +82 -0
  65. data/spec/integration/new_view_spec.rb +52 -0
  66. data/spec/integration/show_view_spec.rb +91 -0
  67. data/spec/spec_helper.rb +104 -0
  68. data/spec/support/rails_template.rb +19 -0
  69. data/spec/unit/action_builder_spec.rb +76 -0
  70. data/spec/unit/action_items_spec.rb +41 -0
  71. data/spec/unit/active_admin_spec.rb +52 -0
  72. data/spec/unit/asset_registration_spec.rb +37 -0
  73. data/spec/unit/controller_filters_spec.rb +26 -0
  74. data/spec/unit/dashboard_section_spec.rb +63 -0
  75. data/spec/unit/dashboards_spec.rb +59 -0
  76. data/spec/unit/filter_form_builder_spec.rb +157 -0
  77. data/spec/unit/form_builder_spec.rb +238 -0
  78. data/spec/unit/menu_item_spec.rb +137 -0
  79. data/spec/unit/menu_spec.rb +53 -0
  80. data/spec/unit/namespace_spec.rb +107 -0
  81. data/spec/unit/registration_spec.rb +46 -0
  82. data/spec/unit/renderer_spec.rb +100 -0
  83. data/spec/unit/resource_controller_spec.rb +48 -0
  84. data/spec/unit/resource_spec.rb +197 -0
  85. data/spec/unit/routing_spec.rb +12 -0
  86. data/spec/unit/sidebar_spec.rb +96 -0
  87. data/spec/unit/table_builder_spec.rb +162 -0
  88. data/spec/unit/tabs_renderer_spec.rb +34 -0
  89. metadata +247 -0
@@ -0,0 +1,26 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe ActiveAdmin, "filters" do
4
+
5
+ describe "before filters" do
6
+ it "should add a new before filter to ActiveAdmin::ResourceController" do
7
+ ActiveAdmin::ResourceController.should_receive(:before_filter).and_return(true)
8
+ ActiveAdmin.before_filter :my_filter, :only => :show
9
+ end
10
+ end
11
+
12
+ describe "after filters" do
13
+ it "should add a new after filter to ActiveAdmin::ResourceController" do
14
+ ActiveAdmin::ResourceController.should_receive(:after_filter).and_return(true)
15
+ ActiveAdmin.after_filter :my_filter, :only => :show
16
+ end
17
+ end
18
+
19
+ describe "around filters" do
20
+ it "should add a new around filter to ActiveAdmin::ResourceController" do
21
+ ActiveAdmin::ResourceController.should_receive(:around_filter).and_return(true)
22
+ ActiveAdmin.around_filter :my_filter, :only => :show
23
+ end
24
+ end
25
+
26
+ end
@@ -0,0 +1,63 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe ActiveAdmin::Dashboards::Section do
4
+
5
+ def section(options = {})
6
+ name = options.delete(:name) || "Recent Posts"
7
+ ActiveAdmin::Dashboards::Section.new(:admin, name, options){ }
8
+ end
9
+
10
+ describe "accessors" do
11
+ it "should have a namespace" do
12
+ section.namespace.should == :admin
13
+ end
14
+
15
+ it "should have a block" do
16
+ section.block.class.should == Proc
17
+ end
18
+
19
+ it "should have a name" do
20
+ section.name.should == 'Recent Posts'
21
+ end
22
+ end
23
+
24
+ describe "retrieving the renderer class" do
25
+ it "should return default if not set" do
26
+ section.renderer.should == ActiveAdmin::Dashboards::Section.renderers[:default]
27
+ end
28
+ it "should return a set renderer class" do
29
+ m = mock('SectionRenderer')
30
+ ActiveAdmin::Dashboards::Section.renderers[:mock] = m
31
+ section(:as => :mock).renderer.should == m
32
+ ActiveAdmin::Dashboards::Section.renderers.delete(:mock)
33
+ end
34
+ it "should raise an exception if the renderer does not exist" do
35
+ lambda{
36
+ section(:as => :woot).renderer
37
+ }.should raise_error(StandardError)
38
+ end
39
+ end
40
+
41
+ describe "priority" do
42
+ context "when not set" do
43
+ subject{ section.priority }
44
+ it { should == ActiveAdmin::Dashboards::Section::DEFAULT_PRIORITY }
45
+ end
46
+
47
+ context "when set" do
48
+ subject{ section(:priority => 1).priority }
49
+ it { should == 1 }
50
+ end
51
+ end
52
+
53
+ describe "sorting sections" do
54
+ it "should sort by priority then alpha" do
55
+ s1 = section :name => "Woot"
56
+ s2 = section :name => :Alpha
57
+ s3 = section :name => "Zulu", :priority => 1
58
+ s4 = section :name => "Beta", :priority => 100
59
+ [s1,s2,s3,s4].sort.should == [s3, s2, s1, s4]
60
+ end
61
+ end
62
+
63
+ end
@@ -0,0 +1,59 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe ActiveAdmin::Dashboards do
4
+
5
+ after(:each) do
6
+ ActiveAdmin::Dashboards.clear_all_sections!
7
+ end
8
+
9
+ describe "adding sections" do
10
+ before do
11
+ ActiveAdmin::Dashboards.clear_all_sections!
12
+ ActiveAdmin::Dashboards.add_section('Recent Posts')
13
+ end
14
+ it "should add a new section namespaced" do
15
+ ActiveAdmin::Dashboards.sections[:admin].first.should be_an_instance_of(ActiveAdmin::Dashboards::Section)
16
+ end
17
+ end
18
+
19
+ describe "adding sections using the build syntax" do
20
+ before do
21
+ ActiveAdmin::Dashboards.clear_all_sections!
22
+ ActiveAdmin::Dashboards.build do
23
+ section "Recent Posts" do
24
+ end
25
+ end
26
+ end
27
+
28
+ it "should add a new section" do
29
+ ActiveAdmin::Dashboards.sections[:admin].first.should be_an_instance_of(ActiveAdmin::Dashboards::Section)
30
+ end
31
+ end
32
+
33
+ describe "clearing all sections" do
34
+ before do
35
+ ActiveAdmin::Dashboards.add_section('Recent Posts')
36
+ end
37
+ it "should clear all sections" do
38
+ ActiveAdmin::Dashboards.clear_all_sections!
39
+ ActiveAdmin::Dashboards.sections.keys.should be_empty
40
+ end
41
+ end
42
+
43
+ describe "finding namespaced sections" do
44
+ context "when the namespace exists" do
45
+ before do
46
+ ActiveAdmin::Dashboards.add_section('Recent Posts')
47
+ end
48
+ it "should return an array of sections" do
49
+ ActiveAdmin::Dashboards.sections_for_namespace(:admin).should_not be_empty
50
+ end
51
+ end
52
+
53
+ context "when the namespace does not exists" do
54
+ it "should return an empty array" do
55
+ ActiveAdmin::Dashboards.sections_for_namespace(:not_a_namespace).should be_empty
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,157 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+
4
+ describe_with_render ActiveAdmin::FormBuilder do
5
+
6
+ def reset!
7
+ Admin::PostsController.reset_filters!
8
+ end
9
+
10
+ def filter(*args)
11
+ Admin::PostsController.filter *args
12
+ end
13
+
14
+ before do
15
+ @john = User.create :first_name => "John", :last_name => "Doe", :username => "john_doe"
16
+ @jane = User.create :first_name => "Jane", :last_name => "Doe", :username => "jane_doe"
17
+ reset!
18
+ filter :title
19
+ filter :body
20
+ filter :created_at
21
+ filter :id
22
+ filter :author
23
+ get :index
24
+ end
25
+
26
+ after(:each) do
27
+ reset!
28
+ end
29
+
30
+ it "should generate a form which submits via get" do
31
+ response.should have_tag("form", :attributes => { :method => 'get' })
32
+ end
33
+
34
+ it "should generate a filter button" do
35
+ response.should have_tag("input", :attributes => { :type => "submit",
36
+ :value => "Filter" })
37
+ end
38
+
39
+ it "should generate a search field for a string attribute" do
40
+ response.should have_tag("input", :attributes => { :name => "q[title_contains]"})
41
+ end
42
+
43
+ it "should label a text field with search" do
44
+ response.should have_tag('label', 'Search Title')
45
+ end
46
+
47
+ it "should generate a search field for a text attribute" do
48
+ response.should have_tag("input", :attributes => { :name => "q[body_contains]"})
49
+ end
50
+
51
+ it "should only generate the form once" do
52
+ response.body.scan(/q\[title_contains\]/).size.should == 1
53
+ end
54
+
55
+ it "should generate a clear filters link" do
56
+ response.should have_tag("a", "Clear Filters", :attributes => { :class => "clear_filters_btn" })
57
+ end
58
+
59
+ context "when date" do
60
+ it "should generate a date greater than" do
61
+ response.should have_tag("input", :attributes => { :name => "q[created_at_gte]", :class => "datepicker"})
62
+ end
63
+ it "should generate a date less than" do
64
+ response.should have_tag("input", :attributes => { :name => "q[created_at_lte]", :class => "datepicker"})
65
+ end
66
+ end
67
+
68
+ context "when integer" do
69
+ it "should generate a select option for equal to" do
70
+ response.should have_tag("option", "Equal To", :attributes => { :value => 'id_eq' })
71
+ end
72
+ it "should generate a select option for greater than" do
73
+ response.should have_tag("option", "Greater Than")
74
+ end
75
+ it "should generate a select option for less than" do
76
+ response.should have_tag("option", "Less Than")
77
+ end
78
+ it "should generate a text field for input" do
79
+ response.should have_tag("input", :attributes => {
80
+ :name => "q[id_equals]" })
81
+ end
82
+ it "should select the option which is currently being filtered"
83
+ end
84
+
85
+ context "when belong to" do
86
+
87
+ context "when given as the _id attribute name" do
88
+ before do
89
+ filter :author_id
90
+ get :index
91
+ end
92
+ it "should not render as an integer" do
93
+ response.should_not have_tag("input", :attributes => {
94
+ :name => "q[author_id_eq]"})
95
+ end
96
+ it "should render as belongs to select" do
97
+ response.should have_tag("select", :attributes => {
98
+ :name => "q[author_id_eq]"})
99
+ response.should have_tag("option", "jane_doe", :attributes => {
100
+ :value => @jane.id })
101
+ end
102
+ end
103
+
104
+ context "as select" do
105
+ it "should generate a select" do
106
+ response.should have_tag("select", :attributes => {
107
+ :name => "q[author_id_eq]"})
108
+ end
109
+ it "should set the default text to 'Any'" do
110
+ response.should have_tag("option", "Any", :attributes => {
111
+ :value => "" })
112
+ end
113
+ it "should create an option for each related object" do
114
+ response.should have_tag("option", "john_doe", :attributes => {
115
+ :value => @john.id })
116
+ response.should have_tag("option", "jane_doe", :attributes => {
117
+ :value => @jane.id })
118
+ end
119
+ context "with a proc" do
120
+ before do
121
+ reset!
122
+ filter :title, :as => :select, :collection => proc{ ['Title One', 'Title Two'] }
123
+ get :index
124
+ end
125
+ it "should use call the proc as the collection" do
126
+ response.should have_tag("option", "Title One")
127
+ response.should have_tag("option", "Title Two")
128
+ end
129
+ end
130
+ end
131
+
132
+ context "as check boxes" do
133
+ before do
134
+ filter :author, :as => :check_boxes
135
+ get :index
136
+ end
137
+ it "should create a check box for each related object" do
138
+ response.should have_tag("input", :attributes => {
139
+ :name => "q[author_id_in][]",
140
+ :type => "checkbox",
141
+ :value => @john.id })
142
+ response.should have_tag("input", :attributes => {
143
+ :name => "q[author_id_in][]",
144
+ :type => "checkbox",
145
+ :value => @jane.id })
146
+ end
147
+ end
148
+ end # belongs to
149
+
150
+ describe "default filters" do
151
+ it "should order by association, then content columns" do
152
+ attributes = controller.class.default_filters_config.collect{|f| f[:attribute] }
153
+ attributes.should == [ :author, :title, :body, :published_at, :created_at, :updated_at ]
154
+ end
155
+ end
156
+
157
+ end
@@ -0,0 +1,238 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe_with_render ActiveAdmin::FormBuilder do
4
+
5
+ def build_form(&block)
6
+ Admin::PostsController.form(&block)
7
+ get :new
8
+ end
9
+
10
+ context "in general" do
11
+ before do
12
+ build_form do |f|
13
+ f.inputs do
14
+ f.input :title
15
+ f.input :body
16
+ end
17
+ f.label :title, "My Super Title"
18
+ f.text_field :title
19
+ f.buttons do
20
+ f.submit "My Submit Button"
21
+ f.commit_button "Submit Me"
22
+ f.commit_button "Another Button"
23
+ end
24
+ end
25
+ end
26
+ it "should generate a text input" do
27
+ response.should have_tag("input", :attributes => { :type => "text",
28
+ :name => "post[title]" })
29
+ end
30
+ it "should generate a label using the default form methods" do
31
+ response.should have_tag("label", "My Super Title")
32
+ end
33
+ it "should generate a textarea" do
34
+ response.should have_tag("textarea", :attributes => { :name => "post[body]" })
35
+ end
36
+ it "should only generate the form once" do
37
+ response.body.scan(/My Super Title/).size.should == 1
38
+ end
39
+ it "should generate buttons" do
40
+ response.should have_tag("input", :attributes => { :type => "submit",
41
+ :value => "Submit Me" })
42
+ response.should have_tag("input", :attributes => { :type => "submit",
43
+ :value => "Another Button" })
44
+ end
45
+ end
46
+
47
+ describe "passing in options" do
48
+ before do
49
+ Admin::PostsController.form :html => { :multipart => true } do |f|
50
+ f.inputs :title
51
+ f.buttons
52
+ end
53
+ get :new
54
+ end
55
+ it "should pass the options on to the form" do
56
+ response.should have_tag("form", :attributes => { :enctype => "multipart/form-data" })
57
+ end
58
+ end
59
+
60
+ context "with default settings" do
61
+ before do
62
+ Admin::PostsController.reset_form_config!
63
+ get :new
64
+ end
65
+ it "should generate one post title field" do
66
+ response.body.scan('id="post_title"').size.should == 1
67
+ end
68
+ end
69
+
70
+ context "with buttons" do
71
+ it "should generate the form once" do
72
+ build_form do |f|
73
+ f.inputs do
74
+ f.input :title
75
+ end
76
+ f.buttons
77
+ end
78
+ response.body.scan(/id=\"post_title\"/).size.should == 1
79
+ end
80
+ it "should generate one button" do
81
+ build_form do |f|
82
+ f.buttons
83
+ end
84
+ response.body.scan(/type=\"submit\"/).size.should == 1
85
+ end
86
+ it "should generate multiple buttons" do
87
+ build_form do |f|
88
+ f.buttons do
89
+ f.submit "Create"
90
+ f.commit_button "Create & Continue"
91
+ f.commit_button "Create & Edit"
92
+ end
93
+ end
94
+ response.body.scan(/type=\"submit\"/).size.should == 3
95
+ end
96
+
97
+ end
98
+
99
+ context "without passing a block to inputs" do
100
+ before do
101
+ build_form do |f|
102
+ f.inputs :title, :body
103
+ end
104
+ end
105
+ it "should have a title input" do
106
+ response.should have_tag("input", :attributes => { :type => "text",
107
+ :name => "post[title]" })
108
+ end
109
+ it "should have a body textarea" do
110
+ response.should have_tag("textarea", :attributes => { :name => "post[body]" })
111
+ end
112
+ end
113
+
114
+ context "with semantic fields for" do
115
+ before do
116
+ build_form do |f|
117
+ f.inputs do
118
+ f.input :title
119
+ f.input :body
120
+ end
121
+ f.instance_eval do
122
+ @object.author = User.new
123
+ end
124
+ f.semantic_fields_for :author do |author|
125
+ author.inputs :first_name, :last_name
126
+ end
127
+ end
128
+ end
129
+ it "should generate a nested text input once" do
130
+ response.body.scan("post_author_attributes_first_name_input").size.should == 1
131
+ end
132
+ end
133
+
134
+ context "with collection inputs" do
135
+ before do
136
+ User.create :first_name => "John", :last_name => "Doe"
137
+ User.create :first_name => "Jane", :last_name => "Doe"
138
+ end
139
+
140
+ describe "as select" do
141
+ before do
142
+ build_form do |f|
143
+ f.input :author
144
+ end
145
+ end
146
+ it "should create 2 options" do
147
+ response.body.scan(/\<option/).size.should == 3
148
+ end
149
+ end
150
+
151
+ describe "as radio buttons" do
152
+ before do
153
+ build_form do |f|
154
+ f.input :author, :as => :radio
155
+ end
156
+ end
157
+ it "should create 2 radio buttons" do
158
+ response.body.scan(/type=\"radio\"/).size.should == 2
159
+ end
160
+ end
161
+ end
162
+
163
+ context "with inputs 'for'" do
164
+ before do
165
+ build_form do |f|
166
+ f.inputs do
167
+ f.input :title
168
+ f.input :body
169
+ end
170
+ f.instance_eval do
171
+ @object.author = User.new
172
+ end
173
+ f.inputs :name => 'Author', :for => :author do |author|
174
+ author.inputs :first_name, :last_name
175
+ end
176
+ end
177
+ end
178
+ it "should generate a nested text input once" do
179
+ response.body.scan("post_author_attributes_first_name_input").size.should == 1
180
+ end
181
+ it "should add an author first name field" do
182
+ response.body.should have_tag("input", :attributes => { :name => "post[author_attributes][first_name]"})
183
+ end
184
+ end
185
+
186
+ context "with wrapper html" do
187
+ it "should set a class" do
188
+ build_form do |f|
189
+ f.input :title, :wrapper_html => { :class => "important" }
190
+ end
191
+ response.should have_tag("li", :attributes => {:class => "string optional important"})
192
+ end
193
+ end
194
+
195
+
196
+ # This checks that each input can be added via the standard
197
+ # rails method as well as using the form builder's #input method.
198
+ {
199
+ "input :title, :as => :string" => /id\=\"post_title\"/,
200
+ "text_field :title" => /id\=\"post_title\"/,
201
+ "input :title, :as => :text" => /id\=\"post_title\"/,
202
+ "text_area :title" => /id\=\"post_title\"/,
203
+ "input :created_at, :as => :time" => /id\=\"post_created_at_2i\"/,
204
+ "time_select :created_at" => /id\=\"post_created_at_2i\"/,
205
+ "input :created_at, :as => :datetime" => /id\=\"post_created_at_2i\"/,
206
+ "datetime_select :created_at" => /id\=\"post_created_at_2i\"/,
207
+ "input :created_at, :as => :date" => /id\=\"post_created_at_2i\"/,
208
+ "date_select :created_at" => /id\=\"post_created_at_2i\"/,
209
+ "radio_button :title, 'title'" => /id\=\"post_title_title\"/,
210
+ "file_field :title" => /id\=\"post_title\"/,
211
+ "hidden_field :title" => /id\=\"post_title\"/,
212
+ "label :title" => /for\=\"post_title\"/,
213
+ }.each do |source, regex|
214
+ it "should properly buffer #{source}" do
215
+ build_form do |f|
216
+ f.instance_eval(source)
217
+ f.instance_eval(source)
218
+ end
219
+ response.body.scan(regex).size.should == 2
220
+ end
221
+ end
222
+
223
+ describe "datepicker input" do
224
+ before do
225
+ build_form do |f|
226
+ f.inputs do
227
+ f.input :created_at, :as => :datepicker
228
+ end
229
+ end
230
+ end
231
+ it "should generate a text input with the class of datepicker" do
232
+ response.should have_tag("input", :attributes => { :type => "text",
233
+ :class => "datepicker",
234
+ :name => "post[created_at]" })
235
+ end
236
+ end
237
+
238
+ end