activeadmin-rails 1.7.0

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