activeadmin-orac 1.0.0.pre4

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.
Files changed (529) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +49 -0
  3. data/.hound.yml +14 -0
  4. data/.travis.yml +40 -0
  5. data/.yardopts +8 -0
  6. data/CHANGELOG.md +120 -0
  7. data/CODE_OF_CONDUCT.md +22 -0
  8. data/CONTRIBUTING.md +144 -0
  9. data/Gemfile +78 -0
  10. data/Guardfile +8 -0
  11. data/LICENSE +20 -0
  12. data/README.md +102 -0
  13. data/Rakefile +33 -0
  14. data/activeadmin.gemspec +31 -0
  15. data/app/assets/images/active_admin/datepicker/datepicker-input-icon.png +0 -0
  16. data/app/assets/images/active_admin/nested_menu_arrow.gif +0 -0
  17. data/app/assets/images/active_admin/nested_menu_arrow_dark.gif +0 -0
  18. data/app/assets/images/active_admin/orderable.png +0 -0
  19. data/app/assets/javascripts/active_admin/base.js.coffee +9 -0
  20. data/app/assets/javascripts/active_admin/ext/jquery-ui.js.coffee +6 -0
  21. data/app/assets/javascripts/active_admin/ext/jquery.js.coffee +7 -0
  22. data/app/assets/javascripts/active_admin/initializers/batch_actions.js.coffee +7 -0
  23. data/app/assets/javascripts/active_admin/initializers/datepicker.js.coffee +10 -0
  24. data/app/assets/javascripts/active_admin/initializers/filters.js.coffee +22 -0
  25. data/app/assets/javascripts/active_admin/initializers/tabs.js.coffee +3 -0
  26. data/app/assets/javascripts/active_admin/jquery_ui.js.erb +11 -0
  27. data/app/assets/javascripts/active_admin/lib/batch_actions.js.coffee +39 -0
  28. data/app/assets/javascripts/active_admin/lib/checkbox-toggler.js.coffee +44 -0
  29. data/app/assets/javascripts/active_admin/lib/dropdown-menu.js.coffee +101 -0
  30. data/app/assets/javascripts/active_admin/lib/flash.js.coffee +19 -0
  31. data/app/assets/javascripts/active_admin/lib/has_many.js.coffee +79 -0
  32. data/app/assets/javascripts/active_admin/lib/modal_dialog.js.coffee +45 -0
  33. data/app/assets/javascripts/active_admin/lib/per_page.js.coffee +42 -0
  34. data/app/assets/javascripts/active_admin/lib/table-checkbox-toggler.js.coffee +24 -0
  35. data/app/assets/stylesheets/active_admin/_base.scss +41 -0
  36. data/app/assets/stylesheets/active_admin/_forms.scss +333 -0
  37. data/app/assets/stylesheets/active_admin/_header.scss +156 -0
  38. data/app/assets/stylesheets/active_admin/_mixins.scss +1 -0
  39. data/app/assets/stylesheets/active_admin/_typography.scss +100 -0
  40. data/app/assets/stylesheets/active_admin/components/_batch_actions.scss +11 -0
  41. data/app/assets/stylesheets/active_admin/components/_blank_slates.scss +30 -0
  42. data/app/assets/stylesheets/active_admin/components/_breadcrumbs.scss +20 -0
  43. data/app/assets/stylesheets/active_admin/components/_buttons.scss +6 -0
  44. data/app/assets/stylesheets/active_admin/components/_columns.scss +3 -0
  45. data/app/assets/stylesheets/active_admin/components/_comments.scss +41 -0
  46. data/app/assets/stylesheets/active_admin/components/_date_picker.scss +149 -0
  47. data/app/assets/stylesheets/active_admin/components/_dropdown_menu.scss +152 -0
  48. data/app/assets/stylesheets/active_admin/components/_flash_messages.scss +37 -0
  49. data/app/assets/stylesheets/active_admin/components/_grid.scss +9 -0
  50. data/app/assets/stylesheets/active_admin/components/_index_list.scss +12 -0
  51. data/app/assets/stylesheets/active_admin/components/_links.scss +5 -0
  52. data/app/assets/stylesheets/active_admin/components/_modal_dialog.scss +34 -0
  53. data/app/assets/stylesheets/active_admin/components/_pagination.scss +44 -0
  54. data/app/assets/stylesheets/active_admin/components/_panels.scss +6 -0
  55. data/app/assets/stylesheets/active_admin/components/_scopes.scss +10 -0
  56. data/app/assets/stylesheets/active_admin/components/_status_tags.scss +16 -0
  57. data/app/assets/stylesheets/active_admin/components/_table_tools.scss +67 -0
  58. data/app/assets/stylesheets/active_admin/components/_tables.scss +110 -0
  59. data/app/assets/stylesheets/active_admin/components/_tabs.scss +65 -0
  60. data/app/assets/stylesheets/active_admin/components/_unsupported_browser.scss +16 -0
  61. data/app/assets/stylesheets/active_admin/mixins/_all.scss +10 -0
  62. data/app/assets/stylesheets/active_admin/mixins/_buttons.scss +65 -0
  63. data/app/assets/stylesheets/active_admin/mixins/_gradients.scss +28 -0
  64. data/app/assets/stylesheets/active_admin/mixins/_reset.scss +165 -0
  65. data/app/assets/stylesheets/active_admin/mixins/_rounded.scss +22 -0
  66. data/app/assets/stylesheets/active_admin/mixins/_sections.scss +41 -0
  67. data/app/assets/stylesheets/active_admin/mixins/_shadows.scss +15 -0
  68. data/app/assets/stylesheets/active_admin/mixins/_typography.scss +3 -0
  69. data/app/assets/stylesheets/active_admin/mixins/_utilities.scss +17 -0
  70. data/app/assets/stylesheets/active_admin/mixins/_variables.scss +34 -0
  71. data/app/assets/stylesheets/active_admin/pages/_logged_out.scss +44 -0
  72. data/app/assets/stylesheets/active_admin/print.scss +288 -0
  73. data/app/assets/stylesheets/active_admin/structure/_footer.scss +14 -0
  74. data/app/assets/stylesheets/active_admin/structure/_main_structure.scss +29 -0
  75. data/app/assets/stylesheets/active_admin/structure/_title_bar.scss +41 -0
  76. data/app/views/active_admin/devise/confirmations/new.html.erb +15 -0
  77. data/app/views/active_admin/devise/mailer/reset_password_instructions.html.erb +8 -0
  78. data/app/views/active_admin/devise/mailer/unlock_instructions.html.erb +7 -0
  79. data/app/views/active_admin/devise/passwords/edit.html.erb +18 -0
  80. data/app/views/active_admin/devise/passwords/new.html.erb +15 -0
  81. data/app/views/active_admin/devise/registrations/new.html.erb +22 -0
  82. data/app/views/active_admin/devise/sessions/new.html.erb +20 -0
  83. data/app/views/active_admin/devise/shared/_links.erb +27 -0
  84. data/app/views/active_admin/devise/unlocks/new.html.erb +15 -0
  85. data/app/views/active_admin/page/index.html.arb +1 -0
  86. data/app/views/active_admin/resource/edit.html.arb +1 -0
  87. data/app/views/active_admin/resource/index.html.arb +1 -0
  88. data/app/views/active_admin/resource/new.html.arb +1 -0
  89. data/app/views/active_admin/resource/show.html.arb +1 -0
  90. data/app/views/layouts/active_admin.html.arb +1 -0
  91. data/app/views/layouts/active_admin_logged_out.html.erb +39 -0
  92. data/config/locales/ar.yml +136 -0
  93. data/config/locales/bg.yml +121 -0
  94. data/config/locales/bs.yml +122 -0
  95. data/config/locales/ca.yml +107 -0
  96. data/config/locales/cs.yml +110 -0
  97. data/config/locales/da.yml +106 -0
  98. data/config/locales/de-CH.yml +102 -0
  99. data/config/locales/de.yml +135 -0
  100. data/config/locales/el.yml +127 -0
  101. data/config/locales/en-GB.yml +98 -0
  102. data/config/locales/en.yml +136 -0
  103. data/config/locales/es-MX.yml +94 -0
  104. data/config/locales/es.yml +136 -0
  105. data/config/locales/fa.yml +120 -0
  106. data/config/locales/fi.yml +113 -0
  107. data/config/locales/fr.yml +119 -0
  108. data/config/locales/he.yml +95 -0
  109. data/config/locales/hr.yml +124 -0
  110. data/config/locales/hu.yml +99 -0
  111. data/config/locales/id.yml +136 -0
  112. data/config/locales/it.yml +136 -0
  113. data/config/locales/ja.yml +136 -0
  114. data/config/locales/ko.yml +121 -0
  115. data/config/locales/lt.yml +121 -0
  116. data/config/locales/lv.yml +93 -0
  117. data/config/locales/nb.yml +121 -0
  118. data/config/locales/nl.yml +134 -0
  119. data/config/locales/pl.yml +98 -0
  120. data/config/locales/pt-BR.yml +136 -0
  121. data/config/locales/pt-PT.yml +93 -0
  122. data/config/locales/ro.yml +97 -0
  123. data/config/locales/ru.yml +140 -0
  124. data/config/locales/sv-SE.yml +134 -0
  125. data/config/locales/tr.yml +136 -0
  126. data/config/locales/uk.yml +137 -0
  127. data/config/locales/vi.yml +94 -0
  128. data/config/locales/zh-CN.yml +112 -0
  129. data/config/locales/zh-TW.yml +136 -0
  130. data/cucumber.yml +3 -0
  131. data/docs/0-installation.md +112 -0
  132. data/docs/1-general-configuration.md +171 -0
  133. data/docs/10-custom-pages.md +106 -0
  134. data/docs/11-decorators.md +55 -0
  135. data/docs/12-arbre-components.md +150 -0
  136. data/docs/13-authorization-adapter.md +248 -0
  137. data/docs/14-gotchas.md +116 -0
  138. data/docs/2-resource-customization.md +422 -0
  139. data/docs/3-index-pages.md +272 -0
  140. data/docs/3-index-pages/custom-index.md +31 -0
  141. data/docs/3-index-pages/index-as-block.md +21 -0
  142. data/docs/3-index-pages/index-as-blog.md +71 -0
  143. data/docs/3-index-pages/index-as-grid.md +29 -0
  144. data/docs/3-index-pages/index-as-table.md +213 -0
  145. data/docs/4-csv-format.md +58 -0
  146. data/docs/5-forms.md +172 -0
  147. data/docs/6-show-pages.md +105 -0
  148. data/docs/7-sidebars.md +71 -0
  149. data/docs/8-custom-actions.md +160 -0
  150. data/docs/9-batch-actions.md +233 -0
  151. data/docs/README.md +24 -0
  152. data/features/action_item.feature +73 -0
  153. data/features/authorization.feature +64 -0
  154. data/features/authorization_cancan.feature +52 -0
  155. data/features/authorization_pundit.feature +37 -0
  156. data/features/belongs_to.feature +66 -0
  157. data/features/breadcrumb.feature +75 -0
  158. data/features/comments/commenting.feature +171 -0
  159. data/features/comments/viewing_index.feature +19 -0
  160. data/features/dashboard.feature +16 -0
  161. data/features/decorators.feature +43 -0
  162. data/features/development_reloading.feature +30 -0
  163. data/features/edit_page.feature +117 -0
  164. data/features/favicon.feature +20 -0
  165. data/features/first_boot.feature +16 -0
  166. data/features/global_navigation.feature +29 -0
  167. data/features/i18n.feature +43 -0
  168. data/features/index/batch_actions.feature +196 -0
  169. data/features/index/filters.feature +161 -0
  170. data/features/index/format_as_csv.feature +203 -0
  171. data/features/index/formats.feature +66 -0
  172. data/features/index/index_as_block.feature +15 -0
  173. data/features/index/index_as_blog.feature +69 -0
  174. data/features/index/index_as_grid.feature +45 -0
  175. data/features/index/index_as_table.feature +291 -0
  176. data/features/index/index_blank_slate.feature +83 -0
  177. data/features/index/index_parameters.feature +75 -0
  178. data/features/index/index_scope_to.feature +56 -0
  179. data/features/index/index_scopes.feature +251 -0
  180. data/features/index/page_title.feature +42 -0
  181. data/features/index/pagination.feature +63 -0
  182. data/features/index/switch_index_view.feature +73 -0
  183. data/features/menu.feature +53 -0
  184. data/features/meta_tags.feature +21 -0
  185. data/features/new_page.feature +109 -0
  186. data/features/registering_assets.feature +34 -0
  187. data/features/registering_pages.feature +148 -0
  188. data/features/registering_resources.feature +33 -0
  189. data/features/renamed_resource.feature +32 -0
  190. data/features/root_to.feature +17 -0
  191. data/features/show/columns.feature +40 -0
  192. data/features/show/default_content.feature +44 -0
  193. data/features/show/page_title.feature +59 -0
  194. data/features/show/tabs.feature +27 -0
  195. data/features/sidebar_sections.feature +210 -0
  196. data/features/site_title.feature +47 -0
  197. data/features/specifying_actions.feature +93 -0
  198. data/features/step_definitions/action_item_steps.rb +7 -0
  199. data/features/step_definitions/action_link_steps.rb +20 -0
  200. data/features/step_definitions/additional_web_steps.rb +81 -0
  201. data/features/step_definitions/asset_steps.rb +15 -0
  202. data/features/step_definitions/attribute_steps.rb +18 -0
  203. data/features/step_definitions/batch_action_steps.rb +81 -0
  204. data/features/step_definitions/blog_steps.rb +3 -0
  205. data/features/step_definitions/breadcrumb_steps.rb +3 -0
  206. data/features/step_definitions/column_steps.rb +8 -0
  207. data/features/step_definitions/comment_steps.rb +12 -0
  208. data/features/step_definitions/configuration_steps.rb +100 -0
  209. data/features/step_definitions/dashboard_steps.rb +15 -0
  210. data/features/step_definitions/factory_steps.rb +35 -0
  211. data/features/step_definitions/filter_steps.rb +39 -0
  212. data/features/step_definitions/flash_steps.rb +11 -0
  213. data/features/step_definitions/format_steps.rb +52 -0
  214. data/features/step_definitions/i18n_steps.rb +3 -0
  215. data/features/step_definitions/index_scope_steps.rb +21 -0
  216. data/features/step_definitions/index_views_steps.rb +3 -0
  217. data/features/step_definitions/layout_steps.rb +3 -0
  218. data/features/step_definitions/member_link_steps.rb +7 -0
  219. data/features/step_definitions/menu_steps.rb +11 -0
  220. data/features/step_definitions/meta_tag_steps.rb +3 -0
  221. data/features/step_definitions/pagination_steps.rb +15 -0
  222. data/features/step_definitions/sidebar_steps.rb +13 -0
  223. data/features/step_definitions/site_title_steps.rb +17 -0
  224. data/features/step_definitions/symbol_leak_steps.rb +3 -0
  225. data/features/step_definitions/tab_steps.rb +8 -0
  226. data/features/step_definitions/table_steps.rb +116 -0
  227. data/features/step_definitions/user_steps.rb +52 -0
  228. data/features/step_definitions/web_steps.rb +85 -0
  229. data/features/sti_resource.feature +65 -0
  230. data/features/strong_parameters.feature +73 -0
  231. data/features/support/env.rb +162 -0
  232. data/features/support/paths.rb +71 -0
  233. data/features/support/selectors.rb +45 -0
  234. data/features/symbol_leak.feature +35 -0
  235. data/features/users/logging_in.feature +36 -0
  236. data/features/users/logging_out.feature +13 -0
  237. data/features/users/resetting_password.feature +34 -0
  238. data/lib/active_admin.rb +130 -0
  239. data/lib/active_admin/abstract_view_factory.rb +85 -0
  240. data/lib/active_admin/application.rb +324 -0
  241. data/lib/active_admin/asset_registration.rb +29 -0
  242. data/lib/active_admin/authorization_adapter.rb +132 -0
  243. data/lib/active_admin/base_controller.rb +87 -0
  244. data/lib/active_admin/base_controller/authorization.rb +130 -0
  245. data/lib/active_admin/base_controller/menu.rb +38 -0
  246. data/lib/active_admin/batch_actions.rb +16 -0
  247. data/lib/active_admin/batch_actions/controller.rb +40 -0
  248. data/lib/active_admin/batch_actions/resource_extension.rb +159 -0
  249. data/lib/active_admin/batch_actions/views/batch_action_form.rb +38 -0
  250. data/lib/active_admin/batch_actions/views/batch_action_selector.rb +58 -0
  251. data/lib/active_admin/batch_actions/views/selection_cells.rb +37 -0
  252. data/lib/active_admin/callbacks.rb +88 -0
  253. data/lib/active_admin/cancan_adapter.rb +36 -0
  254. data/lib/active_admin/component.rb +5 -0
  255. data/lib/active_admin/controller_action.rb +12 -0
  256. data/lib/active_admin/csv_builder.rb +129 -0
  257. data/lib/active_admin/dependency.rb +168 -0
  258. data/lib/active_admin/deprecation.rb +35 -0
  259. data/lib/active_admin/devise.rb +80 -0
  260. data/lib/active_admin/dsl.rb +173 -0
  261. data/lib/active_admin/engine.rb +16 -0
  262. data/lib/active_admin/error.rb +62 -0
  263. data/lib/active_admin/event.rb +24 -0
  264. data/lib/active_admin/filters.rb +9 -0
  265. data/lib/active_admin/filters/active.rb +30 -0
  266. data/lib/active_admin/filters/dsl.rb +21 -0
  267. data/lib/active_admin/filters/forms.rb +83 -0
  268. data/lib/active_admin/filters/formtastic_addons.rb +79 -0
  269. data/lib/active_admin/filters/humanized.rb +68 -0
  270. data/lib/active_admin/filters/resource_extension.rb +194 -0
  271. data/lib/active_admin/form_builder.rb +145 -0
  272. data/lib/active_admin/generators/boilerplate.rb +45 -0
  273. data/lib/active_admin/helpers/collection.rb +17 -0
  274. data/lib/active_admin/helpers/i18n.rb +7 -0
  275. data/lib/active_admin/helpers/optional_display.rb +38 -0
  276. data/lib/active_admin/helpers/routes/url_helpers.rb +15 -0
  277. data/lib/active_admin/helpers/scope_chain.rb +23 -0
  278. data/lib/active_admin/helpers/settings.rb +115 -0
  279. data/lib/active_admin/inputs.rb +20 -0
  280. data/lib/active_admin/inputs/datepicker_input.rb +20 -0
  281. data/lib/active_admin/inputs/filters/base.rb +44 -0
  282. data/lib/active_admin/inputs/filters/base/search_method_select.rb +75 -0
  283. data/lib/active_admin/inputs/filters/boolean_input.rb +24 -0
  284. data/lib/active_admin/inputs/filters/check_boxes_input.rb +50 -0
  285. data/lib/active_admin/inputs/filters/date_picker_input.rb +13 -0
  286. data/lib/active_admin/inputs/filters/date_range_input.rb +36 -0
  287. data/lib/active_admin/inputs/filters/numeric_input.rb +12 -0
  288. data/lib/active_admin/inputs/filters/select_input.rb +55 -0
  289. data/lib/active_admin/inputs/filters/string_input.rb +26 -0
  290. data/lib/active_admin/menu.rb +108 -0
  291. data/lib/active_admin/menu_collection.rb +93 -0
  292. data/lib/active_admin/menu_item.rb +97 -0
  293. data/lib/active_admin/namespace.rb +247 -0
  294. data/lib/active_admin/order_clause.rb +26 -0
  295. data/lib/active_admin/orm/active_record.rb +5 -0
  296. data/lib/active_admin/orm/active_record/comments.rb +95 -0
  297. data/lib/active_admin/orm/active_record/comments/comment.rb +45 -0
  298. data/lib/active_admin/orm/active_record/comments/namespace_helper.rb +14 -0
  299. data/lib/active_admin/orm/active_record/comments/resource_helper.rb +17 -0
  300. data/lib/active_admin/orm/active_record/comments/show_page_helper.rb +23 -0
  301. data/lib/active_admin/orm/active_record/comments/views.rb +2 -0
  302. data/lib/active_admin/orm/active_record/comments/views/active_admin_comments.rb +88 -0
  303. data/lib/active_admin/orm/mongoid.rb +1 -0
  304. data/lib/active_admin/orm/mongoid/.gitkeep +0 -0
  305. data/lib/active_admin/page.rb +92 -0
  306. data/lib/active_admin/page_controller.rb +33 -0
  307. data/lib/active_admin/page_dsl.rb +28 -0
  308. data/lib/active_admin/page_presenter.rb +32 -0
  309. data/lib/active_admin/pundit_adapter.rb +68 -0
  310. data/lib/active_admin/reloader.rb +25 -0
  311. data/lib/active_admin/resource.rb +168 -0
  312. data/lib/active_admin/resource/action_items.rb +108 -0
  313. data/lib/active_admin/resource/belongs_to.rb +44 -0
  314. data/lib/active_admin/resource/controllers.rb +19 -0
  315. data/lib/active_admin/resource/includes.rb +12 -0
  316. data/lib/active_admin/resource/menu.rb +64 -0
  317. data/lib/active_admin/resource/naming.rb +62 -0
  318. data/lib/active_admin/resource/page_presenters.rb +82 -0
  319. data/lib/active_admin/resource/pagination.rb +23 -0
  320. data/lib/active_admin/resource/routes.rb +115 -0
  321. data/lib/active_admin/resource/scope_to.rb +74 -0
  322. data/lib/active_admin/resource/scopes.rb +50 -0
  323. data/lib/active_admin/resource/sidebars.rb +28 -0
  324. data/lib/active_admin/resource_collection.rb +72 -0
  325. data/lib/active_admin/resource_controller.rb +51 -0
  326. data/lib/active_admin/resource_controller/action_builder.rb +21 -0
  327. data/lib/active_admin/resource_controller/data_access.rb +317 -0
  328. data/lib/active_admin/resource_controller/decorators.rb +102 -0
  329. data/lib/active_admin/resource_controller/resource_class_methods.rb +24 -0
  330. data/lib/active_admin/resource_controller/scoping.rb +31 -0
  331. data/lib/active_admin/resource_controller/sidebars.rb +18 -0
  332. data/lib/active_admin/resource_controller/streaming.rb +43 -0
  333. data/lib/active_admin/resource_dsl.rb +190 -0
  334. data/lib/active_admin/router.rb +106 -0
  335. data/lib/active_admin/scope.rb +56 -0
  336. data/lib/active_admin/sidebar_section.rb +37 -0
  337. data/lib/active_admin/version.rb +3 -0
  338. data/lib/active_admin/view_factory.rb +27 -0
  339. data/lib/active_admin/view_helpers.rb +19 -0
  340. data/lib/active_admin/view_helpers/active_admin_application_helper.rb +12 -0
  341. data/lib/active_admin/view_helpers/auto_link_helper.rb +45 -0
  342. data/lib/active_admin/view_helpers/breadcrumb_helper.rb +33 -0
  343. data/lib/active_admin/view_helpers/display_helper.rb +97 -0
  344. data/lib/active_admin/view_helpers/download_format_links_helper.rb +46 -0
  345. data/lib/active_admin/view_helpers/fields_for.rb +51 -0
  346. data/lib/active_admin/view_helpers/flash_helper.rb +14 -0
  347. data/lib/active_admin/view_helpers/form_helper.rb +20 -0
  348. data/lib/active_admin/view_helpers/method_or_proc_helper.rb +97 -0
  349. data/lib/active_admin/view_helpers/sidebar_helper.rb +15 -0
  350. data/lib/active_admin/view_helpers/title_helper.rb +11 -0
  351. data/lib/active_admin/view_helpers/view_factory_helper.rb +11 -0
  352. data/lib/active_admin/views.rb +8 -0
  353. data/lib/active_admin/views/action_items.rb +17 -0
  354. data/lib/active_admin/views/components/active_admin_form.rb +124 -0
  355. data/lib/active_admin/views/components/attributes_table.rb +94 -0
  356. data/lib/active_admin/views/components/blank_slate.rb +17 -0
  357. data/lib/active_admin/views/components/columns.rb +161 -0
  358. data/lib/active_admin/views/components/dropdown_menu.rb +71 -0
  359. data/lib/active_admin/views/components/index_list.rb +68 -0
  360. data/lib/active_admin/views/components/paginated_collection.rb +163 -0
  361. data/lib/active_admin/views/components/panel.rb +38 -0
  362. data/lib/active_admin/views/components/scopes.rb +66 -0
  363. data/lib/active_admin/views/components/sidebar_section.rb +34 -0
  364. data/lib/active_admin/views/components/site_title.rb +55 -0
  365. data/lib/active_admin/views/components/status_tag.rb +80 -0
  366. data/lib/active_admin/views/components/table_for.rb +218 -0
  367. data/lib/active_admin/views/components/tabs.rb +28 -0
  368. data/lib/active_admin/views/components/unsupported_browser.rb +11 -0
  369. data/lib/active_admin/views/footer.rb +20 -0
  370. data/lib/active_admin/views/header.rb +32 -0
  371. data/lib/active_admin/views/index_as_block.rb +36 -0
  372. data/lib/active_admin/views/index_as_blog.rb +156 -0
  373. data/lib/active_admin/views/index_as_grid.rb +80 -0
  374. data/lib/active_admin/views/index_as_table.rb +373 -0
  375. data/lib/active_admin/views/pages/base.rb +147 -0
  376. data/lib/active_admin/views/pages/form.rb +65 -0
  377. data/lib/active_admin/views/pages/index.rb +163 -0
  378. data/lib/active_admin/views/pages/layout.rb +26 -0
  379. data/lib/active_admin/views/pages/page.rb +30 -0
  380. data/lib/active_admin/views/pages/show.rb +59 -0
  381. data/lib/active_admin/views/tabbed_navigation.rb +66 -0
  382. data/lib/active_admin/views/title_bar.rb +55 -0
  383. data/lib/activeadmin.rb +1 -0
  384. data/lib/generators/active_admin/assets/assets_generator.rb +14 -0
  385. data/lib/generators/active_admin/assets/templates/active_admin.js.coffee +1 -0
  386. data/lib/generators/active_admin/assets/templates/active_admin.scss +17 -0
  387. data/lib/generators/active_admin/devise/devise_generator.rb +65 -0
  388. data/lib/generators/active_admin/install/install_generator.rb +45 -0
  389. data/lib/generators/active_admin/install/templates/active_admin.rb.erb +272 -0
  390. data/lib/generators/active_admin/install/templates/admin_user.rb.erb +30 -0
  391. data/lib/generators/active_admin/install/templates/dashboard.rb +33 -0
  392. data/lib/generators/active_admin/install/templates/migrations/create_active_admin_comments.rb +19 -0
  393. data/lib/generators/active_admin/page/USAGE +8 -0
  394. data/lib/generators/active_admin/page/page_generator.rb +12 -0
  395. data/lib/generators/active_admin/page/templates/page.rb +5 -0
  396. data/lib/generators/active_admin/resource/resource_generator.rb +20 -0
  397. data/lib/generators/active_admin/resource/templates/admin.rb +45 -0
  398. data/lib/ransack_ext.rb +20 -0
  399. data/script/local +53 -0
  400. data/script/travis_cache +107 -0
  401. data/script/use_rails +53 -0
  402. data/spec/javascripts/coffeescripts/jquery.aa.checkbox-toggler-spec.js.coffee +50 -0
  403. data/spec/javascripts/coffeescripts/jquery.aa.flash.js.coffee +25 -0
  404. data/spec/javascripts/coffeescripts/jquery.aa.table-checkbox-toggler-spec.js.coffee +34 -0
  405. data/spec/javascripts/fixtures/checkboxes.html +9 -0
  406. data/spec/javascripts/fixtures/flashes.html +2 -0
  407. data/spec/javascripts/fixtures/table_checkboxes.html +17 -0
  408. data/spec/javascripts/helpers/SpecHelper.js +3 -0
  409. data/spec/javascripts/support/jasmine.yml +74 -0
  410. data/spec/javascripts/support/jasmine_config.rb +23 -0
  411. data/spec/javascripts/support/jasmine_runner.rb +32 -0
  412. data/spec/rails_helper.rb +161 -0
  413. data/spec/requests/default_namespace_spec.rb +61 -0
  414. data/spec/requests/javascript_spec.rb +22 -0
  415. data/spec/requests/memory_spec.rb +21 -0
  416. data/spec/requests/stylesheets_spec.rb +18 -0
  417. data/spec/spec_helper.rb +17 -0
  418. data/spec/support/active_admin_request_helpers.rb +27 -0
  419. data/spec/support/deferred_garbage_collection.rb +19 -0
  420. data/spec/support/detect_rails_version.rb +34 -0
  421. data/spec/support/jslint.yml +80 -0
  422. data/spec/support/rails_template.rb +162 -0
  423. data/spec/support/rails_template_with_data.rb +74 -0
  424. data/spec/support/templates/admin/stores.rb +9 -0
  425. data/spec/support/templates/en.yml +8 -0
  426. data/spec/support/templates/manifest.js +3 -0
  427. data/spec/support/templates/policies/active_admin/comment_policy.rb +9 -0
  428. data/spec/support/templates/policies/active_admin/page_policy.rb +18 -0
  429. data/spec/support/templates/policies/admin_user_policy.rb +11 -0
  430. data/spec/support/templates/policies/application_policy.rb +45 -0
  431. data/spec/support/templates/policies/category_policy.rb +7 -0
  432. data/spec/support/templates/policies/post_policy.rb +15 -0
  433. data/spec/support/templates/policies/store_policy.rb +11 -0
  434. data/spec/support/templates/policies/user_policy.rb +11 -0
  435. data/spec/support/templates/post_decorator.rb +11 -0
  436. data/spec/unit/abstract_view_factory_spec.rb +79 -0
  437. data/spec/unit/action_builder_spec.rb +134 -0
  438. data/spec/unit/active_admin_spec.rb +11 -0
  439. data/spec/unit/application_spec.rb +165 -0
  440. data/spec/unit/asset_registration_spec.rb +52 -0
  441. data/spec/unit/authorization/authorization_adapter_spec.rb +61 -0
  442. data/spec/unit/authorization/controller_authorization_spec.rb +39 -0
  443. data/spec/unit/authorization/index_overriding_spec.rb +23 -0
  444. data/spec/unit/auto_link_spec.rb +69 -0
  445. data/spec/unit/batch_actions/resource_spec.rb +97 -0
  446. data/spec/unit/batch_actions/settings_spec.rb +61 -0
  447. data/spec/unit/belongs_to_spec.rb +65 -0
  448. data/spec/unit/cancan_adapter_spec.rb +43 -0
  449. data/spec/unit/comments_spec.rb +188 -0
  450. data/spec/unit/component_spec.rb +18 -0
  451. data/spec/unit/config_shared_examples.rb +59 -0
  452. data/spec/unit/controller_filters_spec.rb +41 -0
  453. data/spec/unit/csv_builder_spec.rb +303 -0
  454. data/spec/unit/dependency_spec.rb +135 -0
  455. data/spec/unit/devise_spec.rb +96 -0
  456. data/spec/unit/dsl_spec.rb +122 -0
  457. data/spec/unit/filters/filter_form_builder_spec.rb +434 -0
  458. data/spec/unit/filters/humanized_spec.rb +64 -0
  459. data/spec/unit/filters/resource_spec.rb +128 -0
  460. data/spec/unit/form_builder_spec.rb +932 -0
  461. data/spec/unit/generators/install_spec.rb +24 -0
  462. data/spec/unit/helpers/collection_spec.rb +65 -0
  463. data/spec/unit/helpers/scope_chain_spec.rb +36 -0
  464. data/spec/unit/helpers/settings_spec.rb +30 -0
  465. data/spec/unit/i18n_spec.rb +12 -0
  466. data/spec/unit/menu_collection_spec.rb +62 -0
  467. data/spec/unit/menu_item_spec.rb +143 -0
  468. data/spec/unit/menu_spec.rb +71 -0
  469. data/spec/unit/namespace/authorization_spec.rb +27 -0
  470. data/spec/unit/namespace/register_page_spec.rb +73 -0
  471. data/spec/unit/namespace/register_resource_spec.rb +160 -0
  472. data/spec/unit/namespace_spec.rb +103 -0
  473. data/spec/unit/order_clause_spec.rb +81 -0
  474. data/spec/unit/page_controller_spec.rb +5 -0
  475. data/spec/unit/page_spec.rb +78 -0
  476. data/spec/unit/pretty_format_spec.rb +77 -0
  477. data/spec/unit/pundit_adapter_spec.rb +98 -0
  478. data/spec/unit/resource/action_items_spec.rb +65 -0
  479. data/spec/unit/resource/includes_spec.rb +21 -0
  480. data/spec/unit/resource/menu_spec.rb +18 -0
  481. data/spec/unit/resource/naming_spec.rb +122 -0
  482. data/spec/unit/resource/page_presenters_spec.rb +44 -0
  483. data/spec/unit/resource/pagination_spec.rb +38 -0
  484. data/spec/unit/resource/routes_spec.rb +77 -0
  485. data/spec/unit/resource/scopes_spec.rb +50 -0
  486. data/spec/unit/resource/sidebars_spec.rb +43 -0
  487. data/spec/unit/resource_collection_spec.rb +175 -0
  488. data/spec/unit/resource_controller/data_access_spec.rb +140 -0
  489. data/spec/unit/resource_controller/decorators_spec.rb +94 -0
  490. data/spec/unit/resource_controller/sidebars_spec.rb +38 -0
  491. data/spec/unit/resource_controller_spec.rb +269 -0
  492. data/spec/unit/resource_registration_spec.rb +56 -0
  493. data/spec/unit/resource_spec.rb +337 -0
  494. data/spec/unit/routing_spec.rb +185 -0
  495. data/spec/unit/scope_spec.rb +185 -0
  496. data/spec/unit/settings_spec.rb +118 -0
  497. data/spec/unit/view_factory_spec.rb +19 -0
  498. data/spec/unit/view_helpers/breadcrumbs_spec.rb +217 -0
  499. data/spec/unit/view_helpers/display_helper_spec.rb +165 -0
  500. data/spec/unit/view_helpers/download_format_links_helper_spec.rb +39 -0
  501. data/spec/unit/view_helpers/fields_for_spec.rb +50 -0
  502. data/spec/unit/view_helpers/flash_helper_spec.rb +25 -0
  503. data/spec/unit/view_helpers/form_helper_spec.rb +43 -0
  504. data/spec/unit/view_helpers/method_or_proc_helper_spec.rb +139 -0
  505. data/spec/unit/views/components/attributes_table_spec.rb +272 -0
  506. data/spec/unit/views/components/batch_action_selector_spec.rb +43 -0
  507. data/spec/unit/views/components/blank_slate_spec.rb +27 -0
  508. data/spec/unit/views/components/columns_spec.rb +189 -0
  509. data/spec/unit/views/components/index_list_spec.rb +35 -0
  510. data/spec/unit/views/components/index_table_for_spec.rb +127 -0
  511. data/spec/unit/views/components/paginated_collection_spec.rb +249 -0
  512. data/spec/unit/views/components/panel_spec.rb +58 -0
  513. data/spec/unit/views/components/sidebar_section_spec.rb +68 -0
  514. data/spec/unit/views/components/site_title_spec.rb +78 -0
  515. data/spec/unit/views/components/status_tag_spec.rb +249 -0
  516. data/spec/unit/views/components/table_for_spec.rb +434 -0
  517. data/spec/unit/views/components/tabs_spec.rb +39 -0
  518. data/spec/unit/views/components/unsupported_browser_spec.rb +41 -0
  519. data/spec/unit/views/index_as_blog_spec.rb +76 -0
  520. data/spec/unit/views/pages/form_spec.rb +51 -0
  521. data/spec/unit/views/pages/index_spec.rb +60 -0
  522. data/spec/unit/views/pages/layout_spec.rb +59 -0
  523. data/spec/unit/views/pages/show_spec.rb +33 -0
  524. data/spec/unit/views/tabbed_navigation_spec.rb +158 -0
  525. data/tasks/docs.rake +37 -0
  526. data/tasks/parallel_tests.rake +66 -0
  527. data/tasks/test.rake +91 -0
  528. data/tasks/yard.rake +9 -0
  529. metadata +974 -0
@@ -0,0 +1,64 @@
1
+ require 'rails_helper'
2
+
3
+ describe ActiveAdmin::Filters::Humanized do
4
+ describe '#value' do
5
+ it 'should equal query string parameter if not an Array' do
6
+ param = ['category_id_eq', '1']
7
+ subject = ActiveAdmin::Filters::Humanized.new(param)
8
+ expect(subject.value).to eq('1')
9
+ end
10
+
11
+ it 'should equal query string parameters separated by commas if an Array' do
12
+ param = ['category_id_eq', ['1', '2']]
13
+ subject = ActiveAdmin::Filters::Humanized.new(param)
14
+ expect(subject.value).to eq("1, 2")
15
+ end
16
+
17
+ it 'should remove nil values before joining equal query string parameters separated by commas if an Array' do
18
+ param = ['category_id_eq', ['1', nil, '2']]
19
+ subject = ActiveAdmin::Filters::Humanized.new(param)
20
+ expect(subject.value).to eq("1, 2")
21
+ end
22
+ end
23
+
24
+ describe '#body' do
25
+ context 'when Ransack predicate' do
26
+ it 'parses language from Ransack' do
27
+ param = ['category_id_eq', '1']
28
+ subject = ActiveAdmin::Filters::Humanized.new(param)
29
+ expect(subject.body).to eq('Category ID equals')
30
+ end
31
+
32
+ it 'handles strings with embedded predicates' do
33
+ param = ['requires_approval_eq', '1']
34
+ humanizer = ActiveAdmin::Filters::Humanized.new(param)
35
+ expect(humanizer.value).to eq('1')
36
+ expect(humanizer.body).to eq('Requires Approval equals')
37
+ end
38
+ end
39
+
40
+ context 'when ActiveAdmin predicate' do
41
+ it 'parses language from ActiveAdmin' do
42
+ param = ['name_starts_with', 'test']
43
+ humanizer = ActiveAdmin::Filters::Humanized.new(param)
44
+ expect(humanizer.body).to eq('Name starts with')
45
+ end
46
+ end
47
+
48
+ context 'when unknown predicate' do
49
+ it 'uses raw predicate string' do
50
+ param = ['name_predicate_does_not_exist', 'test']
51
+ humanizer = ActiveAdmin::Filters::Humanized.new(param)
52
+ expect(humanizer.body).to eq("Name Predicate Does Not Exist")
53
+ end
54
+ end
55
+
56
+ context 'when column name similar to predicate' do
57
+ it 'parses correct predicate' do
58
+ param = ['time_start_gteq', 'test']
59
+ humanizer = ActiveAdmin::Filters::Humanized.new(param)
60
+ expect(humanizer.body).to eq('Time Start greater than or equal to')
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,128 @@
1
+ require 'rails_helper'
2
+
3
+ describe ActiveAdmin::Filters::ResourceExtension do
4
+
5
+ let(:resource) do
6
+ namespace = ActiveAdmin::Namespace.new(ActiveAdmin::Application.new, :admin)
7
+ namespace.register(Post)
8
+ end
9
+
10
+ it "should return a Hash" do
11
+ expect(resource.filters).to be_a Hash
12
+ end
13
+
14
+ it "should return the defaults if no filters are set" do
15
+ expect(resource.filters.keys).to match_array([
16
+ :author, :body, :category, :created_at, :custom_searcher, :position, :published_at, :starred, :taggings, :title, :updated_at
17
+ ])
18
+ end
19
+
20
+ it "should not have defaults when filters are disabled on the resource" do
21
+ resource.filters = false
22
+ expect(resource.filters).to be_empty
23
+ end
24
+
25
+ it "should not have defaults when the filters are disabled on the namespace" do
26
+ resource.namespace.filters = false
27
+ expect(resource.filters).to be_empty
28
+ end
29
+
30
+ it "should not have defaults when the filters are disabled on the application" do
31
+ resource.namespace.application.filters = false
32
+ expect(resource.filters).to be_empty
33
+ end
34
+
35
+ it "should return the defaults without associations if default association filters are disabled on the namespace" do
36
+ resource.namespace.include_default_association_filters = false
37
+ expect(resource.filters.keys).to match_array([
38
+ :body, :created_at, :custom_searcher, :position, :published_at, :starred, :title, :updated_at
39
+ ])
40
+ end
41
+
42
+ describe "removing a filter" do
43
+ it "should work" do
44
+ expect(resource.filters.keys).to include :author
45
+ resource.remove_filter :author
46
+ expect(resource.filters.keys).to_not include :author
47
+ end
48
+
49
+ it "should work as a string" do
50
+ expect(resource.filters.keys).to include :author
51
+ resource.remove_filter 'author'
52
+ expect(resource.filters.keys).to_not include :author
53
+ end
54
+
55
+ it "should be lazy" do
56
+ expect(resource).to_not receive :default_filters # this hits the DB
57
+ resource.remove_filter :author
58
+ end
59
+
60
+ it "should not prevent the default filters from being added" do
61
+ resource.remove_filter :author
62
+ expect(resource.filters).to_not be_empty
63
+ end
64
+
65
+ it "should raise an exception when filters are disabled" do
66
+ resource.filters = false
67
+ expect{ resource.remove_filter :author }.to raise_error ActiveAdmin::Filters::Disabled
68
+ end
69
+ end
70
+
71
+ describe "removing a multiple filters inline" do
72
+ it "should work" do
73
+ expect(resource.filters.keys).to include :author, :body
74
+ resource.remove_filter :author, :body
75
+ expect(resource.filters.keys).to_not include :author, :body
76
+ end
77
+ end
78
+
79
+ describe "adding a filter" do
80
+ it "should work" do
81
+ resource.add_filter :title
82
+ expect(resource.filters).to eq title: {}
83
+ end
84
+
85
+ it "should work as a string" do
86
+ resource.add_filter 'title'
87
+ expect(resource.filters).to eq title: {}
88
+ end
89
+
90
+ it "should work with specified options" do
91
+ resource.add_filter :title, as: :string
92
+ expect(resource.filters).to eq title: {as: :string}
93
+ end
94
+
95
+ it "should override an existing filter" do
96
+ resource.add_filter :title, one: :two
97
+ resource.add_filter :title, three: :four
98
+
99
+ expect(resource.filters).to eq title: {three: :four}
100
+ end
101
+
102
+ it "should preserve default filters" do
103
+ resource.preserve_default_filters!
104
+ resource.add_filter :count, as: :string
105
+
106
+ expect(resource.filters.keys).to match_array([
107
+ :author, :body, :category, :count, :created_at, :custom_searcher, :position, :published_at, :starred, :taggings, :title, :updated_at
108
+ ])
109
+ end
110
+
111
+ it "should raise an exception when filters are disabled" do
112
+ resource.filters = false
113
+ expect{ resource.add_filter :title }.to raise_error ActiveAdmin::Filters::Disabled
114
+ end
115
+ end
116
+
117
+ it "should reset filters" do
118
+ resource.add_filter :title
119
+ expect(resource.filters.size).to eq 1
120
+ resource.reset_filters!
121
+ expect(resource.filters.size).to be > 1
122
+ end
123
+
124
+ it "should add a sidebar section for the filters" do
125
+ expect(resource.sidebar_sections.first.name).to eq "filters"
126
+ end
127
+
128
+ end
@@ -0,0 +1,932 @@
1
+ require 'rails_helper'
2
+ require "rspec/mocks/standalone"
3
+
4
+ describe ActiveAdmin::FormBuilder do
5
+ # Setup an ActionView::Base object which can be used for
6
+ # generating the form for.
7
+ let(:helpers) do
8
+ view = action_view
9
+ def view.posts_path
10
+ "/posts"
11
+ end
12
+
13
+ def view.protect_against_forgery?
14
+ false
15
+ end
16
+
17
+ def view.url_for(*args)
18
+ if args.first == {action: "index"}
19
+ posts_path
20
+ else
21
+ super
22
+ end
23
+ end
24
+
25
+ def view.a_helper_method
26
+ "A Helper Method"
27
+ end
28
+
29
+ def view.fa_icon(*args)
30
+ args.inspect
31
+ end
32
+
33
+ view
34
+ end
35
+
36
+ def build_form(options = {}, form_object = Post.new, &block)
37
+ options = {url: helpers.posts_path}.merge(options)
38
+
39
+ form = render_arbre_component({form_object: form_object, form_options: options, form_block: block}, helpers) do
40
+ active_admin_form_for(assigns[:form_object], assigns[:form_options], &assigns[:form_block])
41
+ end.to_s
42
+
43
+ Capybara.string(form)
44
+ end
45
+
46
+ context "in general" do
47
+ context "it without custom settings" do
48
+ let :body do
49
+ build_form do |f|
50
+ f.inputs do
51
+ f.input :title
52
+ f.input :body
53
+ end
54
+ end
55
+ end
56
+
57
+ it "should generate a fieldset with a inputs class" do
58
+ expect(body).to have_selector("fieldset.inputs")
59
+ end
60
+ end
61
+
62
+ context "it with custom settings" do
63
+ let :body do
64
+ build_form do |f|
65
+ f.inputs class: "custom_class", name: 'custom_name', custom_attr: 'custom_attr' do
66
+ f.input :title
67
+ f.input :body
68
+ end
69
+ end
70
+ end
71
+
72
+ it "should generate a fieldset with a inputs and custom class" do
73
+ expect(body).to have_selector("fieldset.custom_class")
74
+ end
75
+
76
+ it "should generate a fieldset with a custom legend" do
77
+ expect(body).to have_css("legend", text: 'custom_name')
78
+ end
79
+
80
+ it "should generate a fieldset with a custom attributes" do
81
+ expect(body).to have_selector("fieldset[custom_attr='custom_attr']")
82
+ end
83
+ end
84
+ end
85
+
86
+ context "in general with actions" do
87
+ let :body do
88
+ build_form do |f|
89
+ f.inputs do
90
+ f.input :title
91
+ f.input :body
92
+ end
93
+ f.actions do
94
+ f.action :submit, label: "Submit Me"
95
+ f.action :submit, label: "Another Button"
96
+ end
97
+ end
98
+ end
99
+
100
+ it "should generate a text input" do
101
+ expect(body).to have_selector("input[type=text][name='post[title]']")
102
+ end
103
+ it "should generate a textarea" do
104
+ expect(body).to have_selector("textarea[name='post[body]']")
105
+ end
106
+ it "should only generate the form once" do
107
+ expect(body).to have_selector("form", count: 1)
108
+ end
109
+ it "should generate actions" do
110
+ expect(body).to have_selector("input[type=submit][value='Submit Me']")
111
+ expect(body).to have_selector("input[type=submit][value='Another Button']")
112
+ end
113
+ end
114
+
115
+ context "when polymorphic relationship" do
116
+ it "should raise error" do
117
+ expect {
118
+ comment = ActiveAdmin::Comment.new
119
+ build_form({url: "admins/comments"}, comment) do |f|
120
+ f.inputs :resource
121
+ end
122
+ }.to raise_error(Formtastic::PolymorphicInputWithoutCollectionError)
123
+ end
124
+ end
125
+
126
+ describe "passing in options with actions" do
127
+ let :body do
128
+ build_form html: { multipart: true } do |f|
129
+ f.inputs :title
130
+ f.actions
131
+ end
132
+ end
133
+ it "should pass the options on to the form" do
134
+ expect(body).to have_selector("form[enctype='multipart/form-data']")
135
+ end
136
+ end
137
+
138
+ if Rails::VERSION::MAJOR > 3
139
+ context "file input present" do
140
+ let :body do
141
+ build_form do |f|
142
+ f.input :body, as: :file
143
+ end
144
+ end
145
+
146
+ it "adds multipart attribute automatically" do
147
+ expect(body).to have_selector("form[enctype='multipart/form-data']")
148
+ end
149
+ end
150
+ end
151
+
152
+ context "with actions" do
153
+ it "should generate the form once" do
154
+ body = build_form do |f|
155
+ f.inputs do
156
+ f.input :title
157
+ end
158
+ f.actions
159
+ end
160
+ expect(body).to have_selector("[id=post_title]", count: 1)
161
+ end
162
+ it "should generate one button and a cancel link" do
163
+ body = build_form do |f|
164
+ f.actions
165
+ end
166
+ expect(body).to have_selector("[type=submit]", count: 1)
167
+ expect(body).to have_selector("[class=cancel]", count: 1)
168
+ end
169
+ it "should generate multiple actions" do
170
+ body = build_form do |f|
171
+ f.actions do
172
+ f.action :submit, label: "Create & Continue"
173
+ f.action :submit, label: "Create & Edit"
174
+ end
175
+ end
176
+ expect(body).to have_selector("[type=submit]", count: 2)
177
+ expect(body).to have_selector("[class=cancel]", count: 0)
178
+ end
179
+
180
+ end
181
+
182
+ context "with Arbre inside" do
183
+ it "should render the Arbre in the expected place" do
184
+ body = build_form do |f|
185
+ div do
186
+ h1 'Heading'
187
+ end
188
+ f.inputs do
189
+ span 'Top note'
190
+ f.input :title
191
+ span 'Bottom note'
192
+ end
193
+ h3 'Footer'
194
+ f.actions
195
+ end
196
+
197
+ expect(body).to have_selector("div > h1")
198
+ expect(body).to have_selector("h1", count: 1)
199
+ expect(body).to have_selector(".inputs > ol > span")
200
+ expect(body).to have_selector("span", count: 2)
201
+ end
202
+ it "should allow a simplified syntax" do
203
+ body = build_form do |f|
204
+ div do
205
+ h1 'Heading'
206
+ end
207
+ inputs do
208
+ span 'Top note'
209
+ input :title
210
+ span 'Bottom note'
211
+ end
212
+ h3 'Footer'
213
+ actions
214
+ end
215
+
216
+ expect(body).to have_selector("div > h1")
217
+ expect(body).to have_selector("h1", count: 1)
218
+ expect(body).to have_selector(".inputs > ol > span")
219
+ expect(body).to have_selector("span", count: 2)
220
+ end
221
+ end
222
+
223
+ context "without passing a block to inputs" do
224
+ let :body do
225
+ build_form do |f|
226
+ f.inputs :title, :body
227
+ end
228
+ end
229
+ it "should have a title input" do
230
+ expect(body).to have_selector("input[type=text][name='post[title]']")
231
+ end
232
+ it "should have a body textarea" do
233
+ expect(body).to have_selector("textarea[name='post[body]']")
234
+ end
235
+ end
236
+
237
+ context "with semantic fields for" do
238
+ let :body do
239
+ build_form do |f|
240
+ f.inputs do
241
+ f.input :title
242
+ f.input :body
243
+ end
244
+ f.form_builder.instance_eval do
245
+ @object.author = User.new
246
+ end
247
+ f.semantic_fields_for :author do |author|
248
+ author.inputs :first_name, :last_name
249
+ end
250
+ end
251
+ end
252
+ it "should generate a nested text input once" do
253
+ expect(body).to have_selector("[id=post_author_attributes_first_name_input]", count: 1)
254
+ end
255
+ end
256
+
257
+ context "with collection inputs" do
258
+ before do
259
+ User.create first_name: "John", last_name: "Doe"
260
+ User.create first_name: "Jane", last_name: "Doe"
261
+ end
262
+
263
+ describe "as select" do
264
+ let :body do
265
+ build_form do |f|
266
+ f.input :author, include_blank: false
267
+ end
268
+ end
269
+ it "should create 2 options" do
270
+ expect(body).to have_selector("option", count: 2)
271
+ end
272
+ end
273
+
274
+ describe "as radio buttons" do
275
+ let :body do
276
+ build_form do |f|
277
+ f.input :author, as: :radio
278
+ end
279
+ end
280
+ it "should create 2 radio buttons" do
281
+ expect(body).to have_selector("[type=radio]", count: 2)
282
+ end
283
+ end
284
+
285
+ end
286
+
287
+ context "with a has_one relation on an author's profile" do
288
+ let :body do
289
+ author = user()
290
+ build_form do |f|
291
+ f.inputs do
292
+ f.input :title
293
+ f.input :body
294
+ end
295
+ f.form_builder.instance_eval do
296
+ @object.author = author
297
+ end
298
+ f.inputs name: 'Author', for: :author do |author|
299
+ author.has_many :profile, allow_destroy: true do |profile|
300
+ profile.input :bio
301
+ end
302
+ end
303
+ end
304
+ end
305
+
306
+ it "should see the button to add profile" do
307
+ def user
308
+ User.new
309
+ end
310
+ expect(body).to have_selector("a[contains(data-html,'post[author_attributes][profile_attributes][bio]')]")
311
+ end
312
+
313
+ it "should see the profile fields for an existing profile" do
314
+ def user
315
+ u = User.new
316
+ u.profile = Profile.new
317
+ u
318
+ end
319
+ expect(body).to have_selector("[id='post_author_attributes_profile_attributes_bio']", count: 1)
320
+ expect(body).to have_selector("textarea[name='post[author_attributes][profile_attributes][bio]']")
321
+ end
322
+ end
323
+
324
+ shared_examples :inputs_with_for_expectation do
325
+ it "should generate a nested text input once" do
326
+ expect(body).to have_selector("[id=post_author_attributes_first_name_input]", count: 1)
327
+ expect(body).to have_selector("[id=post_author_attributes_last_name_input]", count: 1)
328
+ end
329
+ it "should add author first and last name fields" do
330
+ expect(body).to have_selector("input[name='post[author_attributes][first_name]']")
331
+ expect(body).to have_selector("input[name='post[author_attributes][last_name]']")
332
+ end
333
+ end
334
+
335
+ context "with inputs 'for'" do
336
+ let :body do
337
+ build_form do |f|
338
+ f.inputs do
339
+ f.input :title
340
+ f.input :body
341
+ end
342
+ f.form_builder.instance_eval do
343
+ @object.author = User.new
344
+ end
345
+ f.inputs name: 'Author', for: :author do |author|
346
+ author.inputs :first_name, :last_name
347
+ end
348
+ end
349
+ end
350
+
351
+ include_examples :inputs_with_for_expectation
352
+ end
353
+
354
+ context "with two input fields 'for' at the end of block" do
355
+ let :body do
356
+ build_form do |f|
357
+ f.inputs do
358
+ f.input :title
359
+ f.input :body
360
+ end
361
+ f.form_builder.instance_eval do
362
+ @object.author = User.new
363
+ end
364
+ f.inputs name: 'Author', for: :author do |author|
365
+ author.input :first_name
366
+ author.input :last_name
367
+ end
368
+ end
369
+ end
370
+
371
+ include_examples :inputs_with_for_expectation
372
+ end
373
+
374
+ context "with two input fields 'for' at the beginning of block" do
375
+ let :body do
376
+ build_form do |f|
377
+ f.form_builder.instance_eval do
378
+ @object.author = User.new
379
+ end
380
+ f.inputs name: 'Author', for: :author do |author|
381
+ author.input :first_name
382
+ author.input :last_name
383
+ end
384
+ f.inputs do
385
+ f.input :title
386
+ f.input :body
387
+ end
388
+ end
389
+ end
390
+
391
+ include_examples :inputs_with_for_expectation
392
+ end
393
+
394
+ context "with wrapper html" do
395
+ it "should set a class" do
396
+ body = build_form do |f|
397
+ f.input :title, wrapper_html: { class: "important" }
398
+ end
399
+ expect(body).to have_selector("li[class='important string input optional stringish']")
400
+ end
401
+ end
402
+
403
+ context "with inputs twice" do
404
+ let :body do
405
+ build_form do |f|
406
+ f.inputs do
407
+ f.input :title
408
+ f.input :body
409
+ end
410
+ f.inputs do
411
+ f.input :author
412
+ f.input :published_at
413
+ end
414
+ end
415
+ end
416
+ it "should render four inputs" do
417
+ expect(body).to have_selector("input[name='post[title]']", count: 1)
418
+ expect(body).to have_selector("textarea[name='post[body]']", count: 1)
419
+ expect(body).to have_selector("select[name='post[author_id]']", count: 1)
420
+ expect(body).to have_selector("select[name='post[published_at(1i)]']", count: 1)
421
+ expect(body).to have_selector("select[name='post[published_at(2i)]']", count: 1)
422
+ expect(body).to have_selector("select[name='post[published_at(3i)]']", count: 1)
423
+ expect(body).to have_selector("select[name='post[published_at(4i)]']", count: 1)
424
+ end
425
+ end
426
+
427
+ context "with has many inputs" do
428
+ describe "with simple block" do
429
+ let :body do
430
+ build_form({url: '/categories'}, Category.new) do |f|
431
+ f.object.posts.build
432
+ f.has_many :posts do |p|
433
+ p.input :title
434
+ p.input :body
435
+ end
436
+ f.inputs
437
+ end
438
+ end
439
+
440
+ let(:valid_html_id) { /^[A-Za-z]+[\w\-\:\.]*$/ }
441
+
442
+ it "should translate the association name in header" do
443
+ with_translation activerecord: {models: {post: {one: 'Blog Post', other: 'Blog Posts'}}} do
444
+ expect(body).to have_selector("h3", text: "Blog Posts")
445
+ end
446
+ end
447
+
448
+ it "should use model name when there is no translation for given model in header" do
449
+ expect(body).to have_selector("h3", text: "Post")
450
+ end
451
+
452
+ it "should translate the association name in has many new button" do
453
+ with_translation activerecord: {models: {post: {one: 'Blog Post', other: 'Blog Posts'}}} do
454
+ expect(body).to have_selector("a", text: "Add New Blog Post")
455
+ end
456
+ end
457
+
458
+ it "should translate the attribute name" do
459
+ with_translation activerecord: {attributes: {post: {title: 'A very nice title'}}} do
460
+ expect(body).to have_selector("label", text: "A very nice title")
461
+ end
462
+ end
463
+
464
+ it "should use model name when there is no translation for given model in has many new button" do
465
+ expect(body).to have_selector("a", text: "Add New Post")
466
+ end
467
+
468
+ it "should render the nested form" do
469
+ expect(body).to have_selector("input[name='category[posts_attributes][0][title]']")
470
+ expect(body).to have_selector("textarea[name='category[posts_attributes][0][body]']")
471
+ end
472
+
473
+ it "should add a link to remove new nested records" do
474
+ expect(body).to have_selector(".has_many_container > fieldset > ol > li > a.button.has_many_remove[href='#']", text: "Remove")
475
+ end
476
+
477
+ it "should add a link to add new nested records" do
478
+ expect(body).to have_selector(".has_many_container > a.button.has_many_add[href='#']", text: "Add New Post")
479
+ end
480
+
481
+ it "should set an HTML-id valid placeholder" do
482
+ link = body.find('.has_many_container > a.button.has_many_add')
483
+ expect(link[:'data-placeholder']).to match valid_html_id
484
+ end
485
+
486
+ describe "with namespaced model" do
487
+ it "should set an HTML-id valid placeholder" do
488
+ allow(Post).to receive(:name).and_return "ActiveAdmin::Post"
489
+ link = body.find('.has_many_container > a.button.has_many_add')
490
+ expect(link[:'data-placeholder']).to match valid_html_id
491
+ end
492
+ end
493
+ end
494
+
495
+ describe "with complex block" do
496
+ let :body do
497
+ build_form({url: '/categories'}, Category.new) do |f|
498
+ f.object.posts.build
499
+ f.has_many :posts do |p,i|
500
+ p.input :title, label: "Title #{i}"
501
+ end
502
+ end
503
+ end
504
+
505
+ it "should accept a block with a second argument" do
506
+ expect(body).to have_selector("label", text: "Title 1")
507
+ end
508
+
509
+ it "should add a custom header" do
510
+ expect(body).to have_selector("h3", text: "Post")
511
+ end
512
+ end
513
+
514
+ describe "without heading and new record link" do
515
+ let :body do
516
+ build_form({url: '/categories'}, Category.new) do |f|
517
+ f.object.posts.build
518
+ f.has_many :posts, heading: false, new_record: false do |p|
519
+ p.input :title
520
+ end
521
+ end
522
+ end
523
+
524
+ it "should not add a header" do
525
+ expect(body).not_to have_selector("h3", text: "Post")
526
+ end
527
+
528
+ it "should not add link to new nested records" do
529
+ expect(body).not_to have_selector("a", text: "Add New Post")
530
+ end
531
+
532
+ it "should render the nested form" do
533
+ expect(body).to have_selector("input[name='category[posts_attributes][0][title]']")
534
+ end
535
+ end
536
+
537
+ describe "with custom heading" do
538
+ let :body do
539
+ build_form({url: '/categories'}, Category.new) do |f|
540
+ f.object.posts.build
541
+ f.has_many :posts, heading: "Test heading" do |p|
542
+ p.input :title
543
+ end
544
+ end
545
+ end
546
+
547
+ it "should add a custom header" do
548
+ expect(body).to have_selector("h3", text: "Test heading")
549
+ end
550
+ end
551
+
552
+ describe "with custom new record link" do
553
+ let :body do
554
+ build_form({url: '/categories'}, Category.new) do |f|
555
+ f.object.posts.build
556
+ f.has_many :posts, new_record: 'My Custom New Post' do |p|
557
+ p.input :title
558
+ end
559
+ end
560
+ end
561
+
562
+ it "should add a custom new record link" do
563
+ expect(body).to have_selector("a", text: "My Custom New Post")
564
+ end
565
+ end
566
+
567
+ describe "with allow destroy" do
568
+ shared_examples_for "has many with allow_destroy = true" do |child_num|
569
+ it "should render the nested form" do
570
+ expect(body).to have_selector("input[name='category[posts_attributes][#{child_num}][title]']")
571
+ end
572
+
573
+ it "should include a boolean field for _destroy" do
574
+ expect(body).to have_selector("input[name='category[posts_attributes][#{child_num}][_destroy]']")
575
+ end
576
+
577
+ it "should have a check box with 'Remove' as its label" do
578
+ expect(body).to have_selector("label[for=category_posts_attributes_#{child_num}__destroy]", text: "Delete")
579
+ end
580
+
581
+ it "should wrap the destroy field in an li with class 'has_many_delete'" do
582
+ expect(body).to have_selector(".has_many_container > fieldset > ol > li.has_many_delete > input", count: 1)
583
+ end
584
+ end
585
+
586
+ shared_examples_for "has many with allow_destroy = false" do |child_num|
587
+ it "should render the nested form" do
588
+ expect(body).to have_selector("input[name='category[posts_attributes][#{child_num}][title]']")
589
+ end
590
+
591
+ it "should not have a boolean field for _destroy" do
592
+ expect(body).not_to have_selector("input[name='category[posts_attributes][#{child_num}][_destroy]']")
593
+ end
594
+
595
+ it "should not have a check box with 'Remove' as its label" do
596
+ expect(body).not_to have_selector("label[for=category_posts_attributes_#{child_num}__destroy]", text: "Remove")
597
+ end
598
+ end
599
+
600
+ shared_examples_for "has many with allow_destroy as String, Symbol or Proc" do |allow_destroy_option|
601
+ let :body do
602
+ s = self
603
+ build_form({url: '/categories'}, Category.new) do |f|
604
+ s.instance_exec do
605
+ allow(f.object.posts.build).to receive(:foo?).and_return(true)
606
+ allow(f.object.posts.build).to receive(:foo?).and_return(false)
607
+
608
+ f.object.posts.each do |post|
609
+ allow(post).to receive(:new_record?).and_return(false)
610
+ end
611
+ end
612
+ f.has_many :posts, allow_destroy: allow_destroy_option do |p|
613
+ p.input :title
614
+ end
615
+ end
616
+ end
617
+
618
+ context 'for the child that responds with true' do
619
+ it_behaves_like "has many with allow_destroy = true", 0
620
+ end
621
+
622
+ context 'for the child that responds with false' do
623
+ it_behaves_like "has many with allow_destroy = false", 1
624
+ end
625
+ end
626
+
627
+ context "with an existing post" do
628
+ context "with allow_destroy = true" do
629
+ let :body do
630
+ s = self
631
+ build_form({url: '/categories'}, Category.new) do |f|
632
+ s.instance_exec do
633
+ allow(f.object.posts.build).to receive(:new_record?).and_return(false)
634
+ end
635
+ f.has_many :posts, allow_destroy: true do |p|
636
+ p.input :title
637
+ end
638
+ end
639
+ end
640
+
641
+ it_behaves_like "has many with allow_destroy = true", 0
642
+ end
643
+
644
+ context "with allow_destroy = false" do
645
+ let :body do
646
+ s = self
647
+ build_form({url: '/categories'}, Category.new) do |f|
648
+ s.instance_exec do
649
+ allow(f.object.posts.build).to receive(:new_record?).and_return(false)
650
+ end
651
+ f.has_many :posts, allow_destroy: false do |p|
652
+ p.input :title
653
+ end
654
+ end
655
+ end
656
+
657
+ it_behaves_like "has many with allow_destroy = false", 0
658
+ end
659
+
660
+ context "with allow_destroy = nil" do
661
+ let :body do
662
+ s = self
663
+ build_form({url: '/categories'}, Category.new) do |f|
664
+ s.instance_exec do
665
+ allow(f.object.posts.build).to receive(:new_record?).and_return(false)
666
+ end
667
+ f.has_many :posts, allow_destroy: nil do |p|
668
+ p.input :title
669
+ end
670
+ end
671
+ end
672
+
673
+ it_behaves_like "has many with allow_destroy = false", 0
674
+ end
675
+
676
+ context "with allow_destroy as Symbol" do
677
+ it_behaves_like("has many with allow_destroy as String, Symbol or Proc", :foo?)
678
+ end
679
+
680
+ context "with allow_destroy as String" do
681
+ it_behaves_like("has many with allow_destroy as String, Symbol or Proc", "foo?")
682
+ end
683
+
684
+ context "with allow_destroy as proc" do
685
+ it_behaves_like("has many with allow_destroy as String, Symbol or Proc",
686
+ Proc.new { |child| child.foo? })
687
+ end
688
+
689
+ context "with allow_destroy as lambda" do
690
+ it_behaves_like("has many with allow_destroy as String, Symbol or Proc",
691
+ lambda { |child| child.foo? })
692
+ end
693
+
694
+ context "with allow_destroy as any other expression that evaluates to true" do
695
+ let :body do
696
+ s = self
697
+ build_form({url: '/categories'}, Category.new) do |f|
698
+ s.instance_exec do
699
+ allow(f.object.posts.build).to receive(:new_record?).and_return(false)
700
+ end
701
+ f.has_many :posts, allow_destroy: Object.new do |p|
702
+ p.input :title
703
+ end
704
+ end
705
+ end
706
+
707
+ it_behaves_like "has many with allow_destroy = true", 0
708
+ end
709
+ end
710
+
711
+ context "with a new post" do
712
+ context "with allow_destroy = true" do
713
+ let :body do
714
+ build_form({url: '/categories'}, Category.new) do |f|
715
+ f.object.posts.build
716
+ f.has_many :posts, allow_destroy: true do |p|
717
+ p.input :title
718
+ end
719
+ end
720
+ end
721
+
722
+ it_behaves_like "has many with allow_destroy = false", 0
723
+ end
724
+ end
725
+ end
726
+
727
+ describe "sortable" do
728
+ # TODO: it doesn't make any sense to use your foreign key as something that's sortable (and therefore editable)
729
+ context "with a new post" do
730
+ let :body do
731
+ build_form({url: '/categories'}, Category.new) do |f|
732
+ f.object.posts.build
733
+ f.has_many :posts, sortable: :position do |p|
734
+ p.input :title
735
+ end
736
+ end
737
+ end
738
+
739
+ it "shows the nested fields for unsaved records" do
740
+ expect(body).to have_selector("fieldset.inputs.has_many_fields")
741
+ end
742
+
743
+ end
744
+
745
+ context "with post returning nil for the sortable attribute" do
746
+ let :body do
747
+ build_form({url: '/categories'}, Category.new) do |f|
748
+ f.object.posts.build position: 3
749
+ f.object.posts.build
750
+ f.has_many :posts, sortable: :position do |p|
751
+ p.input :title
752
+ end
753
+ end
754
+ end
755
+
756
+ it "shows the nested fields for unsaved records" do
757
+ expect(body).to have_selector("fieldset.inputs.has_many_fields")
758
+ end
759
+
760
+ end
761
+
762
+ context "with existing and new posts" do
763
+ let! :category do
764
+ Category.create name: 'Name'
765
+ end
766
+ let! :post do
767
+ category.posts.create
768
+ end
769
+ let :body do
770
+ build_form({url: '/categories'}, category) do |f|
771
+ f.object.posts.build
772
+ f.has_many :posts, sortable: :position do |p|
773
+ p.input :title
774
+ end
775
+ end
776
+ end
777
+
778
+ it "shows the nested fields for saved and unsaved records" do
779
+ expect(body).to have_selector("fieldset.inputs.has_many_fields")
780
+ end
781
+ end
782
+
783
+ context "without sortable_start set" do
784
+ let :body do
785
+ build_form({url: '/categories'}, Category.new) do |f|
786
+ f.object.posts.build
787
+ f.has_many :posts, sortable: :position do |p|
788
+ p.input :title
789
+ end
790
+ end
791
+ end
792
+
793
+ it "defaults to 0" do
794
+ expect(body).to have_selector("div.has_many_container[data-sortable-start='0']")
795
+ end
796
+ end
797
+
798
+ context "with sortable_start set" do
799
+ let :body do
800
+ build_form({url: '/categories'}, Category.new) do |f|
801
+ f.object.posts.build
802
+ f.has_many :posts, sortable: :position, sortable_start: 15 do |p|
803
+ p.input :title
804
+ end
805
+ end
806
+ end
807
+
808
+ it "sets the data attribute" do
809
+ expect(body).to have_selector("div.has_many_container[data-sortable-start='15']")
810
+ end
811
+ end
812
+ end
813
+
814
+ describe "with nesting" do
815
+ context "in an inputs block" do
816
+ let :body do
817
+ build_form({url: '/categories'}, Category.new) do |f|
818
+ f.inputs "Field Wrapper" do
819
+ f.object.posts.build
820
+ f.has_many :posts do |p|
821
+ p.input :title
822
+ end
823
+ end
824
+ end
825
+ end
826
+
827
+ it "should wrap the has_many fieldset in an li" do
828
+ expect(body).to have_selector("ol > li.has_many_container")
829
+ end
830
+
831
+ it "should have a direct fieldset child" do
832
+ expect(body).to have_selector("li.has_many_container > fieldset")
833
+ end
834
+
835
+ it "should not contain invalid li children" do
836
+ expect(body).not_to have_selector("div.has_many_container > li")
837
+ end
838
+ end
839
+
840
+ context "in another has_many block" do
841
+ let :body do
842
+ build_form({url: '/categories'}, Category.new) do |f|
843
+ f.object.posts.build
844
+ f.has_many :posts do |p|
845
+ p.object.taggings.build
846
+ p.has_many :taggings do |t|
847
+ t.input :tag
848
+ end
849
+ end
850
+ end
851
+ end
852
+
853
+ it "should wrap the inner has_many fieldset in an ol > li" do
854
+ expect(body).to have_selector(".has_many_container ol > li.has_many_container > fieldset")
855
+ end
856
+
857
+ it "should not contain invalid li children" do
858
+ expect(body).not_to have_selector(".has_many_container div.has_many_container > li")
859
+ end
860
+ end
861
+ end
862
+
863
+ it "should render the block if it returns nil" do
864
+ body = build_form({url: '/categories'}, Category.new) do |f|
865
+ f.object.posts.build
866
+ f.has_many :posts do |p|
867
+ p.input :title
868
+ nil
869
+ end
870
+ end
871
+
872
+ expect(body).to have_selector("input[name='category[posts_attributes][0][title]']")
873
+ end
874
+ end
875
+
876
+ { # Testing that the same input can be used multiple times
877
+ "f.input :title, as: :string" => "post_title",
878
+ "f.input :title, as: :text" => "post_title",
879
+ "f.input :created_at, as: :time_select" => "post_created_at_2i",
880
+ "f.input :created_at, as: :datetime_select" => "post_created_at_2i",
881
+ "f.input :created_at, as: :date_select" => "post_created_at_2i",
882
+ # Testing that return values don't screw up the form
883
+ "f.input :title; nil" => "post_title",
884
+ "f.input :title; []" => "post_title",
885
+ "[:title].each{ |r| f.input r }" => "post_title",
886
+ "[:title].map { |r| f.input r }" => "post_title",
887
+ }.each do |source, selector|
888
+ it "should properly buffer `#{source}`" do
889
+ body = build_form do |f|
890
+ f.inputs do
891
+ eval source
892
+ eval source
893
+ end
894
+ end
895
+ expect(body).to have_selector("[id=#{selector}]", count: 2)
896
+ end
897
+ end
898
+
899
+ describe "datepicker input" do
900
+ context 'with default options' do
901
+ let :body do
902
+ build_form do |f|
903
+ f.inputs do
904
+ f.input :created_at, as: :datepicker
905
+ end
906
+ end
907
+ end
908
+ it "should generate a text input with the class of datepicker" do
909
+ expect(body).to have_selector("input.datepicker[type=text][name='post[created_at]']")
910
+ end
911
+ end
912
+
913
+ context 'with date range options' do
914
+ let :body do
915
+ build_form do |f|
916
+ f.inputs do
917
+ f.input :created_at, as: :datepicker,
918
+ datepicker_options: {
919
+ min_date: Date.new(2013, 10, 18),
920
+ max_date: "2013-12-31" }
921
+ end
922
+ end
923
+ end
924
+
925
+ it 'should generate a datepicker text input with data min and max dates' do
926
+ selector = "input.datepicker[type=text][name='post[created_at]']"
927
+ expect(body).to have_selector(selector)
928
+ expect(body.find(selector)["data-datepicker-options"]).to eq({ minDate: '2013-10-18', maxDate: '2013-12-31' }.to_json)
929
+ end
930
+ end
931
+ end
932
+ end